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,
|
runtimeProxy.Object,
|
||||||
shutdown.Object,
|
shutdown.Object,
|
||||||
taskbar.Object,
|
taskbar.Object,
|
||||||
terminationActivator.Object,
|
|
||||||
text.Object,
|
text.Object,
|
||||||
uiFactory.Object);
|
uiFactory.Object);
|
||||||
|
|
||||||
context.AppConfig = appConfig;
|
context.AppConfig = appConfig;
|
||||||
|
context.Activators.Add(terminationActivator.Object);
|
||||||
context.Browser = browserController.Object;
|
context.Browser = browserController.Object;
|
||||||
context.ClientHost = clientHost.Object;
|
context.ClientHost = clientHost.Object;
|
||||||
context.SessionId = sessionId;
|
context.SessionId = sessionId;
|
||||||
|
@ -423,13 +423,29 @@ namespace SafeExamBrowser.Client.UnitTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Shutdown_MustCloseActionCenterAndTaskbar()
|
public void Shutdown_MustCloseActionCenterAndTaskbarIfEnabled()
|
||||||
{
|
{
|
||||||
|
settings.ActionCenter.EnableActionCenter = true;
|
||||||
|
settings.Taskbar.EnableTaskbar = true;
|
||||||
|
|
||||||
sut.Terminate();
|
sut.Terminate();
|
||||||
|
|
||||||
actionCenter.Verify(a => a.Close(), Times.Once);
|
actionCenter.Verify(a => a.Close(), Times.Once);
|
||||||
taskbar.Verify(o => o.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]
|
[TestMethod]
|
||||||
public void Shutdown_MustShowErrorMessageOnCommunicationFailure()
|
public void Shutdown_MustShowErrorMessageOnCommunicationFailure()
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Moq;
|
using Moq;
|
||||||
using SafeExamBrowser.Client.Contracts;
|
using SafeExamBrowser.Client.Contracts;
|
||||||
|
@ -21,7 +20,6 @@ using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork;
|
using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork;
|
||||||
using SafeExamBrowser.UserInterface.Contracts;
|
using SafeExamBrowser.UserInterface.Contracts;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
|
||||||
|
|
||||||
namespace SafeExamBrowser.Client.UnitTests.Operations
|
namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
{
|
{
|
||||||
|
@ -32,7 +30,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
private Mock<IAudio> audio;
|
private Mock<IAudio> audio;
|
||||||
private ClientContext context;
|
private ClientContext context;
|
||||||
private Mock<ILogger> logger;
|
private Mock<ILogger> logger;
|
||||||
private Mock<ITerminationActivator> terminationActivator;
|
|
||||||
private Mock<INotificationInfo> aboutInfo;
|
private Mock<INotificationInfo> aboutInfo;
|
||||||
private Mock<INotificationController> aboutController;
|
private Mock<INotificationController> aboutController;
|
||||||
private Mock<IKeyboard> keyboard;
|
private Mock<IKeyboard> keyboard;
|
||||||
|
@ -41,6 +38,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
private Mock<IPowerSupply> powerSupply;
|
private Mock<IPowerSupply> powerSupply;
|
||||||
private Mock<ISystemInfo> systemInfo;
|
private Mock<ISystemInfo> systemInfo;
|
||||||
private Mock<ITaskbar> taskbar;
|
private Mock<ITaskbar> taskbar;
|
||||||
|
private Mock<ITaskView> taskView;
|
||||||
private Mock<IText> text;
|
private Mock<IText> text;
|
||||||
private Mock<IUserInterfaceFactory> uiFactory;
|
private Mock<IUserInterfaceFactory> uiFactory;
|
||||||
private Mock<IWirelessAdapter> wirelessAdapter;
|
private Mock<IWirelessAdapter> wirelessAdapter;
|
||||||
|
@ -62,7 +60,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
powerSupply = new Mock<IPowerSupply>();
|
powerSupply = new Mock<IPowerSupply>();
|
||||||
systemInfo = new Mock<ISystemInfo>();
|
systemInfo = new Mock<ISystemInfo>();
|
||||||
taskbar = new Mock<ITaskbar>();
|
taskbar = new Mock<ITaskbar>();
|
||||||
terminationActivator = new Mock<ITerminationActivator>();
|
taskView = new Mock<ITaskView>();
|
||||||
text = new Mock<IText>();
|
text = new Mock<IText>();
|
||||||
uiFactory = new Mock<IUserInterfaceFactory>();
|
uiFactory = new Mock<IUserInterfaceFactory>();
|
||||||
wirelessAdapter = new Mock<IWirelessAdapter>();
|
wirelessAdapter = new Mock<IWirelessAdapter>();
|
||||||
|
@ -86,7 +84,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
powerSupply.Object,
|
powerSupply.Object,
|
||||||
systemInfo.Object,
|
systemInfo.Object,
|
||||||
taskbar.Object,
|
taskbar.Object,
|
||||||
terminationActivator.Object,
|
taskView.Object,
|
||||||
text.Object,
|
text.Object,
|
||||||
uiFactory.Object,
|
uiFactory.Object,
|
||||||
wirelessAdapter.Object);
|
wirelessAdapter.Object);
|
||||||
|
@ -95,28 +93,20 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Perform_MustInitializeActivators()
|
public void Perform_MustInitializeActivators()
|
||||||
{
|
{
|
||||||
var activatorMocks = new List<Mock<IActionCenterActivator>>
|
var actionCenterActivator = new Mock<IActionCenterActivator>();
|
||||||
{
|
var taskViewActivator = new Mock<ITaskViewActivator>();
|
||||||
new Mock<IActionCenterActivator>(),
|
var terminationActivator = new Mock<ITerminationActivator>();
|
||||||
new Mock<IActionCenterActivator>(),
|
|
||||||
new Mock<IActionCenterActivator>()
|
|
||||||
};
|
|
||||||
|
|
||||||
|
context.Activators.Add(actionCenterActivator.Object);
|
||||||
|
context.Activators.Add(taskViewActivator.Object);
|
||||||
|
context.Activators.Add(terminationActivator.Object);
|
||||||
context.Settings.ActionCenter.EnableActionCenter = true;
|
context.Settings.ActionCenter.EnableActionCenter = true;
|
||||||
|
|
||||||
foreach (var activator in activatorMocks)
|
|
||||||
{
|
|
||||||
context.Activators.Add(activator.Object);
|
|
||||||
}
|
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
|
||||||
terminationActivator.Verify(t => t.Start(), Times.Once);
|
actionCenterActivator.Verify(a => a.Start(), Times.Once);
|
||||||
|
taskViewActivator.Verify(a => a.Start(), Times.Once);
|
||||||
foreach (var activator in activatorMocks)
|
terminationActivator.Verify(a => a.Start(), Times.Once);
|
||||||
{
|
|
||||||
activator.Verify(a => a.Start(), Times.Once);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -183,6 +173,12 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
taskbar.Verify(t => t.AddNotificationControl(It.Is<INotificationControl>(i => i == logControl.Object)), Times.Never);
|
taskbar.Verify(t => t.AddNotificationControl(It.Is<INotificationControl>(i => i == logControl.Object)), Times.Never);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Perform_MustInitializeTaskView()
|
||||||
|
{
|
||||||
|
Assert.Fail("TODO");
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Perform_MustInitializeSystemComponents()
|
public void Perform_MustInitializeSystemComponents()
|
||||||
{
|
{
|
||||||
|
@ -242,9 +238,15 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Perform_MustNotInitializeActionCenterIfNotEnabled()
|
public void Perform_MustNotInitializeActionCenterIfNotEnabled()
|
||||||
{
|
{
|
||||||
|
var actionCenterActivator = new Mock<IActionCenterActivator>();
|
||||||
|
|
||||||
|
context.Activators.Add(actionCenterActivator.Object);
|
||||||
context.Settings.ActionCenter.EnableActionCenter = false;
|
context.Settings.ActionCenter.EnableActionCenter = false;
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
|
||||||
actionCenter.VerifyNoOtherCalls();
|
actionCenter.VerifyNoOtherCalls();
|
||||||
|
actionCenterActivator.VerifyNoOtherCalls();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -258,28 +260,20 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Revert_MustTerminateActivators()
|
public void Revert_MustTerminateActivators()
|
||||||
{
|
{
|
||||||
var activatorMocks = new List<Mock<IActionCenterActivator>>
|
var actionCenterActivator = new Mock<IActionCenterActivator>();
|
||||||
{
|
var taskViewActivator = new Mock<ITaskViewActivator>();
|
||||||
new Mock<IActionCenterActivator>(),
|
var terminationActivator = new Mock<ITerminationActivator>();
|
||||||
new Mock<IActionCenterActivator>(),
|
|
||||||
new Mock<IActionCenterActivator>()
|
|
||||||
};
|
|
||||||
|
|
||||||
|
context.Activators.Add(actionCenterActivator.Object);
|
||||||
|
context.Activators.Add(taskViewActivator.Object);
|
||||||
|
context.Activators.Add(terminationActivator.Object);
|
||||||
context.Settings.ActionCenter.EnableActionCenter = true;
|
context.Settings.ActionCenter.EnableActionCenter = true;
|
||||||
|
|
||||||
foreach (var activator in activatorMocks)
|
|
||||||
{
|
|
||||||
context.Activators.Add(activator.Object);
|
|
||||||
}
|
|
||||||
|
|
||||||
sut.Revert();
|
sut.Revert();
|
||||||
|
|
||||||
terminationActivator.Verify(t => t.Stop(), Times.Once);
|
actionCenterActivator.Verify(a => a.Stop(), Times.Once);
|
||||||
|
taskViewActivator.Verify(a => a.Stop(), Times.Once);
|
||||||
foreach (var activator in activatorMocks)
|
terminationActivator.Verify(a => a.Stop(), Times.Once);
|
||||||
{
|
|
||||||
activator.Verify(a => a.Stop(), Times.Once);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|
|
@ -23,9 +23,9 @@ namespace SafeExamBrowser.Client
|
||||||
internal class ClientContext
|
internal class ClientContext
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All activators for the action center.
|
/// All activators for shell components.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal IList<IActionCenterActivator> Activators { get; }
|
internal IList<IActivator> Activators { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All applications allowed for the current session.
|
/// All applications allowed for the current session.
|
||||||
|
@ -59,7 +59,7 @@ namespace SafeExamBrowser.Client
|
||||||
|
|
||||||
internal ClientContext()
|
internal ClientContext()
|
||||||
{
|
{
|
||||||
Activators = new List<IActionCenterActivator>();
|
Activators = new List<IActivator>();
|
||||||
Applications = new List<IApplication>();
|
Applications = new List<IApplication>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,6 @@ namespace SafeExamBrowser.Client
|
||||||
private Action shutdown;
|
private Action shutdown;
|
||||||
private ISplashScreen splashScreen;
|
private ISplashScreen splashScreen;
|
||||||
private ITaskbar taskbar;
|
private ITaskbar taskbar;
|
||||||
private ITerminationActivator terminationActivator;
|
|
||||||
private IText text;
|
private IText text;
|
||||||
private IUserInterfaceFactory uiFactory;
|
private IUserInterfaceFactory uiFactory;
|
||||||
|
|
||||||
|
@ -72,7 +71,6 @@ namespace SafeExamBrowser.Client
|
||||||
IRuntimeProxy runtime,
|
IRuntimeProxy runtime,
|
||||||
Action shutdown,
|
Action shutdown,
|
||||||
ITaskbar taskbar,
|
ITaskbar taskbar,
|
||||||
ITerminationActivator terminationActivator,
|
|
||||||
IText text,
|
IText text,
|
||||||
IUserInterfaceFactory uiFactory)
|
IUserInterfaceFactory uiFactory)
|
||||||
{
|
{
|
||||||
|
@ -88,7 +86,6 @@ namespace SafeExamBrowser.Client
|
||||||
this.runtime = runtime;
|
this.runtime = runtime;
|
||||||
this.shutdown = shutdown;
|
this.shutdown = shutdown;
|
||||||
this.taskbar = taskbar;
|
this.taskbar = taskbar;
|
||||||
this.terminationActivator = terminationActivator;
|
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.uiFactory = uiFactory;
|
this.uiFactory = uiFactory;
|
||||||
}
|
}
|
||||||
|
@ -140,9 +137,8 @@ namespace SafeExamBrowser.Client
|
||||||
logger.Info("Initiating shutdown procedure...");
|
logger.Info("Initiating shutdown procedure...");
|
||||||
|
|
||||||
splashScreen = uiFactory.CreateSplashScreen(context.AppConfig);
|
splashScreen = uiFactory.CreateSplashScreen(context.AppConfig);
|
||||||
actionCenter.Close();
|
|
||||||
taskbar.Close();
|
|
||||||
|
|
||||||
|
CloseShell();
|
||||||
DeregisterEvents();
|
DeregisterEvents();
|
||||||
|
|
||||||
var success = operations.TryRevert() == OperationResult.Success;
|
var success = operations.TryRevert() == OperationResult.Success;
|
||||||
|
@ -182,7 +178,11 @@ namespace SafeExamBrowser.Client
|
||||||
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
|
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
|
||||||
runtime.ConnectionLost += Runtime_ConnectionLost;
|
runtime.ConnectionLost += Runtime_ConnectionLost;
|
||||||
taskbar.QuitButtonClicked += Shell_QuitButtonClicked;
|
taskbar.QuitButtonClicked += Shell_QuitButtonClicked;
|
||||||
terminationActivator.Activated += TerminationActivator_Activated;
|
|
||||||
|
foreach (var activator in context.Activators.OfType<ITerminationActivator>())
|
||||||
|
{
|
||||||
|
activator.Activated += TerminationActivator_Activated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeregisterEvents()
|
private void DeregisterEvents()
|
||||||
|
@ -193,7 +193,6 @@ namespace SafeExamBrowser.Client
|
||||||
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
|
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
|
||||||
runtime.ConnectionLost -= Runtime_ConnectionLost;
|
runtime.ConnectionLost -= Runtime_ConnectionLost;
|
||||||
taskbar.QuitButtonClicked -= Shell_QuitButtonClicked;
|
taskbar.QuitButtonClicked -= Shell_QuitButtonClicked;
|
||||||
terminationActivator.Activated -= TerminationActivator_Activated;
|
|
||||||
|
|
||||||
if (Browser != null)
|
if (Browser != null)
|
||||||
{
|
{
|
||||||
|
@ -207,10 +206,33 @@ namespace SafeExamBrowser.Client
|
||||||
ClientHost.ReconfigurationDenied -= ClientHost_ReconfigurationDenied;
|
ClientHost.ReconfigurationDenied -= ClientHost_ReconfigurationDenied;
|
||||||
ClientHost.Shutdown -= ClientHost_Shutdown;
|
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()
|
private void ShowShell()
|
||||||
{
|
{
|
||||||
|
if (Settings.ActionCenter.EnableActionCenter)
|
||||||
|
{
|
||||||
|
actionCenter.Show();
|
||||||
|
}
|
||||||
|
|
||||||
if (Settings.Taskbar.EnableTaskbar)
|
if (Settings.Taskbar.EnableTaskbar)
|
||||||
{
|
{
|
||||||
taskbar.Show();
|
taskbar.Show();
|
||||||
|
@ -527,9 +549,6 @@ namespace SafeExamBrowser.Client
|
||||||
|
|
||||||
private void PauseActivators()
|
private void PauseActivators()
|
||||||
{
|
{
|
||||||
// TODO: Same for task view activator!
|
|
||||||
terminationActivator.Pause();
|
|
||||||
|
|
||||||
foreach (var activator in context.Activators)
|
foreach (var activator in context.Activators)
|
||||||
{
|
{
|
||||||
activator.Pause();
|
activator.Pause();
|
||||||
|
@ -538,9 +557,6 @@ namespace SafeExamBrowser.Client
|
||||||
|
|
||||||
private void ResumeActivators()
|
private void ResumeActivators()
|
||||||
{
|
{
|
||||||
// TODO: Same for task view activator!
|
|
||||||
terminationActivator.Resume();
|
|
||||||
|
|
||||||
foreach (var activator in context.Activators)
|
foreach (var activator in context.Activators)
|
||||||
{
|
{
|
||||||
activator.Resume();
|
activator.Resume();
|
||||||
|
|
|
@ -44,6 +44,7 @@ using SafeExamBrowser.SystemComponents.WirelessNetwork;
|
||||||
using SafeExamBrowser.UserInterface.Contracts;
|
using SafeExamBrowser.UserInterface.Contracts;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||||
|
using SafeExamBrowser.UserInterface.Shared.Activators;
|
||||||
using SafeExamBrowser.WindowsApi;
|
using SafeExamBrowser.WindowsApi;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
using SafeExamBrowser.WindowsApi.Contracts;
|
||||||
using Desktop = SafeExamBrowser.UserInterface.Desktop;
|
using Desktop = SafeExamBrowser.UserInterface.Desktop;
|
||||||
|
@ -70,7 +71,6 @@ namespace SafeExamBrowser.Client
|
||||||
private IRuntimeProxy runtimeProxy;
|
private IRuntimeProxy runtimeProxy;
|
||||||
private ISystemInfo systemInfo;
|
private ISystemInfo systemInfo;
|
||||||
private ITaskbar taskbar;
|
private ITaskbar taskbar;
|
||||||
private ITerminationActivator terminationActivator;
|
|
||||||
private IText text;
|
private IText text;
|
||||||
private ITextResource textResource;
|
private ITextResource textResource;
|
||||||
private IUserInterfaceFactory uiFactory;
|
private IUserInterfaceFactory uiFactory;
|
||||||
|
@ -94,7 +94,6 @@ namespace SafeExamBrowser.Client
|
||||||
uiFactory = BuildUserInterfaceFactory();
|
uiFactory = BuildUserInterfaceFactory();
|
||||||
runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), ModuleLogger(nameof(RuntimeProxy)), Interlocutor.Client);
|
runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), ModuleLogger(nameof(RuntimeProxy)), Interlocutor.Client);
|
||||||
taskbar = BuildTaskbar();
|
taskbar = BuildTaskbar();
|
||||||
terminationActivator = new TerminationActivator(ModuleLogger(nameof(TerminationActivator)));
|
|
||||||
|
|
||||||
var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory)));
|
var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory)));
|
||||||
var applicationFactory = new ApplicationFactory(ModuleLogger(nameof(ApplicationFactory)), processFactory);
|
var applicationFactory = new ApplicationFactory(ModuleLogger(nameof(ApplicationFactory)), processFactory);
|
||||||
|
@ -134,7 +133,6 @@ namespace SafeExamBrowser.Client
|
||||||
runtimeProxy,
|
runtimeProxy,
|
||||||
shutdown,
|
shutdown,
|
||||||
taskbar,
|
taskbar,
|
||||||
terminationActivator,
|
|
||||||
text,
|
text,
|
||||||
uiFactory);
|
uiFactory);
|
||||||
}
|
}
|
||||||
|
@ -244,6 +242,7 @@ namespace SafeExamBrowser.Client
|
||||||
var logInfo = new LogNotificationInfo(text);
|
var logInfo = new LogNotificationInfo(text);
|
||||||
var logController = new LogNotificationController(logger, uiFactory);
|
var logController = new LogNotificationController(logger, uiFactory);
|
||||||
var powerSupply = new PowerSupply(ModuleLogger(nameof(PowerSupply)));
|
var powerSupply = new PowerSupply(ModuleLogger(nameof(PowerSupply)));
|
||||||
|
var taskView = BuildTaskView();
|
||||||
var wirelessAdapter = new WirelessAdapter(ModuleLogger(nameof(WirelessAdapter)));
|
var wirelessAdapter = new WirelessAdapter(ModuleLogger(nameof(WirelessAdapter)));
|
||||||
var operation = new ShellOperation(
|
var operation = new ShellOperation(
|
||||||
actionCenter,
|
actionCenter,
|
||||||
|
@ -258,13 +257,15 @@ namespace SafeExamBrowser.Client
|
||||||
powerSupply,
|
powerSupply,
|
||||||
systemInfo,
|
systemInfo,
|
||||||
taskbar,
|
taskbar,
|
||||||
terminationActivator,
|
taskView,
|
||||||
text,
|
text,
|
||||||
uiFactory,
|
uiFactory,
|
||||||
wirelessAdapter);
|
wirelessAdapter);
|
||||||
|
|
||||||
context.Activators.Add(new KeyboardActivator(ModuleLogger(nameof(KeyboardActivator))));
|
context.Activators.Add(new ActionCenterKeyboardActivator(ModuleLogger(nameof(ActionCenterKeyboardActivator)), nativeMethods));
|
||||||
context.Activators.Add(new TouchActivator(ModuleLogger(nameof(TouchActivator))));
|
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;
|
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()
|
private IUserInterfaceFactory BuildUserInterfaceFactory()
|
||||||
{
|
{
|
||||||
switch (uiMode)
|
switch (uiMode)
|
||||||
|
|
|
@ -18,7 +18,6 @@ using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork;
|
using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork;
|
||||||
using SafeExamBrowser.UserInterface.Contracts;
|
using SafeExamBrowser.UserInterface.Contracts;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
|
||||||
|
|
||||||
namespace SafeExamBrowser.Client.Operations
|
namespace SafeExamBrowser.Client.Operations
|
||||||
{
|
{
|
||||||
|
@ -35,7 +34,7 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
private IPowerSupply powerSupply;
|
private IPowerSupply powerSupply;
|
||||||
private ISystemInfo systemInfo;
|
private ISystemInfo systemInfo;
|
||||||
private ITaskbar taskbar;
|
private ITaskbar taskbar;
|
||||||
private ITerminationActivator terminationActivator;
|
private ITaskView taskView;
|
||||||
private IText text;
|
private IText text;
|
||||||
private IUserInterfaceFactory uiFactory;
|
private IUserInterfaceFactory uiFactory;
|
||||||
private IWirelessAdapter wirelessAdapter;
|
private IWirelessAdapter wirelessAdapter;
|
||||||
|
@ -56,7 +55,7 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
IPowerSupply powerSupply,
|
IPowerSupply powerSupply,
|
||||||
ISystemInfo systemInfo,
|
ISystemInfo systemInfo,
|
||||||
ITaskbar taskbar,
|
ITaskbar taskbar,
|
||||||
ITerminationActivator terminationActivator,
|
ITaskView taskView,
|
||||||
IText text,
|
IText text,
|
||||||
IUserInterfaceFactory uiFactory,
|
IUserInterfaceFactory uiFactory,
|
||||||
IWirelessAdapter wirelessAdapter) : base(context)
|
IWirelessAdapter wirelessAdapter) : base(context)
|
||||||
|
@ -71,9 +70,9 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
this.logController = logController;
|
this.logController = logController;
|
||||||
this.powerSupply = powerSupply;
|
this.powerSupply = powerSupply;
|
||||||
this.systemInfo = systemInfo;
|
this.systemInfo = systemInfo;
|
||||||
this.terminationActivator = terminationActivator;
|
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.taskbar = taskbar;
|
this.taskbar = taskbar;
|
||||||
|
this.taskView = taskView;
|
||||||
this.uiFactory = uiFactory;
|
this.uiFactory = uiFactory;
|
||||||
this.wirelessAdapter = wirelessAdapter;
|
this.wirelessAdapter = wirelessAdapter;
|
||||||
}
|
}
|
||||||
|
@ -86,6 +85,7 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
InitializeSystemComponents();
|
InitializeSystemComponents();
|
||||||
InitializeActionCenter();
|
InitializeActionCenter();
|
||||||
InitializeTaskbar();
|
InitializeTaskbar();
|
||||||
|
InitializeTaskView();
|
||||||
InitializeActivators();
|
InitializeActivators();
|
||||||
|
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
|
@ -105,14 +105,23 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
|
|
||||||
private void InitializeActivators()
|
private void InitializeActivators()
|
||||||
{
|
{
|
||||||
terminationActivator.Start();
|
foreach (var activator in Context.Activators)
|
||||||
|
|
||||||
if (Context.Settings.ActionCenter.EnableActionCenter)
|
|
||||||
{
|
{
|
||||||
foreach (var activator in Context.Activators)
|
if (Context.Settings.ActionCenter.EnableActionCenter && activator is IActionCenterActivator actionCenterActivator)
|
||||||
{
|
{
|
||||||
actionCenter.Register(activator);
|
actionCenter.Register(actionCenterActivator);
|
||||||
activator.Start();
|
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)
|
private void InitializeApplicationsFor(Location location)
|
||||||
{
|
{
|
||||||
foreach (var application in Context.Applications)
|
foreach (var application in Context.Applications)
|
||||||
|
@ -295,14 +314,9 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
|
|
||||||
private void TerminateActivators()
|
private void TerminateActivators()
|
||||||
{
|
{
|
||||||
terminationActivator.Stop();
|
foreach (var activator in Context.Activators)
|
||||||
|
|
||||||
if (Context.Settings.ActionCenter.EnableActionCenter)
|
|
||||||
{
|
{
|
||||||
foreach (var activator in Context.Activators)
|
activator.Stop();
|
||||||
{
|
|
||||||
activator.Stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -216,6 +216,10 @@
|
||||||
<Project>{89bc24dd-ff31-496e-9816-a160b686a3d4}</Project>
|
<Project>{89bc24dd-ff31-496e-9816-a160b686a3d4}</Project>
|
||||||
<Name>SafeExamBrowser.UserInterface.Mobile</Name>
|
<Name>SafeExamBrowser.UserInterface.Mobile</Name>
|
||||||
</ProjectReference>
|
</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">
|
<ProjectReference Include="..\SafeExamBrowser.WindowsApi.Contracts\SafeExamBrowser.WindowsApi.Contracts.csproj">
|
||||||
<Project>{7016f080-9aa5-41b2-a225-385ad877c171}</Project>
|
<Project>{7016f080-9aa5-41b2-a225-385ad877c171}</Project>
|
||||||
<Name>SafeExamBrowser.WindowsApi.Contracts</Name>
|
<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;
|
var block = false;
|
||||||
|
|
||||||
|
|
|
@ -71,10 +71,14 @@
|
||||||
<Compile Include="Shell\Events\QuitButtonClickedEventHandler.cs" />
|
<Compile Include="Shell\Events\QuitButtonClickedEventHandler.cs" />
|
||||||
<Compile Include="Shell\IActionCenter.cs" />
|
<Compile Include="Shell\IActionCenter.cs" />
|
||||||
<Compile Include="Shell\IActionCenterActivator.cs" />
|
<Compile Include="Shell\IActionCenterActivator.cs" />
|
||||||
|
<Compile Include="Shell\IActivator.cs" />
|
||||||
<Compile Include="Shell\IApplicationControl.cs" />
|
<Compile Include="Shell\IApplicationControl.cs" />
|
||||||
<Compile Include="Shell\INotificationControl.cs" />
|
<Compile Include="Shell\INotificationControl.cs" />
|
||||||
<Compile Include="Shell\ISystemControl.cs" />
|
<Compile Include="Shell\ISystemControl.cs" />
|
||||||
<Compile Include="Shell\ITaskbar.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="Shell\Location.cs" />
|
||||||
<Compile Include="Windows\Data\LockScreenOption.cs" />
|
<Compile Include="Windows\Data\LockScreenOption.cs" />
|
||||||
<Compile Include="Windows\Data\LockScreenResult.cs" />
|
<Compile Include="Windows\Data\LockScreenResult.cs" />
|
||||||
|
|
|
@ -12,7 +12,7 @@ using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
|
||||||
namespace SafeExamBrowser.UserInterface.Contracts.Shell
|
namespace SafeExamBrowser.UserInterface.Contracts.Shell
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
public interface IActionCenter
|
public interface IActionCenter
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,9 +11,9 @@ using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
|
||||||
namespace SafeExamBrowser.UserInterface.Contracts.Shell
|
namespace SafeExamBrowser.UserInterface.Contracts.Shell
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
public interface IActionCenterActivator
|
public interface IActionCenterActivator : IActivator
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when the action center should be made visible.
|
/// 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.
|
/// Fired when the action center visibility should be toggled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
event ActivatorEventHandler Toggled;
|
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/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using SafeExamBrowser.WindowsApi.Contracts.Events;
|
namespace SafeExamBrowser.UserInterface.Contracts.Shell
|
||||||
|
|
||||||
namespace SafeExamBrowser.WindowsApi.Contracts
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
public interface ITerminationActivator
|
public interface IActivator
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Fired when a termination request has been detected.
|
|
||||||
/// </summary>
|
|
||||||
event TerminationActivatorEventHandler Activated;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Temporarily stops processing all user input.
|
/// Temporarily stops processing all user input.
|
||||||
/// </summary>
|
/// </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">
|
<Compile Include="SplashScreen.xaml.cs">
|
||||||
<DependentUpon>SplashScreen.xaml</DependentUpon>
|
<DependentUpon>SplashScreen.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="TaskView.xaml.cs">
|
||||||
|
<DependentUpon>TaskView.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="UserInterfaceFactory.cs" />
|
<Compile Include="UserInterfaceFactory.cs" />
|
||||||
<Compile Include="ViewModels\DateTimeViewModel.cs" />
|
<Compile Include="ViewModels\DateTimeViewModel.cs" />
|
||||||
<Compile Include="ViewModels\LogViewModel.cs" />
|
<Compile Include="ViewModels\LogViewModel.cs" />
|
||||||
|
@ -315,6 +318,10 @@
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="TaskView.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="Templates\ScrollViewers.xaml">
|
<Page Include="Templates\ScrollViewers.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<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" />
|
<Reference Include="PresentationFramework" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<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">
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -75,6 +81,18 @@
|
||||||
<Project>{fe0e1224-b447-4b14-81e7-ed7d84822aa0}</Project>
|
<Project>{fe0e1224-b447-4b14-81e7-ed7d84822aa0}</Project>
|
||||||
<Name>SafeExamBrowser.Core.Contracts</Name>
|
<Name>SafeExamBrowser.Core.Contracts</Name>
|
||||||
</ProjectReference>
|
</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>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
|
@ -9,7 +9,7 @@
|
||||||
namespace SafeExamBrowser.WindowsApi.Contracts.Events
|
namespace SafeExamBrowser.WindowsApi.Contracts.Events
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
public enum MouseButtonState
|
public enum MouseButtonState
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,5 +11,5 @@ namespace SafeExamBrowser.WindowsApi.Contracts.Events
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The callback for a mouse hook. Return <c>true</c> to consume (i.e. block) the user input, otherwise <c>false</c>.
|
/// The callback for a mouse hook. Return <c>true</c> to consume (i.e. block) the user input, otherwise <c>false</c>.
|
||||||
/// </summary>
|
/// </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
|
namespace SafeExamBrowser.WindowsApi.Contracts
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
public interface IBounds
|
public interface IBounds
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,6 +49,11 @@ namespace SafeExamBrowser.WindowsApi.Contracts
|
||||||
/// </exception>
|
/// </exception>
|
||||||
void EmptyClipboard();
|
void EmptyClipboard();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the current position of the mouse cursor.
|
||||||
|
/// </summary>
|
||||||
|
(int x, int y) GetCursorPosition();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves a collection of handles to all currently open (i.e. visible) windows.
|
/// Retrieves a collection of handles to all currently open (i.e. visible) windows.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
<Compile Include="Events\MouseButton.cs" />
|
<Compile Include="Events\MouseButton.cs" />
|
||||||
<Compile Include="Events\MouseButtonState.cs" />
|
<Compile Include="Events\MouseButtonState.cs" />
|
||||||
<Compile Include="Events\MouseHookCallback.cs" />
|
<Compile Include="Events\MouseHookCallback.cs" />
|
||||||
|
<Compile Include="Events\MouseInformation.cs" />
|
||||||
<Compile Include="Events\ProcessTerminatedEventHandler.cs" />
|
<Compile Include="Events\ProcessTerminatedEventHandler.cs" />
|
||||||
<Compile Include="Events\SystemEventCallback.cs" />
|
<Compile Include="Events\SystemEventCallback.cs" />
|
||||||
<Compile Include="Events\TerminationActivatorEventHandler.cs" />
|
<Compile Include="Events\TerminationActivatorEventHandler.cs" />
|
||||||
|
@ -70,7 +71,6 @@
|
||||||
<Compile Include="INativeMethods.cs" />
|
<Compile Include="INativeMethods.cs" />
|
||||||
<Compile Include="IProcess.cs" />
|
<Compile Include="IProcess.cs" />
|
||||||
<Compile Include="IProcessFactory.cs" />
|
<Compile Include="IProcessFactory.cs" />
|
||||||
<Compile Include="ITerminationActivator.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
|
|
@ -54,8 +54,9 @@ namespace SafeExamBrowser.WindowsApi.Hooks
|
||||||
var mouseData = (MSLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
|
var mouseData = (MSLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
|
||||||
var button = GetButton(wParam.ToInt32());
|
var button = GetButton(wParam.ToInt32());
|
||||||
var state = GetState(wParam.ToInt32());
|
var state = GetState(wParam.ToInt32());
|
||||||
|
var info = GetInfo(mouseData);
|
||||||
|
|
||||||
if (callback(button, state))
|
if (callback(button, state, info))
|
||||||
{
|
{
|
||||||
return (IntPtr) 1;
|
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)
|
private MouseButtonState GetState(int wParam)
|
||||||
{
|
{
|
||||||
switch (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()
|
public IEnumerable<IntPtr> GetOpenWindows()
|
||||||
{
|
{
|
||||||
var windows = new List<IntPtr>();
|
var windows = new List<IntPtr>();
|
||||||
|
|
|
@ -66,14 +66,11 @@
|
||||||
<Compile Include="Desktop.cs" />
|
<Compile Include="Desktop.cs" />
|
||||||
<Compile Include="DesktopFactory.cs" />
|
<Compile Include="DesktopFactory.cs" />
|
||||||
<Compile Include="ExplorerShell.cs" />
|
<Compile Include="ExplorerShell.cs" />
|
||||||
<Compile Include="KeyboardActivator.cs" />
|
|
||||||
<Compile Include="Hooks\MouseHook.cs" />
|
<Compile Include="Hooks\MouseHook.cs" />
|
||||||
<Compile Include="Hooks\SystemHook.cs" />
|
<Compile Include="Hooks\SystemHook.cs" />
|
||||||
<Compile Include="TerminationActivator.cs" />
|
|
||||||
<Compile Include="Process.cs" />
|
<Compile Include="Process.cs" />
|
||||||
<Compile Include="ProcessFactory.cs" />
|
<Compile Include="ProcessFactory.cs" />
|
||||||
<Compile Include="Constants\AccessMask.cs" />
|
<Compile Include="Constants\AccessMask.cs" />
|
||||||
<Compile Include="TouchActivator.cs" />
|
|
||||||
<Compile Include="Types\Bounds.cs" />
|
<Compile Include="Types\Bounds.cs" />
|
||||||
<Compile Include="Types\EXECUTION_STATE.cs" />
|
<Compile Include="Types\EXECUTION_STATE.cs" />
|
||||||
<Compile Include="Types\KBDLLHOOKSTRUCT.cs" />
|
<Compile Include="Types\KBDLLHOOKSTRUCT.cs" />
|
||||||
|
@ -100,10 +97,6 @@
|
||||||
<Project>{64ea30fb-11d4-436a-9c2b-88566285363e}</Project>
|
<Project>{64ea30fb-11d4-436a-9c2b-88566285363e}</Project>
|
||||||
<Name>SafeExamBrowser.Logging.Contracts</Name>
|
<Name>SafeExamBrowser.Logging.Contracts</Name>
|
||||||
</ProjectReference>
|
</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">
|
<ProjectReference Include="..\SafeExamBrowser.WindowsApi.Contracts\SafeExamBrowser.WindowsApi.Contracts.csproj">
|
||||||
<Project>{7016f080-9aa5-41b2-a225-385ad877c171}</Project>
|
<Project>{7016f080-9aa5-41b2-a225-385ad877c171}</Project>
|
||||||
<Name>SafeExamBrowser.WindowsApi.Contracts</Name>
|
<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…
Reference in a new issue