SEBWIN-106: Implemented basic popup and reload handling, revised browser control implementation and added mouse button interception for navigation (auxiliary) keys. Also finally implemented a custom template for small scrollbars in scrollviewers.
This commit is contained in:
		
							parent
							
								
									91c2417930
								
							
						
					
					
						commit
						f949a19f32
					
				
					 40 changed files with 454 additions and 158 deletions
				
			
		| 
						 | 
				
			
			@ -11,12 +11,14 @@ using System.Collections.Generic;
 | 
			
		|||
using System.Linq;
 | 
			
		||||
using CefSharp;
 | 
			
		||||
using CefSharp.WinForms;
 | 
			
		||||
using SafeExamBrowser.Browser.Events;
 | 
			
		||||
using SafeExamBrowser.Contracts.Browser;
 | 
			
		||||
using SafeExamBrowser.Contracts.Configuration;
 | 
			
		||||
using SafeExamBrowser.Contracts.Core;
 | 
			
		||||
using SafeExamBrowser.Contracts.I18n;
 | 
			
		||||
using SafeExamBrowser.Contracts.Logging;
 | 
			
		||||
using SafeExamBrowser.Contracts.UserInterface;
 | 
			
		||||
using SafeExamBrowser.Contracts.UserInterface.MessageBox;
 | 
			
		||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
 | 
			
		||||
using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.BrowserSettings;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -29,6 +31,7 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
		private AppConfig appConfig;
 | 
			
		||||
		private IApplicationButton button;
 | 
			
		||||
		private IList<IApplicationInstance> instances;
 | 
			
		||||
		private IMessageBox messageBox;
 | 
			
		||||
		private IModuleLogger logger;
 | 
			
		||||
		private BrowserSettings settings;
 | 
			
		||||
		private IText text;
 | 
			
		||||
| 
						 | 
				
			
			@ -39,6 +42,7 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
		public BrowserApplicationController(
 | 
			
		||||
			AppConfig appConfig,
 | 
			
		||||
			BrowserSettings settings,
 | 
			
		||||
			IMessageBox messageBox,
 | 
			
		||||
			IModuleLogger logger,
 | 
			
		||||
			IText text,
 | 
			
		||||
			IUserInterfaceFactory uiFactory)
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +50,7 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
			this.appConfig = appConfig;
 | 
			
		||||
			this.instances = new List<IApplicationInstance>();
 | 
			
		||||
			this.logger = logger;
 | 
			
		||||
			this.messageBox = messageBox;
 | 
			
		||||
			this.settings = settings;
 | 
			
		||||
			this.text = text;
 | 
			
		||||
			this.uiFactory = uiFactory;
 | 
			
		||||
| 
						 | 
				
			
			@ -56,7 +61,7 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
			var cefSettings = InitializeCefSettings();
 | 
			
		||||
			var success = Cef.Initialize(cefSettings, true, null);
 | 
			
		||||
 | 
			
		||||
			logger.Info("Initialized CEF.");
 | 
			
		||||
			logger.Info("Initialized browser engine.");
 | 
			
		||||
 | 
			
		||||
			if (!success)
 | 
			
		||||
			{
 | 
			
		||||
| 
						 | 
				
			
			@ -87,18 +92,20 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
 | 
			
		||||
			Cef.Shutdown();
 | 
			
		||||
 | 
			
		||||
			logger.Info("Terminated CEF.");
 | 
			
		||||
			logger.Info("Terminated browser engine.");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void CreateNewInstance()
 | 
			
		||||
		private void CreateNewInstance(BrowserSettings custom = null)
 | 
			
		||||
		{
 | 
			
		||||
			var id = new BrowserInstanceIdentifier(++instanceIdCounter);
 | 
			
		||||
			var isMainInstance = instances.Count == 0;
 | 
			
		||||
			var instanceLogger = logger.CloneFor($"BrowserInstance {id}");
 | 
			
		||||
			var instance = new BrowserApplicationInstance(appConfig, settings, id, isMainInstance, instanceLogger, text, uiFactory);
 | 
			
		||||
			var instanceSettings = custom ?? settings;
 | 
			
		||||
			var instance = new BrowserApplicationInstance(appConfig, instanceSettings, id, isMainInstance, messageBox, instanceLogger, text, uiFactory);
 | 
			
		||||
 | 
			
		||||
			instance.Initialize();
 | 
			
		||||
			instance.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args);
 | 
			
		||||
			instance.PopupRequested += Instance_PopupRequested;
 | 
			
		||||
			instance.Terminated += Instance_Terminated;
 | 
			
		||||
 | 
			
		||||
			button.RegisterInstance(instance);
 | 
			
		||||
| 
						 | 
				
			
			@ -120,9 +127,10 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
				UserAgent = settings.UseCustomUserAgent ? settings.CustomUserAgent : string.Empty
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			logger.Debug($"CEF cache path is '{cefSettings.CachePath}'.");
 | 
			
		||||
			logger.Debug($"CEF log file is '{cefSettings.LogFile}'.");
 | 
			
		||||
			logger.Debug($"CEF log severity is '{cefSettings.LogSeverity}'.");
 | 
			
		||||
			logger.Debug($"Browser cache path: {cefSettings.CachePath}");
 | 
			
		||||
			logger.Debug($"Browser log file: {cefSettings.LogFile}");
 | 
			
		||||
			logger.Debug($"Browser log severity: {cefSettings.LogSeverity}");
 | 
			
		||||
			logger.Debug($"Browser engine version: Chromium {Cef.ChromiumVersion}, CEF {Cef.CefVersion}, CefSharp {Cef.CefSharpVersion}");
 | 
			
		||||
 | 
			
		||||
			return cefSettings;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -139,6 +147,27 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void Instance_PopupRequested(PopupRequestedEventArgs args)
 | 
			
		||||
		{
 | 
			
		||||
			var popupSettings = new BrowserSettings
 | 
			
		||||
			{
 | 
			
		||||
				AllowAddressBar = false,
 | 
			
		||||
				AllowBackwardNavigation = false,
 | 
			
		||||
				AllowConfigurationDownloads = settings.AllowConfigurationDownloads,
 | 
			
		||||
				AllowDeveloperConsole = settings.AllowDeveloperConsole,
 | 
			
		||||
				AllowDownloads = settings.AllowDownloads,
 | 
			
		||||
				AllowForwardNavigation = false,
 | 
			
		||||
				AllowPageZoom = settings.AllowPageZoom,
 | 
			
		||||
				AllowPopups = settings.AllowPopups,
 | 
			
		||||
				AllowReloading = settings.AllowReloading,
 | 
			
		||||
				ShowReloadWarning = settings.ShowReloadWarning,
 | 
			
		||||
				StartUrl = args.Url
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			logger.Info($"Received request to create new instance for '{args.Url}'...");
 | 
			
		||||
			CreateNewInstance(popupSettings);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void Instance_Terminated(InstanceIdentifier id)
 | 
			
		||||
		{
 | 
			
		||||
			instances.Remove(instances.FirstOrDefault(i => i.Id == id));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@
 | 
			
		|||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
using SafeExamBrowser.Browser.Events;
 | 
			
		||||
using SafeExamBrowser.Browser.Handlers;
 | 
			
		||||
using SafeExamBrowser.Contracts.Browser;
 | 
			
		||||
using SafeExamBrowser.Contracts.Configuration;
 | 
			
		||||
| 
						 | 
				
			
			@ -16,6 +17,7 @@ using SafeExamBrowser.Contracts.I18n;
 | 
			
		|||
using SafeExamBrowser.Contracts.Logging;
 | 
			
		||||
using SafeExamBrowser.Contracts.UserInterface;
 | 
			
		||||
using SafeExamBrowser.Contracts.UserInterface.Browser;
 | 
			
		||||
using SafeExamBrowser.Contracts.UserInterface.MessageBox;
 | 
			
		||||
using SafeExamBrowser.Contracts.UserInterface.Windows;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.Browser
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +28,7 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
		private IBrowserControl control;
 | 
			
		||||
		private IBrowserWindow window;
 | 
			
		||||
		private bool isMainInstance;
 | 
			
		||||
		private IMessageBox messageBox;
 | 
			
		||||
		private IModuleLogger logger;
 | 
			
		||||
		private BrowserSettings settings;
 | 
			
		||||
		private IText text;
 | 
			
		||||
| 
						 | 
				
			
			@ -36,14 +39,16 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
		public IWindow Window { get { return window; } }
 | 
			
		||||
 | 
			
		||||
		public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
 | 
			
		||||
		public event NameChangedEventHandler NameChanged;
 | 
			
		||||
		public event InstanceTerminatedEventHandler Terminated;
 | 
			
		||||
		public event NameChangedEventHandler NameChanged;
 | 
			
		||||
		public event PopupRequestedEventHandler PopupRequested;
 | 
			
		||||
 | 
			
		||||
		public BrowserApplicationInstance(
 | 
			
		||||
			AppConfig appConfig,
 | 
			
		||||
			BrowserSettings settings,
 | 
			
		||||
			InstanceIdentifier id,
 | 
			
		||||
			bool isMainInstance,
 | 
			
		||||
			IMessageBox messageBox,
 | 
			
		||||
			IModuleLogger logger,
 | 
			
		||||
			IText text,
 | 
			
		||||
			IUserInterfaceFactory uiFactory)
 | 
			
		||||
| 
						 | 
				
			
			@ -51,6 +56,7 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
			this.appConfig = appConfig;
 | 
			
		||||
			this.Id = id;
 | 
			
		||||
			this.isMainInstance = isMainInstance;
 | 
			
		||||
			this.messageBox = messageBox;
 | 
			
		||||
			this.logger = logger;
 | 
			
		||||
			this.settings = settings;
 | 
			
		||||
			this.text = text;
 | 
			
		||||
| 
						 | 
				
			
			@ -59,13 +65,18 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
 | 
			
		||||
		internal void Initialize()
 | 
			
		||||
		{
 | 
			
		||||
			var controlLogger = logger.CloneFor($"{nameof(BrowserControl)} {Id}");
 | 
			
		||||
			var contextMenuHandler = new ContextMenuHandler(settings, text);
 | 
			
		||||
			var downloadLogger = logger.CloneFor($"{nameof(DownloadHandler)} {Id}");
 | 
			
		||||
			var downloadHandler = new DownloadHandler(appConfig, settings, downloadLogger);
 | 
			
		||||
			var keyboardHandler = new KeyboardHandler();
 | 
			
		||||
			var lifeSpanHandler = new LifeSpanHandler();
 | 
			
		||||
			var requestHandler = new RequestHandler(appConfig);
 | 
			
		||||
 | 
			
		||||
			downloadHandler.ConfigurationDownloadRequested += DownloadHandler_ConfigurationDownloadRequested;
 | 
			
		||||
			keyboardHandler.ReloadRequested += KeyboardHandler_ReloadRequested;
 | 
			
		||||
			lifeSpanHandler.PopupRequested += LifeSpanHandler_PopupRequested;
 | 
			
		||||
 | 
			
		||||
			control = new BrowserControl(appConfig, settings, downloadHandler, controlLogger, text);
 | 
			
		||||
			control = new BrowserControl(contextMenuHandler, downloadHandler, keyboardHandler, lifeSpanHandler, requestHandler, settings.StartUrl);
 | 
			
		||||
			control.AddressChanged += Control_AddressChanged;
 | 
			
		||||
			control.LoadingStateChanged += Control_LoadingStateChanged;
 | 
			
		||||
			control.TitleChanged += Control_TitleChanged;
 | 
			
		||||
| 
						 | 
				
			
			@ -84,8 +95,36 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
			logger.Debug("Initialized browser window.");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void HandleReloadRequest()
 | 
			
		||||
		{
 | 
			
		||||
			if (settings.AllowReloading && settings.ShowReloadWarning)
 | 
			
		||||
			{
 | 
			
		||||
				var result = messageBox.Show(TextKey.MessageBox_ReloadConfirmation, TextKey.MessageBox_ReloadConfirmationTitle, MessageBoxAction.YesNo, MessageBoxIcon.Question, window);
 | 
			
		||||
 | 
			
		||||
				if (result == MessageBoxResult.Yes)
 | 
			
		||||
				{
 | 
			
		||||
					logger.Debug("The user confirmed reloading the current page...");
 | 
			
		||||
					control.Reload();
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					logger.Debug("The user aborted reloading the current page.");
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else if (settings.AllowReloading)
 | 
			
		||||
			{
 | 
			
		||||
				logger.Debug("Reloading current page...");
 | 
			
		||||
				control.Reload();
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				logger.Debug("Blocked reload attempt, as the user is not allowed to reload web pages.");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void Control_AddressChanged(string address)
 | 
			
		||||
		{
 | 
			
		||||
			logger.Debug($"Navigated to '{address}'.");
 | 
			
		||||
			window.UpdateAddress(address);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +145,6 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
			{
 | 
			
		||||
				args.BrowserWindow = window;
 | 
			
		||||
				logger.Debug($"Forwarding download request for configuration file '{fileName}'.");
 | 
			
		||||
 | 
			
		||||
				ConfigurationDownloadRequested?.Invoke(fileName, args);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
| 
						 | 
				
			
			@ -115,6 +153,24 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void KeyboardHandler_ReloadRequested()
 | 
			
		||||
		{
 | 
			
		||||
			HandleReloadRequest();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void LifeSpanHandler_PopupRequested(PopupRequestedEventArgs args)
 | 
			
		||||
		{
 | 
			
		||||
			if (settings.AllowPopups)
 | 
			
		||||
			{
 | 
			
		||||
				logger.Debug($"Forwarding request to open new window for '{args.Url}'...");
 | 
			
		||||
				PopupRequested?.Invoke(args);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				logger.Debug($"Blocked attempt to open new window for '{args.Url}'.");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void Window_AddressChanged(string address)
 | 
			
		||||
		{
 | 
			
		||||
			logger.Debug($"The user requested to navigate to '{address}'.");
 | 
			
		||||
| 
						 | 
				
			
			@ -123,19 +179,18 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
 | 
			
		||||
		private void Window_ReloadRequested()
 | 
			
		||||
		{
 | 
			
		||||
			logger.Debug($"The user requested to reload the current page.");
 | 
			
		||||
			control.Reload();
 | 
			
		||||
			HandleReloadRequest();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void Window_BackwardNavigationRequested()
 | 
			
		||||
		{
 | 
			
		||||
			logger.Debug($"The user requested to navigate backwards.");
 | 
			
		||||
			logger.Debug($"Navigating forwards...");
 | 
			
		||||
			control.NavigateBackwards();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void Window_ForwardNavigationRequested()
 | 
			
		||||
		{
 | 
			
		||||
			logger.Debug($"The user requested to navigate forwards.");
 | 
			
		||||
			logger.Debug($"Navigating backwards...");
 | 
			
		||||
			control.NavigateForwards();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,27 +6,20 @@
 | 
			
		|||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using System.Windows.Forms;
 | 
			
		||||
using CefSharp;
 | 
			
		||||
using CefSharp.WinForms;
 | 
			
		||||
using SafeExamBrowser.Browser.Handlers;
 | 
			
		||||
using SafeExamBrowser.Contracts.Configuration;
 | 
			
		||||
using SafeExamBrowser.Contracts.I18n;
 | 
			
		||||
using SafeExamBrowser.Contracts.Logging;
 | 
			
		||||
using SafeExamBrowser.Contracts.UserInterface.Browser;
 | 
			
		||||
using SafeExamBrowser.Contracts.UserInterface.Browser.Events;
 | 
			
		||||
using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.BrowserSettings;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.Browser
 | 
			
		||||
{
 | 
			
		||||
	internal class BrowserControl : ChromiumWebBrowser, IBrowserControl
 | 
			
		||||
	{
 | 
			
		||||
		private AppConfig appConfig;
 | 
			
		||||
		private BrowserSettings settings;
 | 
			
		||||
		private IContextMenuHandler contextMenuHandler;
 | 
			
		||||
		private IDownloadHandler downloadHandler;
 | 
			
		||||
		private ILogger logger;
 | 
			
		||||
		private IText text;
 | 
			
		||||
		private IKeyboardHandler keyboardHandler;
 | 
			
		||||
		private ILifeSpanHandler lifeSpanHandler;
 | 
			
		||||
		private IRequestHandler requestHandler;
 | 
			
		||||
 | 
			
		||||
		private AddressChangedEventHandler addressChanged;
 | 
			
		||||
		private LoadingStateChangedEventHandler loadingStateChanged;
 | 
			
		||||
| 
						 | 
				
			
			@ -51,30 +44,31 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		public BrowserControl(
 | 
			
		||||
			AppConfig appConfig,
 | 
			
		||||
			BrowserSettings settings,
 | 
			
		||||
			IContextMenuHandler contextMenuHandler,
 | 
			
		||||
			IDownloadHandler downloadHandler,
 | 
			
		||||
			ILogger logger,
 | 
			
		||||
			IText text) : base(settings.StartUrl)
 | 
			
		||||
			IKeyboardHandler keyboardHandler,
 | 
			
		||||
			ILifeSpanHandler lifeSpanHandler,
 | 
			
		||||
			IRequestHandler requestHandler,
 | 
			
		||||
			string url) : base(url)
 | 
			
		||||
		{
 | 
			
		||||
			this.appConfig = appConfig;
 | 
			
		||||
			this.contextMenuHandler = contextMenuHandler;
 | 
			
		||||
			this.downloadHandler = downloadHandler;
 | 
			
		||||
			this.logger = logger;
 | 
			
		||||
			this.settings = settings;
 | 
			
		||||
			this.text = text;
 | 
			
		||||
			this.keyboardHandler = keyboardHandler;
 | 
			
		||||
			this.lifeSpanHandler = lifeSpanHandler;
 | 
			
		||||
			this.requestHandler = requestHandler;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Initialize()
 | 
			
		||||
		{
 | 
			
		||||
			AddressChanged += BrowserControl_AddressChanged;
 | 
			
		||||
			AddressChanged += (o, args) => addressChanged?.Invoke(args.Address);
 | 
			
		||||
			LoadingStateChanged += (o, args) => loadingStateChanged?.Invoke(args.IsLoading);
 | 
			
		||||
			MouseWheel += BrowserControl_MouseWheel;
 | 
			
		||||
			TitleChanged += (o, args) => titleChanged?.Invoke(args.Title);
 | 
			
		||||
 | 
			
		||||
			DownloadHandler = downloadHandler;
 | 
			
		||||
			KeyboardHandler = new KeyboardHandler(settings);
 | 
			
		||||
			MenuHandler = new ContextMenuHandler(settings, text);
 | 
			
		||||
			RequestHandler = new RequestHandler(appConfig);
 | 
			
		||||
			KeyboardHandler = keyboardHandler;
 | 
			
		||||
			LifeSpanHandler = lifeSpanHandler;
 | 
			
		||||
			MenuHandler = contextMenuHandler;
 | 
			
		||||
			RequestHandler = requestHandler;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void NavigateBackwards()
 | 
			
		||||
| 
						 | 
				
			
			@ -89,37 +83,12 @@ namespace SafeExamBrowser.Browser
 | 
			
		|||
 | 
			
		||||
		public void NavigateTo(string address)
 | 
			
		||||
		{
 | 
			
		||||
			if (!String.IsNullOrWhiteSpace(address))
 | 
			
		||||
			{
 | 
			
		||||
				Load(address);
 | 
			
		||||
			}
 | 
			
		||||
			Load(address);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Reload()
 | 
			
		||||
		{
 | 
			
		||||
			GetBrowser().Reload();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void BrowserControl_AddressChanged(object sender, AddressChangedEventArgs args)
 | 
			
		||||
		{
 | 
			
		||||
			logger.Debug($"Navigated to '{args.Address}'.");
 | 
			
		||||
			addressChanged?.Invoke(args.Address);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void BrowserControl_MouseWheel(object sender, MouseEventArgs e)
 | 
			
		||||
		{
 | 
			
		||||
			if (settings.AllowPageZoom && ModifierKeys == Keys.Control)
 | 
			
		||||
			{
 | 
			
		||||
				var browser = GetBrowser();
 | 
			
		||||
 | 
			
		||||
				browser.GetZoomLevelAsync().ContinueWith(task =>
 | 
			
		||||
				{
 | 
			
		||||
					if (task.IsCompleted)
 | 
			
		||||
					{
 | 
			
		||||
						browser.SetZoomLevel(task.Result + e.Delta * 0.1);
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										15
									
								
								SafeExamBrowser.Browser/Events/PopupRequestedEventArgs.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								SafeExamBrowser.Browser/Events/PopupRequestedEventArgs.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
 | 
			
		||||
 * 
 | 
			
		||||
 * This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
			
		||||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.Browser.Events
 | 
			
		||||
{
 | 
			
		||||
	internal class PopupRequestedEventArgs
 | 
			
		||||
	{
 | 
			
		||||
		public string Url { get; set; }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								SafeExamBrowser.Browser/Events/PopupRequestedEventHandler.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								SafeExamBrowser.Browser/Events/PopupRequestedEventHandler.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
 | 
			
		||||
 * 
 | 
			
		||||
 * This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
			
		||||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.Browser.Events
 | 
			
		||||
{
 | 
			
		||||
	internal delegate void PopupRequestedEventHandler(PopupRequestedEventArgs args);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
 | 
			
		||||
 * 
 | 
			
		||||
 * This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
			
		||||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.Browser.Events
 | 
			
		||||
{
 | 
			
		||||
	internal delegate void ReloadRequestedEventHandler();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.Browser
 | 
			
		|||
namespace SafeExamBrowser.Browser.Handlers
 | 
			
		||||
{
 | 
			
		||||
	/// <remarks>
 | 
			
		||||
	/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_IContextMenuHandler.htm.
 | 
			
		||||
	/// See https://cefsharp.github.io/api/67.0.0/html/T_CefSharp_IContextMenuHandler.htm.
 | 
			
		||||
	/// </remarks>
 | 
			
		||||
	internal class ContextMenuHandler : IContextMenuHandler
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.Browser
 | 
			
		|||
namespace SafeExamBrowser.Browser.Handlers
 | 
			
		||||
{
 | 
			
		||||
	/// <remarks>
 | 
			
		||||
	/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_IDownloadHandler.htm.
 | 
			
		||||
	/// See https://cefsharp.github.io/api/67.0.0/html/T_CefSharp_IDownloadHandler.htm.
 | 
			
		||||
	/// </remarks>
 | 
			
		||||
	internal class DownloadHandler : IDownloadHandler
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,21 +8,16 @@
 | 
			
		|||
 | 
			
		||||
using System.Windows.Forms;
 | 
			
		||||
using CefSharp;
 | 
			
		||||
using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.BrowserSettings;
 | 
			
		||||
using SafeExamBrowser.Browser.Events;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.Browser.Handlers
 | 
			
		||||
{
 | 
			
		||||
	/// <remarks>
 | 
			
		||||
	/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_IKeyboardHandler.htm.
 | 
			
		||||
	/// See https://cefsharp.github.io/api/67.0.0/html/T_CefSharp_IKeyboardHandler.htm.
 | 
			
		||||
	/// </remarks>
 | 
			
		||||
	internal class KeyboardHandler : IKeyboardHandler
 | 
			
		||||
	{
 | 
			
		||||
		private BrowserSettings settings;
 | 
			
		||||
 | 
			
		||||
		public KeyboardHandler(BrowserSettings settings)
 | 
			
		||||
		{
 | 
			
		||||
			this.settings = settings;
 | 
			
		||||
		}
 | 
			
		||||
		public event ReloadRequestedEventHandler ReloadRequested;
 | 
			
		||||
 | 
			
		||||
		public bool OnKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -31,9 +26,9 @@ namespace SafeExamBrowser.Browser.Handlers
 | 
			
		|||
 | 
			
		||||
		public bool OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut)
 | 
			
		||||
		{
 | 
			
		||||
			if (settings.AllowReloading && type == KeyType.KeyUp && windowsKeyCode == (int) Keys.F5)
 | 
			
		||||
			if (type == KeyType.KeyUp && windowsKeyCode == (int) Keys.F5)
 | 
			
		||||
			{
 | 
			
		||||
				browserControl.Reload();
 | 
			
		||||
				ReloadRequested?.Invoke();
 | 
			
		||||
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										44
									
								
								SafeExamBrowser.Browser/Handlers/LifeSpanHandler.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								SafeExamBrowser.Browser/Handlers/LifeSpanHandler.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
 | 
			
		||||
 * 
 | 
			
		||||
 * This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
			
		||||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
using CefSharp;
 | 
			
		||||
using SafeExamBrowser.Browser.Events;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.Browser.Handlers
 | 
			
		||||
{
 | 
			
		||||
	/// <remarks>
 | 
			
		||||
	/// See https://cefsharp.github.io/api/67.0.0/html/T_CefSharp_ILifeSpanHandler.htm.
 | 
			
		||||
	/// </remarks>
 | 
			
		||||
	internal class LifeSpanHandler : ILifeSpanHandler
 | 
			
		||||
	{
 | 
			
		||||
		public event PopupRequestedEventHandler PopupRequested;
 | 
			
		||||
 | 
			
		||||
		public bool DoClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
 | 
			
		||||
		{
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void OnAfterCreated(IWebBrowser chromiumWebBrowser, IBrowser browser)
 | 
			
		||||
		{
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void OnBeforeClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
 | 
			
		||||
		{
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
 | 
			
		||||
		{
 | 
			
		||||
			var args = new PopupRequestedEventArgs { Url = targetUrl };
 | 
			
		||||
 | 
			
		||||
			newBrowser = default(IWebBrowser);
 | 
			
		||||
			PopupRequested?.Invoke(args);
 | 
			
		||||
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -14,7 +14,7 @@ using SafeExamBrowser.Contracts.Configuration;
 | 
			
		|||
namespace SafeExamBrowser.Browser.Handlers
 | 
			
		||||
{
 | 
			
		||||
	/// <remarks>
 | 
			
		||||
	/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_Handler_DefaultRequestHandler.htm.
 | 
			
		||||
	/// See https://cefsharp.github.io/api/67.0.0/html/T_CefSharp_Handler_DefaultRequestHandler.htm.
 | 
			
		||||
	/// </remarks>
 | 
			
		||||
	internal class RequestHandler : DefaultRequestHandler
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,6 +66,9 @@
 | 
			
		|||
    <Compile Include="BrowserApplicationInfo.cs" />
 | 
			
		||||
    <Compile Include="BrowserApplicationInstance.cs" />
 | 
			
		||||
    <Compile Include="BrowserInstanceIdentifier.cs" />
 | 
			
		||||
    <Compile Include="Events\PopupRequestedEventArgs.cs" />
 | 
			
		||||
    <Compile Include="Events\PopupRequestedEventHandler.cs" />
 | 
			
		||||
    <Compile Include="Events\ReloadRequestedEventHandler.cs" />
 | 
			
		||||
    <Compile Include="Handlers\ContextMenuHandler.cs" />
 | 
			
		||||
    <Compile Include="BrowserControl.cs">
 | 
			
		||||
      <SubType>Component</SubType>
 | 
			
		||||
| 
						 | 
				
			
			@ -73,6 +76,7 @@
 | 
			
		|||
    <Compile Include="BrowserIconResource.cs" />
 | 
			
		||||
    <Compile Include="Handlers\DownloadHandler.cs" />
 | 
			
		||||
    <Compile Include="Handlers\KeyboardHandler.cs" />
 | 
			
		||||
    <Compile Include="Handlers\LifeSpanHandler.cs" />
 | 
			
		||||
    <Compile Include="Handlers\RequestHandler.cs" />
 | 
			
		||||
    <Compile Include="Properties\AssemblyInfo.cs" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -171,7 +171,7 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
		private IOperation BuildBrowserOperation()
 | 
			
		||||
		{
 | 
			
		||||
			var moduleLogger = new ModuleLogger(logger, "BrowserController");
 | 
			
		||||
			var browserController = new BrowserApplicationController(configuration.AppConfig, configuration.Settings.Browser, moduleLogger, text, uiFactory);
 | 
			
		||||
			var browserController = new BrowserApplicationController(configuration.AppConfig, configuration.Settings.Browser, messageBox, moduleLogger, text, uiFactory);
 | 
			
		||||
			var browserInfo = new BrowserApplicationInfo();
 | 
			
		||||
			var operation = new BrowserOperation(browserController, browserInfo, logger, Taskbar, uiFactory);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,39 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
 | 
			
		|||
{
 | 
			
		||||
	internal partial class DataMapper
 | 
			
		||||
	{
 | 
			
		||||
		private void MapAllowNavigation(Settings settings, object value)
 | 
			
		||||
		{
 | 
			
		||||
			if (value is bool allow)
 | 
			
		||||
			{
 | 
			
		||||
				settings.Browser.AllowBackwardNavigation = allow;
 | 
			
		||||
				settings.Browser.AllowForwardNavigation = allow;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void MapAllowPageZoom(Settings settings, object value)
 | 
			
		||||
		{
 | 
			
		||||
			if (value is bool allow)
 | 
			
		||||
			{
 | 
			
		||||
				settings.Browser.AllowPageZoom = allow;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void MapAllowPopups(Settings settings, object value)
 | 
			
		||||
		{
 | 
			
		||||
			if (value is bool block)
 | 
			
		||||
			{
 | 
			
		||||
				settings.Browser.AllowPopups = !block;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void MapAllowReload(Settings settings, object value)
 | 
			
		||||
		{
 | 
			
		||||
			if (value is bool allow)
 | 
			
		||||
			{
 | 
			
		||||
				settings.Browser.AllowReloading = allow;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void MapMainWindowMode(Settings settings, object value)
 | 
			
		||||
		{
 | 
			
		||||
			const int FULLSCREEN = 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -23,11 +56,11 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void MapPageZoom(Settings settings, object value)
 | 
			
		||||
		private void MapShowReloadWarning(Settings settings, object value)
 | 
			
		||||
		{
 | 
			
		||||
			if (value is bool enabled)
 | 
			
		||||
			if (value is bool show)
 | 
			
		||||
			{
 | 
			
		||||
				settings.Browser.AllowPageZoom = enabled;
 | 
			
		||||
				settings.Browser.ShowReloadWarning = show;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,12 +27,24 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
 | 
			
		|||
		{
 | 
			
		||||
			switch (key)
 | 
			
		||||
			{
 | 
			
		||||
				case Keys.Browser.EnablePageZoom:
 | 
			
		||||
					MapPageZoom(settings, value);
 | 
			
		||||
				case Keys.Browser.AllowNavigation:
 | 
			
		||||
					MapAllowNavigation(settings, value);
 | 
			
		||||
					break;
 | 
			
		||||
				case Keys.Browser.AllowPageZoom:
 | 
			
		||||
					MapAllowPageZoom(settings, value);
 | 
			
		||||
					break;
 | 
			
		||||
				case Keys.Browser.AllowPopups:
 | 
			
		||||
					MapAllowPopups(settings, value);
 | 
			
		||||
					break;
 | 
			
		||||
				case Keys.Browser.AllowReload:
 | 
			
		||||
					MapAllowReload(settings, value);
 | 
			
		||||
					break;
 | 
			
		||||
				case Keys.Browser.MainWindowMode:
 | 
			
		||||
					MapMainWindowMode(settings, value);
 | 
			
		||||
					break;
 | 
			
		||||
				case Keys.Browser.ShowReloadWarning:
 | 
			
		||||
					MapShowReloadWarning(settings, value);
 | 
			
		||||
					break;
 | 
			
		||||
				case Keys.ConfigurationFile.ConfigurationPurpose:
 | 
			
		||||
					MapConfigurationMode(settings, value);
 | 
			
		||||
					break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,10 +20,14 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
 | 
			
		|||
 | 
			
		||||
		internal static class Browser
 | 
			
		||||
		{
 | 
			
		||||
			internal const string AllowNavigation = "allowBrowsingBackForward";
 | 
			
		||||
			internal const string AllowPageZoom = "enableZoomPage";
 | 
			
		||||
			internal const string AllowPopups = "blockPopUpWindows";
 | 
			
		||||
			internal const string AllowReload = "browserWindowAllowReload";
 | 
			
		||||
			internal const string CustomUserAgentDesktop = "browserUserAgentWinDesktopModeCustom";
 | 
			
		||||
			internal const string CustomUserAgentMobile = "browserUserAgentWinTouchModeCustom";
 | 
			
		||||
			internal const string EnablePageZoom = "enableZoomPage";
 | 
			
		||||
			internal const string MainWindowMode = "browserViewMode";
 | 
			
		||||
			internal const string ShowReloadWarning = "showReloadWarning";
 | 
			
		||||
			internal const string UserAgentModeDesktop = "browserUserAgentWinDesktopMode";
 | 
			
		||||
			internal const string UserAgentModeMobile = "browserUserAgentWinTouchMode";
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,42 +17,47 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
 | 
			
		|||
	public class BrowserSettings
 | 
			
		||||
	{
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Determines whether the user should be allowed to change the URL of a browser window.
 | 
			
		||||
		/// Determines whether the user will be allowed to change the URL of a browser window.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public bool AllowAddressBar { get; set; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Determines whether the user should be allowed to navigate backwards in a browser window.
 | 
			
		||||
		/// Determines whether the user will be allowed to navigate backwards in a browser window.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public bool AllowBackwardNavigation { get; set; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Determines whether the user should be allowed to download configuration files.
 | 
			
		||||
		/// Determines whether the user will be allowed to download configuration files.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public bool AllowConfigurationDownloads { get; set; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Determines whether the user should be allowed to open the developer console of a browser window.
 | 
			
		||||
		/// Determines whether the user will be allowed to open the developer console of a browser window.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public bool AllowDeveloperConsole { get; set; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Determines whether the user should be allowed to download files (excluding configuration files).
 | 
			
		||||
		/// Determines whether the user will be allowed to download files (excluding configuration files).
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public bool AllowDownloads { get; set; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Determines whether the user should be allowed to navigate forwards in a browser window.
 | 
			
		||||
		/// Determines whether the user will be allowed to navigate forwards in a browser window.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public bool AllowForwardNavigation { get; set; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Determines whether the user should be allowed to zoom webpages.
 | 
			
		||||
		/// Determines whether the user will be allowed to zoom webpages.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public bool AllowPageZoom { get; set; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Determines whether the user should be allowed to reload webpages.
 | 
			
		||||
		/// Determines whether popup windows will be opened or not.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public bool AllowPopups { get; set; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Determines whether the user will be allowed to reload webpages.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public bool AllowReloading { get; set; }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -62,17 +67,22 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
 | 
			
		|||
		public string CustomUserAgent { get; set; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Determines whether the main browser window should be rendered in fullscreen mode, i.e. without window frame.
 | 
			
		||||
		/// Determines whether the main browser window will be rendered in fullscreen mode, i.e. without window frame.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public bool FullScreenMode { get; set; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// The start URL with which a new browser window should be loaded.
 | 
			
		||||
		/// Determines whether the user will need to confirm every reload attempt.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public bool ShowReloadWarning { get; set; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// The start URL with which a new browser window will be loaded.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public string StartUrl { get; set; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Determines whether a custom user agent should be used for all requests, see <see cref="CustomUserAgent"/>.
 | 
			
		||||
		/// Determines whether a custom user agent will be used for all requests, see <see cref="CustomUserAgent"/>.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public bool UseCustomUserAgent { get; set; }
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,6 +42,8 @@ namespace SafeExamBrowser.Contracts.I18n
 | 
			
		|||
		MessageBox_ReconfigurationErrorTitle,
 | 
			
		||||
		MessageBox_ReconfigurationQuestion,
 | 
			
		||||
		MessageBox_ReconfigurationQuestionTitle,
 | 
			
		||||
		MessageBox_ReloadConfirmation,
 | 
			
		||||
		MessageBox_ReloadConfirmationTitle,
 | 
			
		||||
		MessageBox_ShutdownError,
 | 
			
		||||
		MessageBox_ShutdownErrorTitle,
 | 
			
		||||
		MessageBox_SingleInstance,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ namespace SafeExamBrowser.Contracts.Monitoring
 | 
			
		|||
	/// </summary>
 | 
			
		||||
	public enum KeyState
 | 
			
		||||
	{
 | 
			
		||||
		None = 0,
 | 
			
		||||
		Unknown = 0,
 | 
			
		||||
		Pressed,
 | 
			
		||||
		Released
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,8 @@ namespace SafeExamBrowser.Contracts.Monitoring
 | 
			
		|||
	/// </summary>
 | 
			
		||||
	public enum MouseButton
 | 
			
		||||
	{
 | 
			
		||||
		None = 0,
 | 
			
		||||
		Unknown = 0,
 | 
			
		||||
		Auxiliary,
 | 
			
		||||
		Left,
 | 
			
		||||
		Middle,
 | 
			
		||||
		Right
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -84,6 +84,12 @@
 | 
			
		|||
  <Entry key="MessageBox_ReconfigurationQuestionTitle">
 | 
			
		||||
    Configuration Detected
 | 
			
		||||
  </Entry>
 | 
			
		||||
  <Entry key="MessageBox_ReloadConfirmation">
 | 
			
		||||
    Would you like to reload the current page?
 | 
			
		||||
  </Entry>
 | 
			
		||||
  <Entry key="MessageBox_ReloadConfirmationTitle">
 | 
			
		||||
    Reload?
 | 
			
		||||
  </Entry>
 | 
			
		||||
  <Entry key="MessageBox_ShutdownError">
 | 
			
		||||
    An unexpected error occurred during the shutdown procedure! Please consult the application log for more information...
 | 
			
		||||
  </Entry>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,6 +27,7 @@ namespace SafeExamBrowser.Monitoring.Mouse
 | 
			
		|||
		{
 | 
			
		||||
			var block = false;
 | 
			
		||||
 | 
			
		||||
			block |= button == MouseButton.Auxiliary;
 | 
			
		||||
			block |= button == MouseButton.Middle && !settings.AllowMiddleButton;
 | 
			
		||||
			block |= button == MouseButton.Right && !settings.AllowRightButton;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,8 +5,7 @@
 | 
			
		|||
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 | 
			
		||||
        xmlns:fa="http://schemas.fontawesome.io/icons/"
 | 
			
		||||
        xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop"
 | 
			
		||||
        mc:Ignorable="d" Title="BrowserWindow" Background="#FFF0F0F0" Height="500" Width="750" MinHeight="250" MinWidth="250"
 | 
			
		||||
        WindowState="Maximized" Icon=".\Images\SafeExamBrowser.ico">
 | 
			
		||||
        mc:Ignorable="d" Title="BrowserWindow" Background="#FFF0F0F0" Height="500" Width="750" MinHeight="250" MinWidth="250" Icon=".\Images\SafeExamBrowser.ico">
 | 
			
		||||
    <Window.Resources>
 | 
			
		||||
        <ResourceDictionary>
 | 
			
		||||
            <ResourceDictionary.MergedDictionaries>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -153,12 +153,26 @@ namespace SafeExamBrowser.UserInterface.Desktop
 | 
			
		|||
 | 
			
		||||
		private void ApplySettings()
 | 
			
		||||
		{
 | 
			
		||||
			if (IsMainWindow && settings.FullScreenMode)
 | 
			
		||||
			if (IsMainWindow)
 | 
			
		||||
			{
 | 
			
		||||
				MaxHeight = SystemParameters.WorkArea.Height;
 | 
			
		||||
				ResizeMode = ResizeMode.NoResize;
 | 
			
		||||
				WindowState = WindowState.Maximized;
 | 
			
		||||
				WindowStyle = WindowStyle.None;
 | 
			
		||||
				if (settings.FullScreenMode)
 | 
			
		||||
				{
 | 
			
		||||
					MaxHeight = SystemParameters.WorkArea.Height;
 | 
			
		||||
					ResizeMode = ResizeMode.NoResize;
 | 
			
		||||
					WindowState = WindowState.Maximized;
 | 
			
		||||
					WindowStyle = WindowStyle.None;
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					WindowState = WindowState.Maximized;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				Top = 0;
 | 
			
		||||
				Left = SystemParameters.WorkArea.Width / 2;
 | 
			
		||||
				Height = SystemParameters.WorkArea.Height;
 | 
			
		||||
				Width = SystemParameters.WorkArea.Width / 2;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			UrlTextBox.IsEnabled = settings.AllowAddressBar;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,17 +11,17 @@
 | 
			
		|||
            <ResourceDictionary.MergedDictionaries>
 | 
			
		||||
                <ResourceDictionary Source="../Templates/Buttons.xaml" />
 | 
			
		||||
                <ResourceDictionary Source="../Templates/Colors.xaml" />
 | 
			
		||||
                <ResourceDictionary Source="../Templates/ScrollViewers.xaml" />
 | 
			
		||||
            </ResourceDictionary.MergedDictionaries>
 | 
			
		||||
        </ResourceDictionary>
 | 
			
		||||
    </UserControl.Resources>
 | 
			
		||||
    <Grid>
 | 
			
		||||
        <Popup x:Name="InstancePopup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
 | 
			
		||||
            <ScrollViewer x:Name="InstanceScrollViewer" Background="{StaticResource BackgroundBrush}" VerticalScrollBarVisibility="Auto">
 | 
			
		||||
                <ScrollViewer.Resources>
 | 
			
		||||
                    <s:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">5</s:Double>
 | 
			
		||||
                </ScrollViewer.Resources>
 | 
			
		||||
                <StackPanel x:Name="InstanceStackPanel" />
 | 
			
		||||
            </ScrollViewer>
 | 
			
		||||
            <Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.75,0.75,0.75,0">
 | 
			
		||||
                <ScrollViewer x:Name="InstanceScrollViewer" MaxHeight="400" VerticalScrollBarVisibility="Auto" Template="{StaticResource SmallBarScrollViewer}">
 | 
			
		||||
                    <StackPanel x:Name="InstanceStackPanel" />
 | 
			
		||||
                </ScrollViewer>
 | 
			
		||||
            </Border>
 | 
			
		||||
        </Popup>
 | 
			
		||||
        <Button x:Name="Button" Background="{StaticResource BackgroundBrush}" Click="Button_Click" Padding="4" Template="{StaticResource TaskbarButton}" Width="50" />
 | 
			
		||||
    </Grid>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,13 +6,16 @@
 | 
			
		|||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System.Windows;
 | 
			
		||||
using System.Windows.Controls;
 | 
			
		||||
using System.Windows.Media;
 | 
			
		||||
using SafeExamBrowser.Contracts.Core;
 | 
			
		||||
using System.Windows.Threading;
 | 
			
		||||
using SafeExamBrowser.Contracts.Configuration;
 | 
			
		||||
using SafeExamBrowser.Contracts.Core;
 | 
			
		||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
 | 
			
		||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Desktop.Utilities;
 | 
			
		||||
| 
						 | 
				
			
			@ -36,13 +39,16 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
 | 
			
		|||
 | 
			
		||||
		public void RegisterInstance(IApplicationInstance instance)
 | 
			
		||||
		{
 | 
			
		||||
			var instanceButton = new ApplicationInstanceButton(instance, info);
 | 
			
		||||
			Dispatcher.Invoke(() =>
 | 
			
		||||
			{
 | 
			
		||||
				var instanceButton = new ApplicationInstanceButton(instance, info);
 | 
			
		||||
 | 
			
		||||
			instanceButton.Clicked += (id) => Clicked?.Invoke(id);
 | 
			
		||||
			instance.Terminated += (id) => Instance_OnTerminated(id, instanceButton);
 | 
			
		||||
				instanceButton.Clicked += (id) => Clicked?.Invoke(id);
 | 
			
		||||
				instance.Terminated += (id) => Instance_OnTerminated(id, instanceButton);
 | 
			
		||||
 | 
			
		||||
			instances.Add(instance);
 | 
			
		||||
			InstanceStackPanel.Children.Add(instanceButton);
 | 
			
		||||
				instances.Add(instance);
 | 
			
		||||
				InstanceStackPanel.Children.Add(instanceButton);
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void InitializeApplicationButton()
 | 
			
		||||
| 
						 | 
				
			
			@ -53,13 +59,13 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
 | 
			
		|||
			Button.Content = IconResourceLoader.Load(info.IconResource);
 | 
			
		||||
 | 
			
		||||
			Button.MouseEnter += (o, args) => InstancePopup.IsOpen = instances.Count > 1;
 | 
			
		||||
			Button.MouseLeave += (o, args) => InstancePopup.IsOpen = InstancePopup.IsMouseOver;
 | 
			
		||||
			InstancePopup.MouseLeave += (o, args) => InstancePopup.IsOpen = IsMouseOver;
 | 
			
		||||
			Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => InstancePopup.IsOpen = InstancePopup.IsMouseOver));
 | 
			
		||||
			InstancePopup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => InstancePopup.IsOpen = IsMouseOver));
 | 
			
		||||
 | 
			
		||||
			InstancePopup.Opened += (o, args) =>
 | 
			
		||||
			{
 | 
			
		||||
				Background = Brushes.LightBlue;
 | 
			
		||||
				Button.Background = Brushes.LightBlue;
 | 
			
		||||
				Background = Brushes.LightGray;
 | 
			
		||||
				Button.Background = Brushes.LightGray;
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			InstancePopup.Closed += (o, args) =>
 | 
			
		||||
| 
						 | 
				
			
			@ -67,14 +73,6 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
 | 
			
		|||
				Background = originalBrush;
 | 
			
		||||
				Button.Background = originalBrush;
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			InstanceStackPanel.SizeChanged += (o, args) =>
 | 
			
		||||
			{
 | 
			
		||||
				if (instances.Count > 9)
 | 
			
		||||
				{
 | 
			
		||||
					InstanceScrollViewer.MaxHeight = InstanceScrollViewer.ActualHeight;
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void Button_Click(object sender, RoutedEventArgs e)
 | 
			
		||||
| 
						 | 
				
			
			@ -91,8 +89,11 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
 | 
			
		|||
 | 
			
		||||
		private void Instance_OnTerminated(InstanceIdentifier id, ApplicationInstanceButton instanceButton)
 | 
			
		||||
		{
 | 
			
		||||
			instances.Remove(instances.FirstOrDefault(i => i.Id == id));
 | 
			
		||||
			InstanceStackPanel.Children.Remove(instanceButton);
 | 
			
		||||
			Dispatcher.BeginInvoke(new Action(() =>
 | 
			
		||||
			{
 | 
			
		||||
				instances.Remove(instances.FirstOrDefault(i => i.Id == id));
 | 
			
		||||
				InstanceStackPanel.Children.Remove(instanceButton);
 | 
			
		||||
			}));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,10 +14,10 @@
 | 
			
		|||
        </ResourceDictionary>
 | 
			
		||||
    </UserControl.Resources>
 | 
			
		||||
    <Grid>
 | 
			
		||||
        <Button x:Name="Button" Background="{StaticResource BackgroundBrush}"  Click="Button_Click" Height="25" Template="{StaticResource TaskbarButton}">
 | 
			
		||||
        <Button x:Name="Button" Background="Transparent" Click="Button_Click" Height="40" Padding="10" Template="{StaticResource TaskbarButton}">
 | 
			
		||||
            <StackPanel Orientation="Horizontal">
 | 
			
		||||
                <ContentControl x:Name="Icon" HorizontalAlignment="Left" />
 | 
			
		||||
                <TextBlock x:Name="Text" Padding="5,0,5,0" HorizontalAlignment="Left" VerticalAlignment="Center" />
 | 
			
		||||
                <ContentControl x:Name="Icon" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,10,0" />
 | 
			
		||||
                <TextBlock x:Name="Text" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="5" />
 | 
			
		||||
            </StackPanel>
 | 
			
		||||
        </Button>
 | 
			
		||||
    </Grid>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
        </ResourceDictionary>
 | 
			
		||||
    </UserControl.Resources>
 | 
			
		||||
    <Grid>
 | 
			
		||||
        <Button x:Name="Button" Height="40" Padding="10,0" Template="{StaticResource TaskbarButton}">
 | 
			
		||||
        <Button x:Name="Button" Background="Transparent" Height="40" Padding="10,0" Template="{StaticResource TaskbarButton}">
 | 
			
		||||
            <Grid>
 | 
			
		||||
                <Grid.ColumnDefinitions>
 | 
			
		||||
                    <ColumnDefinition Width="Auto" />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,8 +17,8 @@
 | 
			
		|||
    </UserControl.Resources>
 | 
			
		||||
    <Grid>
 | 
			
		||||
        <Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
 | 
			
		||||
            <Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.5,0.5,0.5,0">
 | 
			
		||||
                <ScrollViewer x:Name="LayoutsScrollViewer" Background="{StaticResource BackgroundBrush}" MaxHeight="250" VerticalScrollBarVisibility="Auto">
 | 
			
		||||
            <Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.75,0.75,0.75,0">
 | 
			
		||||
                <ScrollViewer x:Name="LayoutsScrollViewer" MaxHeight="250" VerticalScrollBarVisibility="Auto">
 | 
			
		||||
                    <ScrollViewer.Resources>
 | 
			
		||||
                        <s:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">5</s:Double>
 | 
			
		||||
                    </ScrollViewer.Resources>
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,11 @@
 | 
			
		|||
        </Popup>
 | 
			
		||||
        <Button x:Name="Button" Background="Transparent" Template="{StaticResource TaskbarButton}" Padding="5" Width="40">
 | 
			
		||||
            <Grid>
 | 
			
		||||
                <fa:ImageAwesome Panel.ZIndex="1" Foreground="LightGray" Icon="KeyboardOutline" VerticalAlignment="Center" />
 | 
			
		||||
                <fa:ImageAwesome Panel.ZIndex="1" Foreground="LightGray" Icon="KeyboardOutline" VerticalAlignment="Center">
 | 
			
		||||
                    <fa:ImageAwesome.Effect>
 | 
			
		||||
                        <DropShadowEffect Color="White" BlurRadius="5" Direction="0" Opacity="1" ShadowDepth="0" />
 | 
			
		||||
                    </fa:ImageAwesome.Effect>
 | 
			
		||||
                </fa:ImageAwesome>
 | 
			
		||||
                <Viewbox Panel.ZIndex="2" Stretch="Uniform">
 | 
			
		||||
                    <StackPanel Orientation="Vertical">
 | 
			
		||||
                        <TextBlock x:Name="LayoutCultureCode" FontWeight="Bold" TextAlignment="Center" Text="ENG">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@
 | 
			
		|||
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System.Windows.Controls;
 | 
			
		||||
using System.Windows.Media;
 | 
			
		||||
using SafeExamBrowser.Contracts.SystemComponents;
 | 
			
		||||
| 
						 | 
				
			
			@ -62,13 +63,13 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
 | 
			
		|||
			var originalBrush = Button.Background;
 | 
			
		||||
 | 
			
		||||
			Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
 | 
			
		||||
			Button.MouseLeave += (o, args) => Popup.IsOpen = Popup.IsMouseOver;
 | 
			
		||||
			Popup.MouseLeave += (o, args) => Popup.IsOpen = IsMouseOver;
 | 
			
		||||
			Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver));
 | 
			
		||||
			Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver));
 | 
			
		||||
 | 
			
		||||
			Popup.Opened += (o, args) =>
 | 
			
		||||
			{
 | 
			
		||||
				Background = Brushes.LightBlue;
 | 
			
		||||
				Button.Background = Brushes.LightBlue;
 | 
			
		||||
				Background = Brushes.LightGray;
 | 
			
		||||
				Button.Background = Brushes.LightGray;
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			Popup.Closed += (o, args) =>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,8 +15,8 @@
 | 
			
		|||
    </UserControl.Resources>
 | 
			
		||||
    <Grid>
 | 
			
		||||
        <Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
 | 
			
		||||
            <Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.5,0.5,0.5,0" MaxWidth="250" Padding="20,10,20,20">
 | 
			
		||||
                <Grid>
 | 
			
		||||
            <Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.75,0.75,0.75,0">
 | 
			
		||||
                <Grid MaxWidth="250" Margin="20,10,20,20">
 | 
			
		||||
                    <Grid.RowDefinitions>
 | 
			
		||||
                        <RowDefinition />
 | 
			
		||||
                        <RowDefinition />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
        </ResourceDictionary>
 | 
			
		||||
    </UserControl.Resources>
 | 
			
		||||
    <Grid>
 | 
			
		||||
        <Button x:Name="Button" Height="40" Padding="10,0" Template="{StaticResource TaskbarButton}">
 | 
			
		||||
        <Button x:Name="Button" Background="Transparent" Height="40" Padding="10,0" Template="{StaticResource TaskbarButton}">
 | 
			
		||||
            <Grid>
 | 
			
		||||
                <Grid.ColumnDefinitions>
 | 
			
		||||
                    <ColumnDefinition Width="Auto" />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,8 +17,8 @@
 | 
			
		|||
    </UserControl.Resources>
 | 
			
		||||
    <Grid>
 | 
			
		||||
        <Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
 | 
			
		||||
            <Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.5,0.5,0.5,0">
 | 
			
		||||
                <ScrollViewer Background="{StaticResource BackgroundBrush}" MaxHeight="250" VerticalScrollBarVisibility="Auto">
 | 
			
		||||
            <Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.75,0.75,0.75,0">
 | 
			
		||||
                <ScrollViewer MaxHeight="250" VerticalScrollBarVisibility="Auto">
 | 
			
		||||
                    <ScrollViewer.Resources>
 | 
			
		||||
                        <s:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">5</s:Double>
 | 
			
		||||
                    </ScrollViewer.Resources>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@
 | 
			
		|||
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System.Windows;
 | 
			
		||||
using System.Windows.Controls;
 | 
			
		||||
using System.Windows.Media;
 | 
			
		||||
| 
						 | 
				
			
			@ -114,13 +115,13 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
 | 
			
		|||
 | 
			
		||||
			SignalStrengthIcon.Child = GetIcon(0);
 | 
			
		||||
			Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
 | 
			
		||||
			Button.MouseLeave += (o, args) => Popup.IsOpen = Popup.IsMouseOver;
 | 
			
		||||
			Popup.MouseLeave += (o, args) => Popup.IsOpen = IsMouseOver;
 | 
			
		||||
			Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver));
 | 
			
		||||
			Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver));
 | 
			
		||||
 | 
			
		||||
			Popup.Opened += (o, args) =>
 | 
			
		||||
			{
 | 
			
		||||
				Background = Brushes.LightBlue;
 | 
			
		||||
				Button.Background = Brushes.LightBlue;
 | 
			
		||||
				Background = Brushes.LightGray;
 | 
			
		||||
				Button.Background = Brushes.LightGray;
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			Popup.Closed += (o, args) =>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -162,6 +162,10 @@
 | 
			
		|||
      <SubType>Designer</SubType>
 | 
			
		||||
      <Generator>MSBuild:Compile</Generator>
 | 
			
		||||
    </Page>
 | 
			
		||||
    <Page Include="Templates\ScrollViewers.xaml">
 | 
			
		||||
      <SubType>Designer</SubType>
 | 
			
		||||
      <Generator>MSBuild:Compile</Generator>
 | 
			
		||||
    </Page>
 | 
			
		||||
    <Resource Include="Images\Battery.xaml">
 | 
			
		||||
      <Generator>MSBuild:Compile</Generator>
 | 
			
		||||
      <SubType>Designer</SubType>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,13 @@
 | 
			
		|||
        mc:Ignorable="d"
 | 
			
		||||
        Title="Taskbar" Background="#FFF0F0F0" Height="40" Width="750" WindowStyle="None" Topmost="True" Visibility="Visible"
 | 
			
		||||
        ResizeMode="NoResize" Icon="./Images/SafeExamBrowser.ico">
 | 
			
		||||
    <Window.Resources>
 | 
			
		||||
        <ResourceDictionary>
 | 
			
		||||
            <ResourceDictionary.MergedDictionaries>
 | 
			
		||||
                <ResourceDictionary Source="./Templates/ScrollViewers.xaml" />
 | 
			
		||||
            </ResourceDictionary.MergedDictionaries>
 | 
			
		||||
        </ResourceDictionary>
 | 
			
		||||
    </Window.Resources>
 | 
			
		||||
    <Grid>
 | 
			
		||||
        <Grid.ColumnDefinitions>
 | 
			
		||||
            <ColumnDefinition Width="*" />
 | 
			
		||||
| 
						 | 
				
			
			@ -16,10 +23,8 @@
 | 
			
		|||
            <ColumnDefinition Width="Auto" />
 | 
			
		||||
            <ColumnDefinition Width="40" />
 | 
			
		||||
        </Grid.ColumnDefinitions>
 | 
			
		||||
        <ScrollViewer Grid.Column="0" x:Name="ApplicationScrollViewer" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto">
 | 
			
		||||
            <ScrollViewer.Resources>
 | 
			
		||||
                <s:Double x:Key="{x:Static SystemParameters.HorizontalScrollBarHeightKey}">5</s:Double>
 | 
			
		||||
            </ScrollViewer.Resources>
 | 
			
		||||
        <ScrollViewer Grid.Column="0" x:Name="ApplicationScrollViewer" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto"
 | 
			
		||||
                      Template="{StaticResource SmallBarScrollViewer}">
 | 
			
		||||
            <StackPanel x:Name="ApplicationStackPanel" Orientation="Horizontal" />
 | 
			
		||||
        </ScrollViewer>
 | 
			
		||||
        <StackPanel Grid.Column="1" x:Name="NotificationStackPanel" Orientation="Horizontal" VerticalAlignment="Stretch" />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 | 
			
		||||
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 | 
			
		||||
                    xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Templates">
 | 
			
		||||
    <ControlTemplate x:Key="Thumb" TargetType="{x:Type Thumb}">
 | 
			
		||||
        <Border Background="DarkGray" Height="Auto" Width="Auto" />
 | 
			
		||||
    </ControlTemplate>
 | 
			
		||||
    <ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type ScrollBar}">
 | 
			
		||||
        <Track Name="PART_Track" Height="Auto" IsDirectionReversed="True" Width="10">
 | 
			
		||||
            <Track.Thumb>
 | 
			
		||||
                <Thumb Template="{StaticResource Thumb}" Focusable="False" Margin="2.5" OverridesDefaultStyle="True" SnapsToDevicePixels="True" />
 | 
			
		||||
            </Track.Thumb>
 | 
			
		||||
        </Track>
 | 
			
		||||
    </ControlTemplate>
 | 
			
		||||
    <ControlTemplate x:Key="HorizontalScrollBar" TargetType="{x:Type ScrollBar}">
 | 
			
		||||
        <Track Name="PART_Track" Height="10" IsDirectionReversed="False" Width="Auto">
 | 
			
		||||
            <Track.Thumb>
 | 
			
		||||
                <Thumb Template="{StaticResource Thumb}" Focusable="False" Margin="2.5" OverridesDefaultStyle="True" SnapsToDevicePixels="True" />
 | 
			
		||||
            </Track.Thumb>
 | 
			
		||||
        </Track>
 | 
			
		||||
    </ControlTemplate>
 | 
			
		||||
    <ControlTemplate x:Key="SmallBarScrollViewer" TargetType="{x:Type ScrollViewer}">
 | 
			
		||||
        <Grid>
 | 
			
		||||
            <Grid.ColumnDefinitions>
 | 
			
		||||
                <ColumnDefinition Width="Auto"/>
 | 
			
		||||
                <ColumnDefinition />
 | 
			
		||||
            </Grid.ColumnDefinitions>
 | 
			
		||||
            <Grid.RowDefinitions>
 | 
			
		||||
                <RowDefinition />
 | 
			
		||||
                <RowDefinition Height="Auto"/>
 | 
			
		||||
            </Grid.RowDefinitions>
 | 
			
		||||
            <ScrollContentPresenter Grid.Column="0" Grid.Row="0" />
 | 
			
		||||
            <ScrollBar Name="PART_VerticalScrollBar" Grid.Column="1" Grid.Row="0" OverridesDefaultStyle="True" Value="{TemplateBinding VerticalOffset}"
 | 
			
		||||
                       Maximum="{TemplateBinding ScrollableHeight}" Template="{StaticResource VerticalScrollBar}"
 | 
			
		||||
                       ViewportSize="{TemplateBinding ViewportHeight}" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
 | 
			
		||||
            <ScrollBar Name="PART_HorizontalScrollBar" Grid.Column="0" Grid.Row="1" OverridesDefaultStyle="True" Orientation="Horizontal"
 | 
			
		||||
                       Value="{TemplateBinding HorizontalOffset}" Maximum="{TemplateBinding ScrollableWidth}" Template="{StaticResource HorizontalScrollBar}"
 | 
			
		||||
                       ViewportSize="{TemplateBinding ViewportWidth}" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />
 | 
			
		||||
        </Grid>
 | 
			
		||||
    </ControlTemplate>
 | 
			
		||||
</ResourceDictionary>
 | 
			
		||||
| 
						 | 
				
			
			@ -184,5 +184,23 @@ namespace SafeExamBrowser.WindowsApi.Constants
 | 
			
		|||
		/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms646287(v=vs.85).aspx
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		internal const int WM_SYSKEYUP = 0x105;
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Posted when the user presses the first or second X button while the cursor is in the client area of a window. If the mouse is
 | 
			
		||||
		/// not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has
 | 
			
		||||
		/// captured the mouse.
 | 
			
		||||
		/// 
 | 
			
		||||
		/// See https://docs.microsoft.com/de-de/windows/desktop/inputdev/wm-xbuttondown.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		internal const int WM_XBUTTONDOWN = 0x20B;
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Posted when the user releases the first or second X button while the cursor is in the client area of a window. If the mouse is
 | 
			
		||||
		/// not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has
 | 
			
		||||
		/// captured the mouse.
 | 
			
		||||
		/// 
 | 
			
		||||
		/// See https://docs.microsoft.com/de-de/windows/desktop/inputdev/wm-xbuttonup.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		internal const int WM_XBUTTONUP = 0x20C;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,7 +81,7 @@ namespace SafeExamBrowser.WindowsApi.Monitoring
 | 
			
		|||
				case Constant.WM_SYSKEYUP:
 | 
			
		||||
					return KeyState.Released;
 | 
			
		||||
				default:
 | 
			
		||||
					return KeyState.None;
 | 
			
		||||
					return KeyState.Unknown;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,8 +82,11 @@ namespace SafeExamBrowser.WindowsApi.Monitoring
 | 
			
		|||
				case Constant.WM_RBUTTONDOWN:
 | 
			
		||||
				case Constant.WM_RBUTTONUP:
 | 
			
		||||
					return MouseButton.Right;
 | 
			
		||||
				case Constant.WM_XBUTTONDOWN:
 | 
			
		||||
				case Constant.WM_XBUTTONUP:
 | 
			
		||||
					return MouseButton.Auxiliary;
 | 
			
		||||
				default:
 | 
			
		||||
					return MouseButton.None;
 | 
			
		||||
					return MouseButton.Unknown;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -94,13 +97,15 @@ namespace SafeExamBrowser.WindowsApi.Monitoring
 | 
			
		|||
				case Constant.WM_LBUTTONDOWN:
 | 
			
		||||
				case Constant.WM_MBUTTONDOWN:
 | 
			
		||||
				case Constant.WM_RBUTTONDOWN:
 | 
			
		||||
				case Constant.WM_XBUTTONDOWN:
 | 
			
		||||
					return KeyState.Pressed;
 | 
			
		||||
				case Constant.WM_LBUTTONUP:
 | 
			
		||||
				case Constant.WM_MBUTTONUP:
 | 
			
		||||
				case Constant.WM_RBUTTONUP:
 | 
			
		||||
				case Constant.WM_XBUTTONUP:
 | 
			
		||||
					return KeyState.Released;
 | 
			
		||||
				default:
 | 
			
		||||
					return KeyState.None;
 | 
			
		||||
					return KeyState.Unknown;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue