SEBWIN-312: Implemented scaffolding for task view and its keyboard activator. Finally consolidated keyboard and mouse hooks and resolved dependency from WindowsApi to UI.
This commit is contained in:
		
							parent
							
								
									4f930a26d8
								
							
						
					
					
						commit
						5f31656649
					
				
					 37 changed files with 734 additions and 506 deletions
				
			
		| 
						 | 
				
			
			@ -100,11 +100,11 @@ namespace SafeExamBrowser.Client.UnitTests
 | 
			
		|||
				runtimeProxy.Object,
 | 
			
		||||
				shutdown.Object,
 | 
			
		||||
				taskbar.Object,
 | 
			
		||||
				terminationActivator.Object,
 | 
			
		||||
				text.Object,
 | 
			
		||||
				uiFactory.Object);
 | 
			
		||||
 | 
			
		||||
			context.AppConfig = appConfig;
 | 
			
		||||
			context.Activators.Add(terminationActivator.Object);
 | 
			
		||||
			context.Browser = browserController.Object;
 | 
			
		||||
			context.ClientHost = clientHost.Object;
 | 
			
		||||
			context.SessionId = sessionId;
 | 
			
		||||
| 
						 | 
				
			
			@ -423,13 +423,29 @@ namespace SafeExamBrowser.Client.UnitTests
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		[TestMethod]
 | 
			
		||||
		public void Shutdown_MustCloseActionCenterAndTaskbar()
 | 
			
		||||
		public void Shutdown_MustCloseActionCenterAndTaskbarIfEnabled()
 | 
			
		||||
		{
 | 
			
		||||
			settings.ActionCenter.EnableActionCenter = true;
 | 
			
		||||
			settings.Taskbar.EnableTaskbar = true;
 | 
			
		||||
 | 
			
		||||
			sut.Terminate();
 | 
			
		||||
 | 
			
		||||
			actionCenter.Verify(a => a.Close(), Times.Once);
 | 
			
		||||
			taskbar.Verify(o => o.Close(), Times.Once);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[TestMethod]
 | 
			
		||||
		public void Shutdown_MustNotCloseActionCenterAndTaskbarIfNotEnabled()
 | 
			
		||||
		{
 | 
			
		||||
			settings.ActionCenter.EnableActionCenter = false;
 | 
			
		||||
			settings.Taskbar.EnableTaskbar = false;
 | 
			
		||||
 | 
			
		||||
			sut.Terminate();
 | 
			
		||||
 | 
			
		||||
			actionCenter.Verify(a => a.Close(), Times.Never);
 | 
			
		||||
			taskbar.Verify(o => o.Close(), Times.Never);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[TestMethod]
 | 
			
		||||
		public void Shutdown_MustShowErrorMessageOnCommunicationFailure()
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,6 @@
 | 
			
		|||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
 | 
			
		||||
using Moq;
 | 
			
		||||
using SafeExamBrowser.Client.Contracts;
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +20,6 @@ using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
 | 
			
		|||
using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.Client.UnitTests.Operations
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -32,7 +30,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
 | 
			
		|||
		private Mock<IAudio> audio;
 | 
			
		||||
		private ClientContext context;
 | 
			
		||||
		private Mock<ILogger> logger;
 | 
			
		||||
		private Mock<ITerminationActivator> terminationActivator;
 | 
			
		||||
		private Mock<INotificationInfo> aboutInfo;
 | 
			
		||||
		private Mock<INotificationController> aboutController;
 | 
			
		||||
		private Mock<IKeyboard> keyboard;
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +38,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
 | 
			
		|||
		private Mock<IPowerSupply> powerSupply;
 | 
			
		||||
		private Mock<ISystemInfo> systemInfo;
 | 
			
		||||
		private Mock<ITaskbar> taskbar;
 | 
			
		||||
		private Mock<ITaskView> taskView;
 | 
			
		||||
		private Mock<IText> text;
 | 
			
		||||
		private Mock<IUserInterfaceFactory> uiFactory;
 | 
			
		||||
		private Mock<IWirelessAdapter> wirelessAdapter;
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +60,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
 | 
			
		|||
			powerSupply = new Mock<IPowerSupply>();
 | 
			
		||||
			systemInfo = new Mock<ISystemInfo>();
 | 
			
		||||
			taskbar = new Mock<ITaskbar>();
 | 
			
		||||
			terminationActivator = new Mock<ITerminationActivator>();
 | 
			
		||||
			taskView = new Mock<ITaskView>();
 | 
			
		||||
			text = new Mock<IText>();
 | 
			
		||||
			uiFactory = new Mock<IUserInterfaceFactory>();
 | 
			
		||||
			wirelessAdapter = new Mock<IWirelessAdapter>();
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +84,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
 | 
			
		|||
				powerSupply.Object,
 | 
			
		||||
				systemInfo.Object,
 | 
			
		||||
				taskbar.Object,
 | 
			
		||||
				terminationActivator.Object,
 | 
			
		||||
				taskView.Object,
 | 
			
		||||
				text.Object,
 | 
			
		||||
				uiFactory.Object,
 | 
			
		||||
				wirelessAdapter.Object);
 | 
			
		||||
| 
						 | 
				
			
			@ -95,28 +93,20 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
 | 
			
		|||
		[TestMethod]
 | 
			
		||||
		public void Perform_MustInitializeActivators()
 | 
			
		||||
		{
 | 
			
		||||
			var activatorMocks = new List<Mock<IActionCenterActivator>>
 | 
			
		||||
			{
 | 
			
		||||
				new Mock<IActionCenterActivator>(),
 | 
			
		||||
				new Mock<IActionCenterActivator>(),
 | 
			
		||||
				new Mock<IActionCenterActivator>()
 | 
			
		||||
			};
 | 
			
		||||
			var actionCenterActivator = new Mock<IActionCenterActivator>();
 | 
			
		||||
			var taskViewActivator = new Mock<ITaskViewActivator>();
 | 
			
		||||
			var terminationActivator = new Mock<ITerminationActivator>();
 | 
			
		||||
 | 
			
		||||
			context.Activators.Add(actionCenterActivator.Object);
 | 
			
		||||
			context.Activators.Add(taskViewActivator.Object);
 | 
			
		||||
			context.Activators.Add(terminationActivator.Object);
 | 
			
		||||
			context.Settings.ActionCenter.EnableActionCenter = true;
 | 
			
		||||
			
 | 
			
		||||
			foreach (var activator in activatorMocks)
 | 
			
		||||
			{
 | 
			
		||||
				context.Activators.Add(activator.Object);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			sut.Perform();
 | 
			
		||||
 | 
			
		||||
			terminationActivator.Verify(t => t.Start(), Times.Once);
 | 
			
		||||
 | 
			
		||||
			foreach (var activator in activatorMocks)
 | 
			
		||||
			{
 | 
			
		||||
				activator.Verify(a => a.Start(), Times.Once);
 | 
			
		||||
			}
 | 
			
		||||
			actionCenterActivator.Verify(a => a.Start(), Times.Once);
 | 
			
		||||
			taskViewActivator.Verify(a => a.Start(), Times.Once);
 | 
			
		||||
			terminationActivator.Verify(a => a.Start(), Times.Once);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[TestMethod]
 | 
			
		||||
| 
						 | 
				
			
			@ -183,6 +173,12 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
 | 
			
		|||
			taskbar.Verify(t => t.AddNotificationControl(It.Is<INotificationControl>(i => i == logControl.Object)), Times.Never);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[TestMethod]
 | 
			
		||||
		public void Perform_MustInitializeTaskView()
 | 
			
		||||
		{
 | 
			
		||||
			Assert.Fail("TODO");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[TestMethod]
 | 
			
		||||
		public void Perform_MustInitializeSystemComponents()
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -242,9 +238,15 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
 | 
			
		|||
		[TestMethod]
 | 
			
		||||
		public void Perform_MustNotInitializeActionCenterIfNotEnabled()
 | 
			
		||||
		{
 | 
			
		||||
			var actionCenterActivator = new Mock<IActionCenterActivator>();
 | 
			
		||||
 | 
			
		||||
			context.Activators.Add(actionCenterActivator.Object);
 | 
			
		||||
			context.Settings.ActionCenter.EnableActionCenter = false;
 | 
			
		||||
 | 
			
		||||
			sut.Perform();
 | 
			
		||||
 | 
			
		||||
			actionCenter.VerifyNoOtherCalls();
 | 
			
		||||
			actionCenterActivator.VerifyNoOtherCalls();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[TestMethod]
 | 
			
		||||
| 
						 | 
				
			
			@ -258,28 +260,20 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
 | 
			
		|||
		[TestMethod]
 | 
			
		||||
		public void Revert_MustTerminateActivators()
 | 
			
		||||
		{
 | 
			
		||||
			var activatorMocks = new List<Mock<IActionCenterActivator>>
 | 
			
		||||
			{
 | 
			
		||||
				new Mock<IActionCenterActivator>(),
 | 
			
		||||
				new Mock<IActionCenterActivator>(),
 | 
			
		||||
				new Mock<IActionCenterActivator>()
 | 
			
		||||
			};
 | 
			
		||||
			var actionCenterActivator = new Mock<IActionCenterActivator>();
 | 
			
		||||
			var taskViewActivator = new Mock<ITaskViewActivator>();
 | 
			
		||||
			var terminationActivator = new Mock<ITerminationActivator>();
 | 
			
		||||
 | 
			
		||||
			context.Activators.Add(actionCenterActivator.Object);
 | 
			
		||||
			context.Activators.Add(taskViewActivator.Object);
 | 
			
		||||
			context.Activators.Add(terminationActivator.Object);
 | 
			
		||||
			context.Settings.ActionCenter.EnableActionCenter = true;
 | 
			
		||||
 | 
			
		||||
			foreach (var activator in activatorMocks)
 | 
			
		||||
			{
 | 
			
		||||
				context.Activators.Add(activator.Object);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			sut.Revert();
 | 
			
		||||
 | 
			
		||||
			terminationActivator.Verify(t => t.Stop(), Times.Once);
 | 
			
		||||
 | 
			
		||||
			foreach (var activator in activatorMocks)
 | 
			
		||||
			{
 | 
			
		||||
				activator.Verify(a => a.Stop(), Times.Once);
 | 
			
		||||
			}
 | 
			
		||||
			actionCenterActivator.Verify(a => a.Stop(), Times.Once);
 | 
			
		||||
			taskViewActivator.Verify(a => a.Stop(), Times.Once);
 | 
			
		||||
			terminationActivator.Verify(a => a.Stop(), Times.Once);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[TestMethod]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,9 +23,9 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
	internal class ClientContext
 | 
			
		||||
	{
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// All activators for the action center.
 | 
			
		||||
		/// All activators for shell components.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		internal IList<IActionCenterActivator> Activators { get; }
 | 
			
		||||
		internal IList<IActivator> Activators { get; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// All applications allowed for the current session.
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +59,7 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
 | 
			
		||||
		internal ClientContext()
 | 
			
		||||
		{
 | 
			
		||||
			Activators = new List<IActionCenterActivator>();
 | 
			
		||||
			Activators = new List<IActivator>();
 | 
			
		||||
			Applications = new List<IApplication>();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,6 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
		private Action shutdown;
 | 
			
		||||
		private ISplashScreen splashScreen;
 | 
			
		||||
		private ITaskbar taskbar;
 | 
			
		||||
		private ITerminationActivator terminationActivator;
 | 
			
		||||
		private IText text;
 | 
			
		||||
		private IUserInterfaceFactory uiFactory;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -72,7 +71,6 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
			IRuntimeProxy runtime,
 | 
			
		||||
			Action shutdown,
 | 
			
		||||
			ITaskbar taskbar,
 | 
			
		||||
			ITerminationActivator terminationActivator,
 | 
			
		||||
			IText text,
 | 
			
		||||
			IUserInterfaceFactory uiFactory)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +86,6 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
			this.runtime = runtime;
 | 
			
		||||
			this.shutdown = shutdown;
 | 
			
		||||
			this.taskbar = taskbar;
 | 
			
		||||
			this.terminationActivator = terminationActivator;
 | 
			
		||||
			this.text = text;
 | 
			
		||||
			this.uiFactory = uiFactory;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -140,9 +137,8 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
			logger.Info("Initiating shutdown procedure...");
 | 
			
		||||
 | 
			
		||||
			splashScreen = uiFactory.CreateSplashScreen(context.AppConfig);
 | 
			
		||||
			actionCenter.Close();
 | 
			
		||||
			taskbar.Close();
 | 
			
		||||
 | 
			
		||||
			CloseShell();
 | 
			
		||||
			DeregisterEvents();
 | 
			
		||||
 | 
			
		||||
			var success = operations.TryRevert() == OperationResult.Success;
 | 
			
		||||
| 
						 | 
				
			
			@ -182,7 +178,11 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
			displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
 | 
			
		||||
			runtime.ConnectionLost += Runtime_ConnectionLost;
 | 
			
		||||
			taskbar.QuitButtonClicked += Shell_QuitButtonClicked;
 | 
			
		||||
			terminationActivator.Activated += TerminationActivator_Activated;
 | 
			
		||||
 | 
			
		||||
			foreach (var activator in context.Activators.OfType<ITerminationActivator>())
 | 
			
		||||
			{
 | 
			
		||||
				activator.Activated += TerminationActivator_Activated;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void DeregisterEvents()
 | 
			
		||||
| 
						 | 
				
			
			@ -193,7 +193,6 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
			displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
 | 
			
		||||
			runtime.ConnectionLost -= Runtime_ConnectionLost;
 | 
			
		||||
			taskbar.QuitButtonClicked -= Shell_QuitButtonClicked;
 | 
			
		||||
			terminationActivator.Activated -= TerminationActivator_Activated;
 | 
			
		||||
 | 
			
		||||
			if (Browser != null)
 | 
			
		||||
			{
 | 
			
		||||
| 
						 | 
				
			
			@ -207,10 +206,33 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
				ClientHost.ReconfigurationDenied -= ClientHost_ReconfigurationDenied;
 | 
			
		||||
				ClientHost.Shutdown -= ClientHost_Shutdown;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			foreach (var activator in context.Activators.OfType<ITerminationActivator>())
 | 
			
		||||
			{
 | 
			
		||||
				activator.Activated -= TerminationActivator_Activated;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void CloseShell()
 | 
			
		||||
		{
 | 
			
		||||
			if (Settings.ActionCenter.EnableActionCenter)
 | 
			
		||||
			{
 | 
			
		||||
				actionCenter.Close();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (Settings.Taskbar.EnableTaskbar)
 | 
			
		||||
			{
 | 
			
		||||
				taskbar.Close();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void ShowShell()
 | 
			
		||||
		{
 | 
			
		||||
			if (Settings.ActionCenter.EnableActionCenter)
 | 
			
		||||
			{
 | 
			
		||||
				actionCenter.Show();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (Settings.Taskbar.EnableTaskbar)
 | 
			
		||||
			{
 | 
			
		||||
				taskbar.Show();
 | 
			
		||||
| 
						 | 
				
			
			@ -527,9 +549,6 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
 | 
			
		||||
		private void PauseActivators()
 | 
			
		||||
		{
 | 
			
		||||
			// TODO: Same for task view activator!
 | 
			
		||||
			terminationActivator.Pause();
 | 
			
		||||
 | 
			
		||||
			foreach (var activator in context.Activators)
 | 
			
		||||
			{
 | 
			
		||||
				activator.Pause();
 | 
			
		||||
| 
						 | 
				
			
			@ -538,9 +557,6 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
 | 
			
		||||
		private void ResumeActivators()
 | 
			
		||||
		{
 | 
			
		||||
			// TODO: Same for task view activator!
 | 
			
		||||
			terminationActivator.Resume();
 | 
			
		||||
 | 
			
		||||
			foreach (var activator in context.Activators)
 | 
			
		||||
			{
 | 
			
		||||
				activator.Resume();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,6 +44,7 @@ using SafeExamBrowser.SystemComponents.WirelessNetwork;
 | 
			
		|||
using SafeExamBrowser.UserInterface.Contracts;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Shared.Activators;
 | 
			
		||||
using SafeExamBrowser.WindowsApi;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts;
 | 
			
		||||
using Desktop = SafeExamBrowser.UserInterface.Desktop;
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +71,6 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
		private IRuntimeProxy runtimeProxy;
 | 
			
		||||
		private ISystemInfo systemInfo;
 | 
			
		||||
		private ITaskbar taskbar;
 | 
			
		||||
		private ITerminationActivator terminationActivator;
 | 
			
		||||
		private IText text;
 | 
			
		||||
		private ITextResource textResource;
 | 
			
		||||
		private IUserInterfaceFactory uiFactory;
 | 
			
		||||
| 
						 | 
				
			
			@ -94,7 +94,6 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
			uiFactory = BuildUserInterfaceFactory();
 | 
			
		||||
			runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), ModuleLogger(nameof(RuntimeProxy)), Interlocutor.Client);
 | 
			
		||||
			taskbar = BuildTaskbar();
 | 
			
		||||
			terminationActivator = new TerminationActivator(ModuleLogger(nameof(TerminationActivator)));
 | 
			
		||||
 | 
			
		||||
			var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory)));
 | 
			
		||||
			var applicationFactory = new ApplicationFactory(ModuleLogger(nameof(ApplicationFactory)), processFactory);
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +133,6 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
				runtimeProxy,
 | 
			
		||||
				shutdown,
 | 
			
		||||
				taskbar,
 | 
			
		||||
				terminationActivator,
 | 
			
		||||
				text,
 | 
			
		||||
				uiFactory);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -244,6 +242,7 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
			var logInfo = new LogNotificationInfo(text);
 | 
			
		||||
			var logController = new LogNotificationController(logger, uiFactory);
 | 
			
		||||
			var powerSupply = new PowerSupply(ModuleLogger(nameof(PowerSupply)));
 | 
			
		||||
			var taskView = BuildTaskView();
 | 
			
		||||
			var wirelessAdapter = new WirelessAdapter(ModuleLogger(nameof(WirelessAdapter)));
 | 
			
		||||
			var operation = new ShellOperation(
 | 
			
		||||
				actionCenter,
 | 
			
		||||
| 
						 | 
				
			
			@ -258,13 +257,15 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
				powerSupply,
 | 
			
		||||
				systemInfo,
 | 
			
		||||
				taskbar,
 | 
			
		||||
				terminationActivator,
 | 
			
		||||
				taskView,
 | 
			
		||||
				text,
 | 
			
		||||
				uiFactory,
 | 
			
		||||
				wirelessAdapter);
 | 
			
		||||
 | 
			
		||||
			context.Activators.Add(new KeyboardActivator(ModuleLogger(nameof(KeyboardActivator))));
 | 
			
		||||
			context.Activators.Add(new TouchActivator(ModuleLogger(nameof(TouchActivator))));
 | 
			
		||||
			context.Activators.Add(new ActionCenterKeyboardActivator(ModuleLogger(nameof(ActionCenterKeyboardActivator)), nativeMethods));
 | 
			
		||||
			context.Activators.Add(new ActionCenterTouchActivator(ModuleLogger(nameof(ActionCenterTouchActivator)), nativeMethods));
 | 
			
		||||
			context.Activators.Add(new TaskViewKeyboardActivator(ModuleLogger(nameof(TaskViewKeyboardActivator)), nativeMethods));
 | 
			
		||||
			context.Activators.Add(new TerminationActivator(ModuleLogger(nameof(TerminationActivator)), nativeMethods));
 | 
			
		||||
 | 
			
		||||
			return operation;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -302,6 +303,18 @@ namespace SafeExamBrowser.Client
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private ITaskView BuildTaskView()
 | 
			
		||||
		{
 | 
			
		||||
			switch (uiMode)
 | 
			
		||||
			{
 | 
			
		||||
				case UserInterfaceMode.Mobile:
 | 
			
		||||
					// TODO
 | 
			
		||||
					throw new NotImplementedException();
 | 
			
		||||
				default:
 | 
			
		||||
					return new Desktop.TaskView();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private IUserInterfaceFactory BuildUserInterfaceFactory()
 | 
			
		||||
		{
 | 
			
		||||
			switch (uiMode)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,6 @@ using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
 | 
			
		|||
using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.Client.Operations
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +34,7 @@ namespace SafeExamBrowser.Client.Operations
 | 
			
		|||
		private IPowerSupply powerSupply;
 | 
			
		||||
		private ISystemInfo systemInfo;
 | 
			
		||||
		private ITaskbar taskbar;
 | 
			
		||||
		private ITerminationActivator terminationActivator;
 | 
			
		||||
		private ITaskView taskView;
 | 
			
		||||
		private IText text;
 | 
			
		||||
		private IUserInterfaceFactory uiFactory;
 | 
			
		||||
		private IWirelessAdapter wirelessAdapter;
 | 
			
		||||
| 
						 | 
				
			
			@ -56,7 +55,7 @@ namespace SafeExamBrowser.Client.Operations
 | 
			
		|||
			IPowerSupply powerSupply,
 | 
			
		||||
			ISystemInfo systemInfo,
 | 
			
		||||
			ITaskbar taskbar,
 | 
			
		||||
			ITerminationActivator terminationActivator,
 | 
			
		||||
			ITaskView taskView,
 | 
			
		||||
			IText text,
 | 
			
		||||
			IUserInterfaceFactory uiFactory,
 | 
			
		||||
			IWirelessAdapter wirelessAdapter) : base(context)
 | 
			
		||||
| 
						 | 
				
			
			@ -71,9 +70,9 @@ namespace SafeExamBrowser.Client.Operations
 | 
			
		|||
			this.logController = logController;
 | 
			
		||||
			this.powerSupply = powerSupply;
 | 
			
		||||
			this.systemInfo = systemInfo;
 | 
			
		||||
			this.terminationActivator = terminationActivator;
 | 
			
		||||
			this.text = text;
 | 
			
		||||
			this.taskbar = taskbar;
 | 
			
		||||
			this.taskView = taskView;
 | 
			
		||||
			this.uiFactory = uiFactory;
 | 
			
		||||
			this.wirelessAdapter = wirelessAdapter;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -86,6 +85,7 @@ namespace SafeExamBrowser.Client.Operations
 | 
			
		|||
			InitializeSystemComponents();
 | 
			
		||||
			InitializeActionCenter();
 | 
			
		||||
			InitializeTaskbar();
 | 
			
		||||
			InitializeTaskView();
 | 
			
		||||
			InitializeActivators();
 | 
			
		||||
 | 
			
		||||
			return OperationResult.Success;
 | 
			
		||||
| 
						 | 
				
			
			@ -105,14 +105,23 @@ namespace SafeExamBrowser.Client.Operations
 | 
			
		|||
 | 
			
		||||
		private void InitializeActivators()
 | 
			
		||||
		{
 | 
			
		||||
			terminationActivator.Start();
 | 
			
		||||
 | 
			
		||||
			if (Context.Settings.ActionCenter.EnableActionCenter)
 | 
			
		||||
			foreach (var activator in Context.Activators)
 | 
			
		||||
			{
 | 
			
		||||
				foreach (var activator in Context.Activators)
 | 
			
		||||
				if (Context.Settings.ActionCenter.EnableActionCenter && activator is IActionCenterActivator actionCenterActivator)
 | 
			
		||||
				{
 | 
			
		||||
					actionCenter.Register(activator);
 | 
			
		||||
					activator.Start();
 | 
			
		||||
					actionCenter.Register(actionCenterActivator);
 | 
			
		||||
					actionCenterActivator.Start();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (activator is ITaskViewActivator taskViewActivator)
 | 
			
		||||
				{
 | 
			
		||||
					taskView.Register(taskViewActivator);
 | 
			
		||||
					taskViewActivator.Start();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (activator is ITerminationActivator terminationActivator)
 | 
			
		||||
				{
 | 
			
		||||
					terminationActivator.Start();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -161,6 +170,16 @@ namespace SafeExamBrowser.Client.Operations
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void InitializeTaskView()
 | 
			
		||||
		{
 | 
			
		||||
			logger.Info("Initializing task view...");
 | 
			
		||||
 | 
			
		||||
			foreach (var application in Context.Applications)
 | 
			
		||||
			{
 | 
			
		||||
				taskView.Add(application);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void InitializeApplicationsFor(Location location)
 | 
			
		||||
		{
 | 
			
		||||
			foreach (var application in Context.Applications)
 | 
			
		||||
| 
						 | 
				
			
			@ -295,14 +314,9 @@ namespace SafeExamBrowser.Client.Operations
 | 
			
		|||
 | 
			
		||||
		private void TerminateActivators()
 | 
			
		||||
		{
 | 
			
		||||
			terminationActivator.Stop();
 | 
			
		||||
 | 
			
		||||
			if (Context.Settings.ActionCenter.EnableActionCenter)
 | 
			
		||||
			foreach (var activator in Context.Activators)
 | 
			
		||||
			{
 | 
			
		||||
				foreach (var activator in Context.Activators)
 | 
			
		||||
				{
 | 
			
		||||
					activator.Stop();
 | 
			
		||||
				}
 | 
			
		||||
				activator.Stop();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -216,6 +216,10 @@
 | 
			
		|||
      <Project>{89bc24dd-ff31-496e-9816-a160b686a3d4}</Project>
 | 
			
		||||
      <Name>SafeExamBrowser.UserInterface.Mobile</Name>
 | 
			
		||||
    </ProjectReference>
 | 
			
		||||
    <ProjectReference Include="..\SafeExamBrowser.UserInterface.Shared\SafeExamBrowser.UserInterface.Shared.csproj">
 | 
			
		||||
      <Project>{38525928-87ba-4f8c-8010-4eb97bfaae13}</Project>
 | 
			
		||||
      <Name>SafeExamBrowser.UserInterface.Shared</Name>
 | 
			
		||||
    </ProjectReference>
 | 
			
		||||
    <ProjectReference Include="..\SafeExamBrowser.WindowsApi.Contracts\SafeExamBrowser.WindowsApi.Contracts.csproj">
 | 
			
		||||
      <Project>{7016f080-9aa5-41b2-a225-385ad877c171}</Project>
 | 
			
		||||
      <Name>SafeExamBrowser.WindowsApi.Contracts</Name>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ namespace SafeExamBrowser.Monitoring.Mouse
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private bool MouseHookCallback(MouseButton button, MouseButtonState state)
 | 
			
		||||
		private bool MouseHookCallback(MouseButton button, MouseButtonState state, MouseInformation info)
 | 
			
		||||
		{
 | 
			
		||||
			var block = false;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -71,10 +71,14 @@
 | 
			
		|||
    <Compile Include="Shell\Events\QuitButtonClickedEventHandler.cs" />
 | 
			
		||||
    <Compile Include="Shell\IActionCenter.cs" />
 | 
			
		||||
    <Compile Include="Shell\IActionCenterActivator.cs" />
 | 
			
		||||
    <Compile Include="Shell\IActivator.cs" />
 | 
			
		||||
    <Compile Include="Shell\IApplicationControl.cs" />
 | 
			
		||||
    <Compile Include="Shell\INotificationControl.cs" />
 | 
			
		||||
    <Compile Include="Shell\ISystemControl.cs" />
 | 
			
		||||
    <Compile Include="Shell\ITaskbar.cs" />
 | 
			
		||||
    <Compile Include="Shell\ITaskView.cs" />
 | 
			
		||||
    <Compile Include="Shell\ITaskViewActivator.cs" />
 | 
			
		||||
    <Compile Include="Shell\ITerminationActivator.cs" />
 | 
			
		||||
    <Compile Include="Shell\Location.cs" />
 | 
			
		||||
    <Compile Include="Windows\Data\LockScreenOption.cs" />
 | 
			
		||||
    <Compile Include="Windows\Data\LockScreenResult.cs" />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
 | 
			
		|||
namespace SafeExamBrowser.UserInterface.Contracts.Shell
 | 
			
		||||
{
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// The action center is a user interface element via which the user can access and control various aspects of the application.
 | 
			
		||||
	/// The action center is a user interface element via which the user can access and control various aspects of SEB.
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public interface IActionCenter
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,9 +11,9 @@ using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
 | 
			
		|||
namespace SafeExamBrowser.UserInterface.Contracts.Shell
 | 
			
		||||
{
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// A module which can be used to control the visibility of the <see cref="IActionCenter"/>.
 | 
			
		||||
	/// A module which can be used to control the <see cref="IActionCenter"/>.
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public interface IActionCenterActivator
 | 
			
		||||
	public interface IActionCenterActivator : IActivator
 | 
			
		||||
	{
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Fired when the action center should be made visible.
 | 
			
		||||
| 
						 | 
				
			
			@ -29,25 +29,5 @@ namespace SafeExamBrowser.UserInterface.Contracts.Shell
 | 
			
		|||
		/// Fired when the action center visibility should be toggled.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		event ActivatorEventHandler Toggled;
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Temporarily stops processing all user input.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		void Pause();
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Resumes processing user input.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		void Resume();
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Starts monitoring user input events.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		void Start();
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Stops monitoring user input events.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		void Stop();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,20 +6,13 @@
 | 
			
		|||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts.Events;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.WindowsApi.Contracts
 | 
			
		||||
namespace SafeExamBrowser.UserInterface.Contracts.Shell
 | 
			
		||||
{
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// A module which observes user input and indicates when the user would like to terminate the application.
 | 
			
		||||
	/// Defines an activator for a shell component.
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public interface ITerminationActivator
 | 
			
		||||
	public interface IActivator
 | 
			
		||||
	{
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Fired when a termination request has been detected.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		event TerminationActivatorEventHandler Activated;
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Temporarily stops processing all user input.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
							
								
								
									
										28
									
								
								SafeExamBrowser.UserInterface.Contracts/Shell/ITaskView.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								SafeExamBrowser.UserInterface.Contracts/Shell/ITaskView.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 SafeExamBrowser.Applications.Contracts;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.UserInterface.Contracts.Shell
 | 
			
		||||
{
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// The task view provides an overview of all currently running application instances.
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public interface ITaskView
 | 
			
		||||
	{
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Adds the given application to the task view.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		void Add(IApplication application);
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Registers the specified activator for the task view.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		void Register(ITaskViewActivator activator);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 SafeExamBrowser.UserInterface.Contracts.Shell.Events;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.UserInterface.Contracts.Shell
 | 
			
		||||
{
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// A module which can be used to control the <see cref="ITaskView"/>.
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public interface ITaskViewActivator : IActivator
 | 
			
		||||
	{
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Fired when the next application instance should be selected.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		event ActivatorEventHandler Next;
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Fired when the previous application instance should be selected.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		event ActivatorEventHandler Previous;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 SafeExamBrowser.UserInterface.Contracts.Shell.Events;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.UserInterface.Contracts.Shell
 | 
			
		||||
{
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// A module which observes user input and indicates when the user would like to terminate SEB.
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public interface ITerminationActivator : IActivator
 | 
			
		||||
	{
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Fired when a termination request has been detected.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		event ActivatorEventHandler Activated;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -158,6 +158,9 @@
 | 
			
		|||
    <Compile Include="SplashScreen.xaml.cs">
 | 
			
		||||
      <DependentUpon>SplashScreen.xaml</DependentUpon>
 | 
			
		||||
    </Compile>
 | 
			
		||||
    <Compile Include="TaskView.xaml.cs">
 | 
			
		||||
      <DependentUpon>TaskView.xaml</DependentUpon>
 | 
			
		||||
    </Compile>
 | 
			
		||||
    <Compile Include="UserInterfaceFactory.cs" />
 | 
			
		||||
    <Compile Include="ViewModels\DateTimeViewModel.cs" />
 | 
			
		||||
    <Compile Include="ViewModels\LogViewModel.cs" />
 | 
			
		||||
| 
						 | 
				
			
			@ -315,6 +318,10 @@
 | 
			
		|||
      <SubType>Designer</SubType>
 | 
			
		||||
      <Generator>MSBuild:Compile</Generator>
 | 
			
		||||
    </Page>
 | 
			
		||||
    <Page Include="TaskView.xaml">
 | 
			
		||||
      <SubType>Designer</SubType>
 | 
			
		||||
      <Generator>MSBuild:Compile</Generator>
 | 
			
		||||
    </Page>
 | 
			
		||||
    <Page Include="Templates\ScrollViewers.xaml">
 | 
			
		||||
      <SubType>Designer</SubType>
 | 
			
		||||
      <Generator>MSBuild:Compile</Generator>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										12
									
								
								SafeExamBrowser.UserInterface.Desktop/TaskView.xaml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								SafeExamBrowser.UserInterface.Desktop/TaskView.xaml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
<Window x:Class="SafeExamBrowser.UserInterface.Desktop.TaskView"
 | 
			
		||||
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 | 
			
		||||
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 | 
			
		||||
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 | 
			
		||||
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 | 
			
		||||
        xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop"
 | 
			
		||||
        mc:Ignorable="d" AllowsTransparency="True" Background="#74000000" BorderBrush="DodgerBlue" BorderThickness="1" Title="TaskView"
 | 
			
		||||
        Height="450" Width="800" WindowStartupLocation="CenterScreen" WindowStyle="None">
 | 
			
		||||
    <Grid>
 | 
			
		||||
        
 | 
			
		||||
    </Grid>
 | 
			
		||||
</Window>
 | 
			
		||||
							
								
								
									
										32
									
								
								SafeExamBrowser.UserInterface.Desktop/TaskView.xaml.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								SafeExamBrowser.UserInterface.Desktop/TaskView.xaml.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 System.Windows;
 | 
			
		||||
using SafeExamBrowser.Applications.Contracts;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.UserInterface.Desktop
 | 
			
		||||
{
 | 
			
		||||
	public partial class TaskView : Window, ITaskView
 | 
			
		||||
	{
 | 
			
		||||
		public TaskView()
 | 
			
		||||
		{
 | 
			
		||||
			InitializeComponent();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Add(IApplication application)
 | 
			
		||||
		{
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Register(ITaskViewActivator activator)
 | 
			
		||||
		{
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,72 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 System.Windows.Input;
 | 
			
		||||
using SafeExamBrowser.Logging.Contracts;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts.Events;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.UserInterface.Shared.Activators
 | 
			
		||||
{
 | 
			
		||||
	public class ActionCenterKeyboardActivator : KeyboardActivator, IActionCenterActivator
 | 
			
		||||
	{
 | 
			
		||||
		private bool A, LeftWindows;
 | 
			
		||||
		private ILogger logger;
 | 
			
		||||
 | 
			
		||||
		public event ActivatorEventHandler Activated { add { } remove { } }
 | 
			
		||||
		public event ActivatorEventHandler Deactivated { add { } remove { } }
 | 
			
		||||
		public event ActivatorEventHandler Toggled;
 | 
			
		||||
 | 
			
		||||
		public ActionCenterKeyboardActivator(ILogger logger, INativeMethods nativeMethods) : base(nativeMethods)
 | 
			
		||||
		{
 | 
			
		||||
			this.logger = logger;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Pause()
 | 
			
		||||
		{
 | 
			
		||||
			Paused = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Resume()
 | 
			
		||||
		{
 | 
			
		||||
			A = false;
 | 
			
		||||
			LeftWindows = false;
 | 
			
		||||
			Paused = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected override bool Process(Key key, KeyModifier modifier, KeyState state)
 | 
			
		||||
		{
 | 
			
		||||
			var changed = false;
 | 
			
		||||
			var pressed = state == KeyState.Pressed;
 | 
			
		||||
 | 
			
		||||
			switch (key)
 | 
			
		||||
			{
 | 
			
		||||
				case Key.A:
 | 
			
		||||
					changed = A != pressed;
 | 
			
		||||
					A = pressed;
 | 
			
		||||
					break;
 | 
			
		||||
				case Key.LWin:
 | 
			
		||||
					changed = LeftWindows != pressed;
 | 
			
		||||
					LeftWindows = pressed;
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (A && LeftWindows && changed)
 | 
			
		||||
			{
 | 
			
		||||
				logger.Debug("Detected toggle sequence for action center.");
 | 
			
		||||
				Toggled?.Invoke();
 | 
			
		||||
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,78 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 System.Threading.Tasks;
 | 
			
		||||
using SafeExamBrowser.Logging.Contracts;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts.Events;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.UserInterface.Shared.Activators
 | 
			
		||||
{
 | 
			
		||||
	public class ActionCenterTouchActivator : TouchActivator, IActionCenterActivator
 | 
			
		||||
	{
 | 
			
		||||
		private bool isDown;
 | 
			
		||||
		private ILogger logger;
 | 
			
		||||
		private INativeMethods nativeMethods;
 | 
			
		||||
 | 
			
		||||
		public event ActivatorEventHandler Activated;
 | 
			
		||||
		public event ActivatorEventHandler Deactivated { add { } remove { } }
 | 
			
		||||
		public event ActivatorEventHandler Toggled { add { } remove { } }
 | 
			
		||||
 | 
			
		||||
		public ActionCenterTouchActivator(ILogger logger, INativeMethods nativeMethods) : base(nativeMethods)
 | 
			
		||||
		{
 | 
			
		||||
			this.logger = logger;
 | 
			
		||||
			this.nativeMethods = nativeMethods;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Pause()
 | 
			
		||||
		{
 | 
			
		||||
			Paused = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Resume()
 | 
			
		||||
		{
 | 
			
		||||
			isDown = false;
 | 
			
		||||
			Paused = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected override bool Process(MouseButton button, MouseButtonState state, MouseInformation info)
 | 
			
		||||
		{
 | 
			
		||||
			var inActivationArea = 0 < info.X && info.X < 100;
 | 
			
		||||
 | 
			
		||||
			if (button == MouseButton.Left)
 | 
			
		||||
			{
 | 
			
		||||
				if (state == MouseButtonState.Released)
 | 
			
		||||
				{
 | 
			
		||||
					isDown = false;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (state == MouseButtonState.Pressed && inActivationArea)
 | 
			
		||||
				{
 | 
			
		||||
					isDown = true;
 | 
			
		||||
					Task.Delay(100).ContinueWith(_ => CheckPosition());
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void CheckPosition()
 | 
			
		||||
		{
 | 
			
		||||
			var (x, y) = nativeMethods.GetCursorPosition();
 | 
			
		||||
			var hasMoved = x > 200;
 | 
			
		||||
 | 
			
		||||
			if (isDown && hasMoved)
 | 
			
		||||
			{
 | 
			
		||||
				logger.Debug("Detected activation gesture for action center.");
 | 
			
		||||
				Activated?.Invoke();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 System;
 | 
			
		||||
using System.Windows.Input;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts.Events;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.UserInterface.Shared.Activators
 | 
			
		||||
{
 | 
			
		||||
	public abstract class KeyboardActivator
 | 
			
		||||
	{
 | 
			
		||||
		private INativeMethods nativeMethods;
 | 
			
		||||
		private Guid? hookId;
 | 
			
		||||
 | 
			
		||||
		protected bool Paused { get; set; }
 | 
			
		||||
 | 
			
		||||
		protected KeyboardActivator(INativeMethods nativeMethods)
 | 
			
		||||
		{
 | 
			
		||||
			this.nativeMethods = nativeMethods;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected abstract bool Process(Key key, KeyModifier modifier, KeyState state);
 | 
			
		||||
 | 
			
		||||
		public void Start()
 | 
			
		||||
		{
 | 
			
		||||
			hookId = nativeMethods.RegisterKeyboardHook(KeyboardHookCallback);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Stop()
 | 
			
		||||
		{
 | 
			
		||||
			if (hookId.HasValue)
 | 
			
		||||
			{
 | 
			
		||||
				nativeMethods.DeregisterKeyboardHook(hookId.Value);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private bool KeyboardHookCallback(int keyCode, KeyModifier modifier, KeyState state)
 | 
			
		||||
		{
 | 
			
		||||
			if (!Paused)
 | 
			
		||||
			{
 | 
			
		||||
				return Process(KeyInterop.KeyFromVirtualKey(keyCode), modifier, state);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 System.Windows.Input;
 | 
			
		||||
using SafeExamBrowser.Logging.Contracts;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts.Events;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.UserInterface.Shared.Activators
 | 
			
		||||
{
 | 
			
		||||
	public class TaskViewKeyboardActivator : KeyboardActivator, ITaskViewActivator
 | 
			
		||||
	{
 | 
			
		||||
		private ILogger logger;
 | 
			
		||||
 | 
			
		||||
		public event ActivatorEventHandler Next;
 | 
			
		||||
		public event ActivatorEventHandler Previous;
 | 
			
		||||
 | 
			
		||||
		public TaskViewKeyboardActivator(ILogger logger, INativeMethods nativeMethods) : base(nativeMethods)
 | 
			
		||||
		{
 | 
			
		||||
			this.logger = logger;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Pause()
 | 
			
		||||
		{
 | 
			
		||||
			Paused = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Resume()
 | 
			
		||||
		{
 | 
			
		||||
			Paused = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected override bool Process(Key key, KeyModifier modifier, KeyState state)
 | 
			
		||||
		{
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,75 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 System.Windows.Input;
 | 
			
		||||
using SafeExamBrowser.Logging.Contracts;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts.Events;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.UserInterface.Shared.Activators
 | 
			
		||||
{
 | 
			
		||||
	public class TerminationActivator : KeyboardActivator, ITerminationActivator
 | 
			
		||||
	{
 | 
			
		||||
		private bool Q, LeftCtrl, RightCtrl;
 | 
			
		||||
		private ILogger logger;
 | 
			
		||||
 | 
			
		||||
		public event ActivatorEventHandler Activated;
 | 
			
		||||
 | 
			
		||||
		public TerminationActivator(ILogger logger, INativeMethods nativeMethods) : base(nativeMethods)
 | 
			
		||||
		{
 | 
			
		||||
			this.logger = logger;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Pause()
 | 
			
		||||
		{
 | 
			
		||||
			Paused = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Resume()
 | 
			
		||||
		{
 | 
			
		||||
			Q = false;
 | 
			
		||||
			LeftCtrl = false;
 | 
			
		||||
			RightCtrl = false;
 | 
			
		||||
			Paused = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected override bool Process(Key key, KeyModifier modifier, KeyState state)
 | 
			
		||||
		{
 | 
			
		||||
			var changed = false;
 | 
			
		||||
			var pressed = state == KeyState.Pressed;
 | 
			
		||||
 | 
			
		||||
			switch (key)
 | 
			
		||||
			{
 | 
			
		||||
				case Key.Q:
 | 
			
		||||
					changed = Q != pressed;
 | 
			
		||||
					Q = pressed;
 | 
			
		||||
					break;
 | 
			
		||||
				case Key.LeftCtrl:
 | 
			
		||||
					changed = LeftCtrl != pressed;
 | 
			
		||||
					LeftCtrl = pressed;
 | 
			
		||||
					break;
 | 
			
		||||
				case Key.RightCtrl:
 | 
			
		||||
					changed = RightCtrl != pressed;
 | 
			
		||||
					RightCtrl = pressed;
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (Q && (LeftCtrl || RightCtrl) && changed)
 | 
			
		||||
			{
 | 
			
		||||
				logger.Debug("Detected termination sequence.");
 | 
			
		||||
				Activated?.Invoke();
 | 
			
		||||
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 System;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts.Events;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.UserInterface.Shared.Activators
 | 
			
		||||
{
 | 
			
		||||
	public abstract class TouchActivator
 | 
			
		||||
	{
 | 
			
		||||
		private INativeMethods nativeMethods;
 | 
			
		||||
		private Guid? hookId;
 | 
			
		||||
 | 
			
		||||
		protected bool Paused { get; set; }
 | 
			
		||||
 | 
			
		||||
		protected TouchActivator(INativeMethods nativeMethods)
 | 
			
		||||
		{
 | 
			
		||||
			this.nativeMethods = nativeMethods;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected abstract bool Process(MouseButton button, MouseButtonState state, MouseInformation info);
 | 
			
		||||
 | 
			
		||||
		public void Start()
 | 
			
		||||
		{
 | 
			
		||||
			hookId = nativeMethods.RegisterMouseHook(MouseHookCallback);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Stop()
 | 
			
		||||
		{
 | 
			
		||||
			if (hookId.HasValue)
 | 
			
		||||
			{
 | 
			
		||||
				nativeMethods.DeregisterMouseHook(hookId.Value);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private bool MouseHookCallback(MouseButton button, MouseButtonState state, MouseInformation info)
 | 
			
		||||
		{
 | 
			
		||||
			if (!Paused && info.IsTouch)
 | 
			
		||||
			{
 | 
			
		||||
				return Process(button, state, info);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +63,12 @@
 | 
			
		|||
    <Reference Include="PresentationFramework" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Include="Activators\ActionCenterKeyboardActivator.cs" />
 | 
			
		||||
    <Compile Include="Activators\ActionCenterTouchActivator.cs" />
 | 
			
		||||
    <Compile Include="Activators\KeyboardActivator.cs" />
 | 
			
		||||
    <Compile Include="Activators\TaskViewKeyboardActivator.cs" />
 | 
			
		||||
    <Compile Include="Activators\TerminationActivator.cs" />
 | 
			
		||||
    <Compile Include="Activators\TouchActivator.cs" />
 | 
			
		||||
    <Compile Include="Properties\AssemblyInfo.cs">
 | 
			
		||||
      <SubType>Code</SubType>
 | 
			
		||||
    </Compile>
 | 
			
		||||
| 
						 | 
				
			
			@ -75,6 +81,18 @@
 | 
			
		|||
      <Project>{fe0e1224-b447-4b14-81e7-ed7d84822aa0}</Project>
 | 
			
		||||
      <Name>SafeExamBrowser.Core.Contracts</Name>
 | 
			
		||||
    </ProjectReference>
 | 
			
		||||
    <ProjectReference Include="..\SafeExamBrowser.Logging.Contracts\SafeExamBrowser.Logging.Contracts.csproj">
 | 
			
		||||
      <Project>{64ea30fb-11d4-436a-9c2b-88566285363e}</Project>
 | 
			
		||||
      <Name>SafeExamBrowser.Logging.Contracts</Name>
 | 
			
		||||
    </ProjectReference>
 | 
			
		||||
    <ProjectReference Include="..\SafeExamBrowser.UserInterface.Contracts\SafeExamBrowser.UserInterface.Contracts.csproj">
 | 
			
		||||
      <Project>{c7889e97-6ff6-4a58-b7cb-521ed276b316}</Project>
 | 
			
		||||
      <Name>SafeExamBrowser.UserInterface.Contracts</Name>
 | 
			
		||||
    </ProjectReference>
 | 
			
		||||
    <ProjectReference Include="..\SafeExamBrowser.WindowsApi.Contracts\SafeExamBrowser.WindowsApi.Contracts.csproj">
 | 
			
		||||
      <Project>{7016f080-9aa5-41b2-a225-385ad877c171}</Project>
 | 
			
		||||
      <Name>SafeExamBrowser.WindowsApi.Contracts</Name>
 | 
			
		||||
    </ProjectReference>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 | 
			
		||||
</Project>
 | 
			
		||||
| 
						 | 
				
			
			@ -9,7 +9,7 @@
 | 
			
		|||
namespace SafeExamBrowser.WindowsApi.Contracts.Events
 | 
			
		||||
{
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// The mouse button states which can be detected a mouse hook.
 | 
			
		||||
	/// The mouse button states which can be detected by a mouse hook.
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public enum MouseButtonState
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,5 +11,5 @@ namespace SafeExamBrowser.WindowsApi.Contracts.Events
 | 
			
		|||
	/// <summary>
 | 
			
		||||
	/// The callback for a mouse hook. Return <c>true</c> to consume (i.e. block) the user input, otherwise <c>false</c>.
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public delegate bool MouseHookCallback(MouseButton button, MouseButtonState state);
 | 
			
		||||
	public delegate bool MouseHookCallback(MouseButton button, MouseButtonState state, MouseInformation info);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.WindowsApi.Contracts.Events
 | 
			
		||||
{
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// The mouse information which can be detected by a mouse hook.
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public class MouseInformation
 | 
			
		||||
	{
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Indicates whether the mouse event originates from a touch input by the user.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public bool IsTouch { get; set; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// The X coordinate of the current mouse position.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public int X { get; set; }
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// The Y coordinate of the current mouse position.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		public int Y { get; set; }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -9,7 +9,7 @@
 | 
			
		|||
namespace SafeExamBrowser.WindowsApi.Contracts
 | 
			
		||||
{
 | 
			
		||||
	/// <summary>
 | 
			
		||||
	/// Defines rectangular bounds, e.g. used for display-related operations (see <see cref="Monitoring.IDisplayMonitor"/>).
 | 
			
		||||
	/// Defines rectangular bounds, e.g. used for display-related operations.
 | 
			
		||||
	/// </summary>
 | 
			
		||||
	public interface IBounds
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,6 +49,11 @@ namespace SafeExamBrowser.WindowsApi.Contracts
 | 
			
		|||
		/// </exception>
 | 
			
		||||
		void EmptyClipboard();
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Retrieves the current position of the mouse cursor.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		(int x, int y) GetCursorPosition();
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Retrieves a collection of handles to all currently open (i.e. visible) windows.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,6 +60,7 @@
 | 
			
		|||
    <Compile Include="Events\MouseButton.cs" />
 | 
			
		||||
    <Compile Include="Events\MouseButtonState.cs" />
 | 
			
		||||
    <Compile Include="Events\MouseHookCallback.cs" />
 | 
			
		||||
    <Compile Include="Events\MouseInformation.cs" />
 | 
			
		||||
    <Compile Include="Events\ProcessTerminatedEventHandler.cs" />
 | 
			
		||||
    <Compile Include="Events\SystemEventCallback.cs" />
 | 
			
		||||
    <Compile Include="Events\TerminationActivatorEventHandler.cs" />
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +71,6 @@
 | 
			
		|||
    <Compile Include="INativeMethods.cs" />
 | 
			
		||||
    <Compile Include="IProcess.cs" />
 | 
			
		||||
    <Compile Include="IProcessFactory.cs" />
 | 
			
		||||
    <Compile Include="ITerminationActivator.cs" />
 | 
			
		||||
    <Compile Include="Properties\AssemblyInfo.cs" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,8 +54,9 @@ namespace SafeExamBrowser.WindowsApi.Hooks
 | 
			
		|||
				var mouseData = (MSLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
 | 
			
		||||
				var button = GetButton(wParam.ToInt32());
 | 
			
		||||
				var state = GetState(wParam.ToInt32());
 | 
			
		||||
				var info = GetInfo(mouseData);
 | 
			
		||||
 | 
			
		||||
				if (callback(button, state))
 | 
			
		||||
				if (callback(button, state, info))
 | 
			
		||||
				{
 | 
			
		||||
					return (IntPtr) 1;
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -91,6 +92,18 @@ namespace SafeExamBrowser.WindowsApi.Hooks
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private MouseInformation GetInfo(MSLLHOOKSTRUCT mouseData)
 | 
			
		||||
		{
 | 
			
		||||
			var info = new MouseInformation();
 | 
			
		||||
			var extraInfo = mouseData.DwExtraInfo.ToUInt32();
 | 
			
		||||
 | 
			
		||||
			info.IsTouch = (extraInfo & Constant.MOUSEEVENTF_MASK) == Constant.MOUSEEVENTF_FROMTOUCH;
 | 
			
		||||
			info.X = mouseData.Point.X;
 | 
			
		||||
			info.Y = mouseData.Point.Y;
 | 
			
		||||
 | 
			
		||||
			return info;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private MouseButtonState GetState(int wParam)
 | 
			
		||||
		{
 | 
			
		||||
			switch (wParam)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,122 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 System;
 | 
			
		||||
using System.Runtime.InteropServices;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using SafeExamBrowser.Logging.Contracts;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Constants;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Delegates;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Types;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.WindowsApi
 | 
			
		||||
{
 | 
			
		||||
	public class KeyboardActivator : IActionCenterActivator
 | 
			
		||||
	{
 | 
			
		||||
		private bool A, LeftWindows, paused;
 | 
			
		||||
		private IntPtr handle;
 | 
			
		||||
		private HookDelegate hookDelegate;
 | 
			
		||||
		private ILogger logger;
 | 
			
		||||
 | 
			
		||||
		public event ActivatorEventHandler Activated { add { } remove { } }
 | 
			
		||||
		public event ActivatorEventHandler Deactivated { add { } remove { } }
 | 
			
		||||
		public event ActivatorEventHandler Toggled;
 | 
			
		||||
 | 
			
		||||
		public KeyboardActivator(ILogger logger)
 | 
			
		||||
		{
 | 
			
		||||
			this.logger = logger;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Pause()
 | 
			
		||||
		{
 | 
			
		||||
			paused = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Resume()
 | 
			
		||||
		{
 | 
			
		||||
			A = false;
 | 
			
		||||
			LeftWindows = false;
 | 
			
		||||
			paused = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Start()
 | 
			
		||||
		{
 | 
			
		||||
			var hookReadyEvent = new AutoResetEvent(false);
 | 
			
		||||
			var hookThread = new Thread(() =>
 | 
			
		||||
			{
 | 
			
		||||
				var sleepEvent = new AutoResetEvent(false);
 | 
			
		||||
				var process = System.Diagnostics.Process.GetCurrentProcess();
 | 
			
		||||
				var module = process.MainModule;
 | 
			
		||||
				var moduleHandle = Kernel32.GetModuleHandle(module.ModuleName);
 | 
			
		||||
 | 
			
		||||
				// IMPORTANT:
 | 
			
		||||
				// Ensures that the hook delegate does not get garbage collected prematurely, as it will be passed to unmanaged code.
 | 
			
		||||
				// Not doing so will result in a <c>CallbackOnCollectedDelegate</c> error and subsequent application crash!
 | 
			
		||||
				hookDelegate = new HookDelegate(LowLevelKeyboardProc);
 | 
			
		||||
 | 
			
		||||
				handle = User32.SetWindowsHookEx(HookType.WH_KEYBOARD_LL, hookDelegate, moduleHandle, 0);
 | 
			
		||||
				hookReadyEvent.Set();
 | 
			
		||||
 | 
			
		||||
				while (true)
 | 
			
		||||
				{
 | 
			
		||||
					sleepEvent.WaitOne();
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			hookThread.SetApartmentState(ApartmentState.STA);
 | 
			
		||||
			hookThread.IsBackground = true;
 | 
			
		||||
			hookThread.Start();
 | 
			
		||||
 | 
			
		||||
			hookReadyEvent.WaitOne();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Stop()
 | 
			
		||||
		{
 | 
			
		||||
			User32.UnhookWindowsHookEx(handle);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
 | 
			
		||||
		{
 | 
			
		||||
			if (nCode >= 0 && !paused)
 | 
			
		||||
			{
 | 
			
		||||
				var changed = false;
 | 
			
		||||
				var keyData = (KBDLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
 | 
			
		||||
				var pressed = IsPressed(wParam.ToInt32());
 | 
			
		||||
 | 
			
		||||
				switch (keyData.KeyCode)
 | 
			
		||||
				{
 | 
			
		||||
					case (uint) VirtualKeyCode.A:
 | 
			
		||||
						changed = A != pressed;
 | 
			
		||||
						A = pressed;
 | 
			
		||||
						break;
 | 
			
		||||
					case (uint) VirtualKeyCode.LeftWindows:
 | 
			
		||||
						changed = LeftWindows != pressed;
 | 
			
		||||
						LeftWindows = pressed;
 | 
			
		||||
						break;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (A && LeftWindows && changed)
 | 
			
		||||
				{
 | 
			
		||||
					logger.Debug("Detected toggle sequence for action center.");
 | 
			
		||||
					Toggled?.Invoke();
 | 
			
		||||
 | 
			
		||||
					return (IntPtr) 1;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return User32.CallNextHookEx(handle, nCode, wParam, lParam);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private bool IsPressed(int wParam)
 | 
			
		||||
		{
 | 
			
		||||
			return wParam == Constant.WM_KEYDOWN || wParam == Constant.WM_SYSKEYDOWN;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -114,6 +114,15 @@ namespace SafeExamBrowser.WindowsApi
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public (int x, int y) GetCursorPosition()
 | 
			
		||||
		{
 | 
			
		||||
			var position = new POINT();
 | 
			
		||||
 | 
			
		||||
			User32.GetCursorPos(ref position);
 | 
			
		||||
 | 
			
		||||
			return (position.X, position.Y);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public IEnumerable<IntPtr> GetOpenWindows()
 | 
			
		||||
		{
 | 
			
		||||
			var windows = new List<IntPtr>();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,14 +66,11 @@
 | 
			
		|||
    <Compile Include="Desktop.cs" />
 | 
			
		||||
    <Compile Include="DesktopFactory.cs" />
 | 
			
		||||
    <Compile Include="ExplorerShell.cs" />
 | 
			
		||||
    <Compile Include="KeyboardActivator.cs" />
 | 
			
		||||
    <Compile Include="Hooks\MouseHook.cs" />
 | 
			
		||||
    <Compile Include="Hooks\SystemHook.cs" />
 | 
			
		||||
    <Compile Include="TerminationActivator.cs" />
 | 
			
		||||
    <Compile Include="Process.cs" />
 | 
			
		||||
    <Compile Include="ProcessFactory.cs" />
 | 
			
		||||
    <Compile Include="Constants\AccessMask.cs" />
 | 
			
		||||
    <Compile Include="TouchActivator.cs" />
 | 
			
		||||
    <Compile Include="Types\Bounds.cs" />
 | 
			
		||||
    <Compile Include="Types\EXECUTION_STATE.cs" />
 | 
			
		||||
    <Compile Include="Types\KBDLLHOOKSTRUCT.cs" />
 | 
			
		||||
| 
						 | 
				
			
			@ -100,10 +97,6 @@
 | 
			
		|||
      <Project>{64ea30fb-11d4-436a-9c2b-88566285363e}</Project>
 | 
			
		||||
      <Name>SafeExamBrowser.Logging.Contracts</Name>
 | 
			
		||||
    </ProjectReference>
 | 
			
		||||
    <ProjectReference Include="..\SafeExamBrowser.UserInterface.Contracts\SafeExamBrowser.UserInterface.Contracts.csproj">
 | 
			
		||||
      <Project>{c7889e97-6ff6-4a58-b7cb-521ed276b316}</Project>
 | 
			
		||||
      <Name>SafeExamBrowser.UserInterface.Contracts</Name>
 | 
			
		||||
    </ProjectReference>
 | 
			
		||||
    <ProjectReference Include="..\SafeExamBrowser.WindowsApi.Contracts\SafeExamBrowser.WindowsApi.Contracts.csproj">
 | 
			
		||||
      <Project>{7016f080-9aa5-41b2-a225-385ad877c171}</Project>
 | 
			
		||||
      <Name>SafeExamBrowser.WindowsApi.Contracts</Name>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,125 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 System;
 | 
			
		||||
using System.Runtime.InteropServices;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using SafeExamBrowser.Logging.Contracts;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Contracts.Events;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Constants;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Delegates;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Types;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.WindowsApi
 | 
			
		||||
{
 | 
			
		||||
	public class TerminationActivator : ITerminationActivator
 | 
			
		||||
	{
 | 
			
		||||
		private bool Q, LeftCtrl, RightCtrl, paused;
 | 
			
		||||
		private IntPtr handle;
 | 
			
		||||
		private HookDelegate hookDelegate;
 | 
			
		||||
		private ILogger logger;
 | 
			
		||||
 | 
			
		||||
		public event TerminationActivatorEventHandler Activated;
 | 
			
		||||
 | 
			
		||||
		public TerminationActivator(ILogger logger)
 | 
			
		||||
		{
 | 
			
		||||
			this.logger = logger;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Pause()
 | 
			
		||||
		{
 | 
			
		||||
			paused = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Resume()
 | 
			
		||||
		{
 | 
			
		||||
			Q = false;
 | 
			
		||||
			LeftCtrl = false;
 | 
			
		||||
			RightCtrl = false;
 | 
			
		||||
			paused = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Start()
 | 
			
		||||
		{
 | 
			
		||||
			var hookReadyEvent = new AutoResetEvent(false);
 | 
			
		||||
			var hookThread = new Thread(() =>
 | 
			
		||||
			{
 | 
			
		||||
				var sleepEvent = new AutoResetEvent(false);
 | 
			
		||||
				var process = System.Diagnostics.Process.GetCurrentProcess();
 | 
			
		||||
				var module = process.MainModule;
 | 
			
		||||
				var moduleHandle = Kernel32.GetModuleHandle(module.ModuleName);
 | 
			
		||||
 | 
			
		||||
				// IMPORTANT:
 | 
			
		||||
				// Ensures that the hook delegate does not get garbage collected prematurely, as it will be passed to unmanaged code.
 | 
			
		||||
				// Not doing so will result in a <c>CallbackOnCollectedDelegate</c> error and subsequent application crash!
 | 
			
		||||
				hookDelegate = new HookDelegate(LowLevelKeyboardProc);
 | 
			
		||||
 | 
			
		||||
				handle = User32.SetWindowsHookEx(HookType.WH_KEYBOARD_LL, hookDelegate, moduleHandle, 0);
 | 
			
		||||
				hookReadyEvent.Set();
 | 
			
		||||
 | 
			
		||||
				while (true)
 | 
			
		||||
				{
 | 
			
		||||
					sleepEvent.WaitOne();
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			hookThread.SetApartmentState(ApartmentState.STA);
 | 
			
		||||
			hookThread.IsBackground = true;
 | 
			
		||||
			hookThread.Start();
 | 
			
		||||
 | 
			
		||||
			hookReadyEvent.WaitOne();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Stop()
 | 
			
		||||
		{
 | 
			
		||||
			User32.UnhookWindowsHookEx(handle);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
 | 
			
		||||
		{
 | 
			
		||||
			if (nCode >= 0 && !paused)
 | 
			
		||||
			{
 | 
			
		||||
				var changed = false;
 | 
			
		||||
				var keyData = (KBDLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
 | 
			
		||||
				var pressed = IsPressed(wParam.ToInt32());
 | 
			
		||||
 | 
			
		||||
				switch (keyData.KeyCode)
 | 
			
		||||
				{
 | 
			
		||||
					case (uint) VirtualKeyCode.Q:
 | 
			
		||||
						changed = Q != pressed;
 | 
			
		||||
						Q = pressed;
 | 
			
		||||
						break;
 | 
			
		||||
					case (uint) VirtualKeyCode.LeftControl:
 | 
			
		||||
						changed = LeftCtrl != pressed;
 | 
			
		||||
						LeftCtrl = pressed;
 | 
			
		||||
						break;
 | 
			
		||||
					case (uint) VirtualKeyCode.RightControl:
 | 
			
		||||
						changed = RightCtrl != pressed;
 | 
			
		||||
						RightCtrl = pressed;
 | 
			
		||||
						break;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (Q && (LeftCtrl || RightCtrl) && changed)
 | 
			
		||||
				{
 | 
			
		||||
					logger.Debug("Detected termination sequence.");
 | 
			
		||||
					Activated?.Invoke();
 | 
			
		||||
 | 
			
		||||
					return (IntPtr) 1;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return User32.CallNextHookEx(handle, nCode, wParam, lParam);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private bool IsPressed(int wParam)
 | 
			
		||||
		{
 | 
			
		||||
			return wParam == Constant.WM_KEYDOWN || wParam == Constant.WM_SYSKEYDOWN;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,133 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 System;
 | 
			
		||||
using System.Runtime.InteropServices;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using SafeExamBrowser.Logging.Contracts;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
 | 
			
		||||
using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Constants;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Delegates;
 | 
			
		||||
using SafeExamBrowser.WindowsApi.Types;
 | 
			
		||||
 | 
			
		||||
namespace SafeExamBrowser.WindowsApi
 | 
			
		||||
{
 | 
			
		||||
	public class TouchActivator : IActionCenterActivator
 | 
			
		||||
	{
 | 
			
		||||
		private HookDelegate hookDelegate;
 | 
			
		||||
		private IntPtr handle;
 | 
			
		||||
		private bool isDown, paused;
 | 
			
		||||
		private ILogger logger;
 | 
			
		||||
 | 
			
		||||
		public event ActivatorEventHandler Activated;
 | 
			
		||||
		public event ActivatorEventHandler Deactivated { add { } remove { } }
 | 
			
		||||
		public event ActivatorEventHandler Toggled { add { } remove { } }
 | 
			
		||||
 | 
			
		||||
		public TouchActivator(ILogger logger)
 | 
			
		||||
		{
 | 
			
		||||
			this.logger = logger;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Pause()
 | 
			
		||||
		{
 | 
			
		||||
			paused = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Resume()
 | 
			
		||||
		{
 | 
			
		||||
			isDown = false;
 | 
			
		||||
			paused = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Start()
 | 
			
		||||
		{
 | 
			
		||||
			var hookReadyEvent = new AutoResetEvent(false);
 | 
			
		||||
			var hookThread = new Thread(() =>
 | 
			
		||||
			{
 | 
			
		||||
				var sleepEvent = new AutoResetEvent(false);
 | 
			
		||||
				var process = System.Diagnostics.Process.GetCurrentProcess();
 | 
			
		||||
				var module = process.MainModule;
 | 
			
		||||
				var moduleHandle = Kernel32.GetModuleHandle(module.ModuleName);
 | 
			
		||||
 | 
			
		||||
				// IMPORTANT:
 | 
			
		||||
				// Ensures that the hook delegate does not get garbage collected prematurely, as it will be passed to unmanaged code.
 | 
			
		||||
				// Not doing so will result in a <c>CallbackOnCollectedDelegate</c> error and subsequent application crash!
 | 
			
		||||
				hookDelegate = new HookDelegate(LowLevelMouseProc);
 | 
			
		||||
 | 
			
		||||
				handle = User32.SetWindowsHookEx(HookType.WH_MOUSE_LL, hookDelegate, moduleHandle, 0);
 | 
			
		||||
				hookReadyEvent.Set();
 | 
			
		||||
 | 
			
		||||
				while (true)
 | 
			
		||||
				{
 | 
			
		||||
					sleepEvent.WaitOne();
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			hookThread.SetApartmentState(ApartmentState.STA);
 | 
			
		||||
			hookThread.IsBackground = true;
 | 
			
		||||
			hookThread.Start();
 | 
			
		||||
 | 
			
		||||
			hookReadyEvent.WaitOne();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Stop()
 | 
			
		||||
		{
 | 
			
		||||
			User32.UnhookWindowsHookEx(handle);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam)
 | 
			
		||||
		{
 | 
			
		||||
			if (nCode >= 0 && !paused && !Ignore(wParam.ToInt32()))
 | 
			
		||||
			{
 | 
			
		||||
				var message = wParam.ToInt32();
 | 
			
		||||
				var mouseData = (MSLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
 | 
			
		||||
				var position = $"{mouseData.Point.X}/{mouseData.Point.Y}";
 | 
			
		||||
				var extraInfo = mouseData.DwExtraInfo.ToUInt32();
 | 
			
		||||
				var isTouch = (extraInfo & Constant.MOUSEEVENTF_MASK) == Constant.MOUSEEVENTF_FROMTOUCH;
 | 
			
		||||
				var inActivationArea = 0 < mouseData.Point.X && mouseData.Point.X < 100;
 | 
			
		||||
 | 
			
		||||
				if (isTouch)
 | 
			
		||||
				{
 | 
			
		||||
					if (message == Constant.WM_LBUTTONUP)
 | 
			
		||||
					{
 | 
			
		||||
						isDown = false;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if (message == Constant.WM_LBUTTONDOWN && inActivationArea)
 | 
			
		||||
					{
 | 
			
		||||
						isDown = true;
 | 
			
		||||
						Task.Delay(100).ContinueWith(_ => CheckPosition());
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return User32.CallNextHookEx(handle, nCode, wParam, lParam);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void CheckPosition()
 | 
			
		||||
		{
 | 
			
		||||
			var position = new POINT();
 | 
			
		||||
			User32.GetCursorPos(ref position);
 | 
			
		||||
			var hasMoved = position.X > 200;
 | 
			
		||||
 | 
			
		||||
			if (isDown && hasMoved)
 | 
			
		||||
			{
 | 
			
		||||
				logger.Debug("Detected activation gesture for action center.");
 | 
			
		||||
				Activated?.Invoke();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private bool Ignore(int wParam)
 | 
			
		||||
		{
 | 
			
		||||
			// For performance reasons, ignore mouse movement and wheel rotation...
 | 
			
		||||
			return wParam == Constant.WM_MOUSEMOVE || wParam == Constant.WM_MOUSEWHEEL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue