From d99d46d086bc34935a9621d86d9a395aa3734210 Mon Sep 17 00:00:00 2001 From: dbuechel Date: Wed, 6 Mar 2019 16:10:00 +0100 Subject: [PATCH] SEBWIN-141: Basic draft of action center including keyboard and touch activators. --- .../BrowserApplicationController.cs | 2 +- .../ClientControllerTests.cs | 20 ++- .../Notifications/NotificationButtonMock.cs | 4 +- .../Operations/BrowserOperationTests.cs | 2 +- .../DisplayMonitorOperationTests.cs | 2 +- .../Operations/TaskbarOperationTests.cs | 5 +- SafeExamBrowser.Client/App.cs | 7 +- SafeExamBrowser.Client/ClientController.cs | 23 ++- SafeExamBrowser.Client/CompositionRoot.cs | 87 +++++++++-- .../AboutNotificationController.cs | 2 +- .../LogNotificationController.cs | 2 +- .../Operations/ActionCenterOperation.cs | 91 ++++++++++++ .../Operations/BrowserOperation.cs | 2 +- .../Operations/DisplayMonitorOperation.cs | 2 +- .../Operations/TaskbarOperation.cs | 94 ++++++------ .../SafeExamBrowser.Client.csproj | 1 + .../ConfigurationData/DataValues.cs | 4 +- .../Applications/IApplicationController.cs | 2 +- .../Applications/IApplicationInfo.cs | 2 +- .../Applications/IApplicationInstance.cs | 2 +- .../Client/INotificationController.cs | 2 +- .../Client/INotificationInfo.cs | 2 +- .../Settings/ActionCenterSettings.cs | 24 +++ .../Configuration/Settings/Settings.cs | 6 + .../Configuration/Settings/TaskbarSettings.cs | 7 +- .../SafeExamBrowser.Contracts.csproj | 30 ++-- .../SystemComponents/ISystemComponent.cs | 2 +- .../UserInterface/IUserInterfaceFactory.cs | 2 +- .../Shell/Events/ActivatorEventHandler.cs | 15 ++ .../ApplicationButtonClickedEventHandler.cs | 2 +- .../KeyboardLayoutSelectedEventHandler.cs | 2 +- .../NotificationButtonClickedEventHandler.cs | 2 +- .../Events/QuitButtonClickedEventHandler.cs | 2 +- .../WirelessNetworkSelectedEventHandler.cs | 2 +- .../UserInterface/Shell/IActionCenter.cs | 36 +++++ .../Shell/IActionCenterActivator.cs | 43 ++++++ .../{Taskbar => Shell}/IApplicationButton.cs | 4 +- .../{Taskbar => Shell}/INotificationButton.cs | 4 +- .../{Taskbar => Shell}/ISystemControl.cs | 2 +- .../ISystemKeyboardLayoutControl.cs | 4 +- .../ISystemPowerSupplyControl.cs | 2 +- .../ISystemWirelessNetworkControl.cs | 4 +- .../{Taskbar => Shell}/ITaskbar.cs | 12 +- .../Events/WindowClosingEventHandler.cs | 2 +- .../UserInterface/Windows/IWindow.cs | 2 +- SafeExamBrowser.Runtime/CompositionRoot.cs | 38 ++++- .../KeyboardLayout.cs | 2 +- .../PowerSupply.cs | 2 +- .../WirelessNetwork.cs | 2 +- .../AboutWindow.xaml.cs | 2 +- .../ActionCenter.xaml | 12 ++ .../ActionCenter.xaml.cs | 137 ++++++++++++++++++ .../BrowserWindow.xaml.cs | 50 ++++--- .../Controls/ApplicationButton.xaml.cs | 4 +- .../ApplicationInstanceButton.xaml.cs | 2 +- .../Controls/KeyboardLayoutControl.xaml.cs | 4 +- .../Controls/NotificationButton.xaml.cs | 4 +- .../Controls/PowerSupplyControl.xaml.cs | 2 +- .../Controls/QuitButton.xaml.cs | 2 +- .../Controls/WirelessNetworkControl.xaml.cs | 4 +- .../LogWindow.xaml.cs | 2 +- .../PasswordDialog.xaml.cs | 2 +- .../RuntimeWindow.xaml.cs | 2 +- ...feExamBrowser.UserInterface.Desktop.csproj | 7 + .../SplashScreen.xaml.cs | 2 +- .../Taskbar.xaml | 4 +- .../Taskbar.xaml.cs | 9 +- .../UserInterfaceFactory.cs | 2 +- .../{ACCESS_MASK.cs => AccessMask.cs} | 2 +- .../Constants/Constant.cs | 14 ++ .../Constants/VirtualKeyCode.cs | 24 +++ .../Delegates/HookDelegate.cs | 2 +- SafeExamBrowser.WindowsApi/DesktopFactory.cs | 2 +- .../KeyboardActivator.cs | 110 ++++++++++++++ .../Monitoring/KeyboardHook.cs | 14 +- .../Monitoring/MouseHook.cs | 2 +- .../Monitoring/SystemHook.cs | 2 +- .../SafeExamBrowser.WindowsApi.csproj | 5 +- SafeExamBrowser.WindowsApi/TouchActivator.cs | 121 ++++++++++++++++ SafeExamBrowser.WindowsApi/User32.cs | 3 + 80 files changed, 978 insertions(+), 191 deletions(-) create mode 100644 SafeExamBrowser.Client/Operations/ActionCenterOperation.cs create mode 100644 SafeExamBrowser.Contracts/Configuration/Settings/ActionCenterSettings.cs create mode 100644 SafeExamBrowser.Contracts/UserInterface/Shell/Events/ActivatorEventHandler.cs rename SafeExamBrowser.Contracts/UserInterface/{Taskbar => Shell}/Events/ApplicationButtonClickedEventHandler.cs (91%) rename SafeExamBrowser.Contracts/UserInterface/{Taskbar => Shell}/Events/KeyboardLayoutSelectedEventHandler.cs (89%) rename SafeExamBrowser.Contracts/UserInterface/{Taskbar => Shell}/Events/NotificationButtonClickedEventHandler.cs (88%) rename SafeExamBrowser.Contracts/UserInterface/{Taskbar => Shell}/Events/QuitButtonClickedEventHandler.cs (89%) rename SafeExamBrowser.Contracts/UserInterface/{Taskbar => Shell}/Events/WirelessNetworkSelectedEventHandler.cs (89%) create mode 100644 SafeExamBrowser.Contracts/UserInterface/Shell/IActionCenter.cs create mode 100644 SafeExamBrowser.Contracts/UserInterface/Shell/IActionCenterActivator.cs rename SafeExamBrowser.Contracts/UserInterface/{Taskbar => Shell}/IApplicationButton.cs (89%) rename SafeExamBrowser.Contracts/UserInterface/{Taskbar => Shell}/INotificationButton.cs (83%) rename SafeExamBrowser.Contracts/UserInterface/{Taskbar => Shell}/ISystemControl.cs (92%) rename SafeExamBrowser.Contracts/UserInterface/{Taskbar => Shell}/ISystemKeyboardLayoutControl.cs (87%) rename SafeExamBrowser.Contracts/UserInterface/{Taskbar => Shell}/ISystemPowerSupplyControl.cs (95%) rename SafeExamBrowser.Contracts/UserInterface/{Taskbar => Shell}/ISystemWirelessNetworkControl.cs (91%) rename SafeExamBrowser.Contracts/UserInterface/{Taskbar => Shell}/ITaskbar.cs (81%) rename SafeExamBrowser.Contracts/UserInterface/{Taskbar => Windows}/Events/WindowClosingEventHandler.cs (87%) create mode 100644 SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml create mode 100644 SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml.cs rename SafeExamBrowser.WindowsApi/Constants/{ACCESS_MASK.cs => AccessMask.cs} (96%) create mode 100644 SafeExamBrowser.WindowsApi/Constants/VirtualKeyCode.cs create mode 100644 SafeExamBrowser.WindowsApi/KeyboardActivator.cs create mode 100644 SafeExamBrowser.WindowsApi/TouchActivator.cs diff --git a/SafeExamBrowser.Browser/BrowserApplicationController.cs b/SafeExamBrowser.Browser/BrowserApplicationController.cs index 73b8049e..23f1993c 100644 --- a/SafeExamBrowser.Browser/BrowserApplicationController.cs +++ b/SafeExamBrowser.Browser/BrowserApplicationController.cs @@ -19,7 +19,7 @@ using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface.MessageBox; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.BrowserSettings; namespace SafeExamBrowser.Browser diff --git a/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs b/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs index dcdf803f..02ffd4e5 100644 --- a/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs +++ b/SafeExamBrowser.Client.UnitTests/ClientControllerTests.cs @@ -24,7 +24,7 @@ using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Monitoring; using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface.MessageBox; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; using SafeExamBrowser.Contracts.UserInterface.Windows; using SafeExamBrowser.Contracts.WindowsApi; @@ -34,6 +34,7 @@ namespace SafeExamBrowser.Client.UnitTests public class ClientControllerTests { private AppConfig appConfig; + private Mock actionCenter; private Mock browserController; private Mock clientHost; private Mock displayMonitor; @@ -58,6 +59,7 @@ namespace SafeExamBrowser.Client.UnitTests public void Initialize() { appConfig = new AppConfig(); + actionCenter = new Mock(); browserController = new Mock(); clientHost = new Mock(); displayMonitor = new Mock(); @@ -81,6 +83,7 @@ namespace SafeExamBrowser.Client.UnitTests uiFactory.Setup(u => u.CreateSplashScreen(It.IsAny())).Returns(new Mock().Object); sut = new ClientController( + actionCenter.Object, displayMonitor.Object, explorerShell.Object, hashAlgorithm.Object, @@ -632,6 +635,21 @@ namespace SafeExamBrowser.Client.UnitTests splashScreen.VerifySet(s => s.AppConfig = appConfig, Times.Once); } + [TestMethod] + public void Startup_MustCorrectlyHandleTaskbar() + { + operationSequence.Setup(o => o.TryPerform()).Returns(OperationResult.Success); + sut.TryStart(); + + taskbar.Verify(t => t.Show(), Times.Once); + + taskbar.Reset(); + operationSequence.Setup(o => o.TryPerform()).Returns(OperationResult.Aborted); + sut.TryStart(); + + taskbar.Verify(t => t.Show(), Times.Never); + } + [TestMethod] public void WindowMonitor_MustHandleAllowedWindowChangeCorrectly() { diff --git a/SafeExamBrowser.Client.UnitTests/Notifications/NotificationButtonMock.cs b/SafeExamBrowser.Client.UnitTests/Notifications/NotificationButtonMock.cs index 02a872c8..a3e94eda 100644 --- a/SafeExamBrowser.Client.UnitTests/Notifications/NotificationButtonMock.cs +++ b/SafeExamBrowser.Client.UnitTests/Notifications/NotificationButtonMock.cs @@ -6,8 +6,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.UserInterface.Taskbar; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; +using SafeExamBrowser.Contracts.UserInterface.Shell; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; namespace SafeExamBrowser.Client.UnitTests.Notifications { diff --git a/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs index fa51ee1d..fa9b6955 100644 --- a/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs @@ -12,7 +12,7 @@ using SafeExamBrowser.Client.Operations; using SafeExamBrowser.Contracts.Applications; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.UserInterface; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; namespace SafeExamBrowser.Client.UnitTests.Operations { diff --git a/SafeExamBrowser.Client.UnitTests/Operations/DisplayMonitorOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/DisplayMonitorOperationTests.cs index 2de4e6e5..b36261c1 100644 --- a/SafeExamBrowser.Client.UnitTests/Operations/DisplayMonitorOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Operations/DisplayMonitorOperationTests.cs @@ -11,7 +11,7 @@ using Moq; using SafeExamBrowser.Client.Operations; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Monitoring; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; namespace SafeExamBrowser.Client.UnitTests.Operations { diff --git a/SafeExamBrowser.Client.UnitTests/Operations/TaskbarOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/TaskbarOperationTests.cs index 17c70860..24ba16a2 100644 --- a/SafeExamBrowser.Client.UnitTests/Operations/TaskbarOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Operations/TaskbarOperationTests.cs @@ -15,7 +15,7 @@ using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.SystemComponents; using SafeExamBrowser.Contracts.UserInterface; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; namespace SafeExamBrowser.Client.UnitTests.Operations { @@ -33,7 +33,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations private Mock> wirelessNetworkMock; private Mock systemInfoMock; private Mock taskbarMock; - private Mock textMock; private Mock uiFactoryMock; private TaskbarOperation sut; @@ -52,7 +51,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations systemInfoMock = new Mock(); taskbarMock = new Mock(); settings = new TaskbarSettings(); - textMock = new Mock(); uiFactoryMock = new Mock(); settings.AllowApplicationLog = true; @@ -73,7 +71,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations systemInfoMock.Object, taskbarMock.Object, settings, - textMock.Object, uiFactoryMock.Object); } diff --git a/SafeExamBrowser.Client/App.cs b/SafeExamBrowser.Client/App.cs index c9bc4387..149c2fb4 100644 --- a/SafeExamBrowser.Client/App.cs +++ b/SafeExamBrowser.Client/App.cs @@ -62,12 +62,7 @@ namespace SafeExamBrowser.Client var success = instances.ClientController.TryStart(); - if (success) - { - MainWindow = instances.Taskbar; - MainWindow.Show(); - } - else + if (!success) { Shutdown(); } diff --git a/SafeExamBrowser.Client/ClientController.cs b/SafeExamBrowser.Client/ClientController.cs index 161b95a2..6c34d361 100644 --- a/SafeExamBrowser.Client/ClientController.cs +++ b/SafeExamBrowser.Client/ClientController.cs @@ -24,7 +24,7 @@ using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Monitoring; using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface.MessageBox; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; using SafeExamBrowser.Contracts.UserInterface.Windows; using SafeExamBrowser.Contracts.WindowsApi; @@ -32,6 +32,7 @@ namespace SafeExamBrowser.Client { internal class ClientController : IClientController { + private IActionCenter actionCenter; private IDisplayMonitor displayMonitor; private IExplorerShell explorerShell; private IHashAlgorithm hashAlgorithm; @@ -67,6 +68,7 @@ namespace SafeExamBrowser.Client } public ClientController( + IActionCenter actionCenter, IDisplayMonitor displayMonitor, IExplorerShell explorerShell, IHashAlgorithm hashAlgorithm, @@ -81,6 +83,7 @@ namespace SafeExamBrowser.Client IUserInterfaceFactory uiFactory, IWindowMonitor windowMonitor) { + this.actionCenter = actionCenter; this.displayMonitor = displayMonitor; this.explorerShell = explorerShell; this.hashAlgorithm = hashAlgorithm; @@ -109,14 +112,13 @@ namespace SafeExamBrowser.Client if (success) { RegisterEvents(); + ShowShell(); StartBrowser(); var communication = runtime.InformClientReady(); if (communication.Success) { - splashScreen.Close(); - logger.Info("Application successfully initialized."); logger.Log(string.Empty); } @@ -132,6 +134,8 @@ namespace SafeExamBrowser.Client logger.Log(string.Empty); } + splashScreen.Close(); + return success; } @@ -141,7 +145,8 @@ namespace SafeExamBrowser.Client logger.Info("Initiating shutdown procedure..."); splashScreen = uiFactory.CreateSplashScreen(appConfig); - splashScreen.Show(); + actionCenter.Close(); + taskbar.Close(); DeregisterEvents(); @@ -197,6 +202,14 @@ namespace SafeExamBrowser.Client } } + private void ShowShell() + { + if (Settings.Taskbar.EnableTaskbar) + { + taskbar.Show(); + } + } + private void StartBrowser() { logger.Info("Starting browser application..."); @@ -321,7 +334,6 @@ namespace SafeExamBrowser.Client private void ClientHost_Shutdown() { - taskbar.Close(); shutdown.Invoke(); } @@ -363,7 +375,6 @@ namespace SafeExamBrowser.Client logger.Error("Lost connection to the runtime!"); messageBox.Show(TextKey.MessageBox_ApplicationError, TextKey.MessageBox_ApplicationErrorTitle, icon: MessageBoxIcon.Error); - taskbar.Close(); shutdown.Invoke(); } diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index e1e74b3b..a9892313 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -30,6 +30,7 @@ using SafeExamBrowser.Contracts.Monitoring; using SafeExamBrowser.Contracts.SystemComponents; using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface.MessageBox; +using SafeExamBrowser.Contracts.UserInterface.Shell; using SafeExamBrowser.Contracts.WindowsApi; using SafeExamBrowser.Core.OperationModel; using SafeExamBrowser.Core.Operations; @@ -48,27 +49,31 @@ namespace SafeExamBrowser.Client { internal class CompositionRoot { + private ClientConfiguration configuration; private string logFilePath; private LogLevel logLevel; private string runtimeHostUri; private Guid startupToken; + private IActionCenter actionCenter; private IBrowserApplicationController browserController; - private ClientConfiguration configuration; private IClientHost clientHost; private ILogger logger; private IMessageBox messageBox; private IProcessMonitor processMonitor; private INativeMethods nativeMethods; private IRuntimeProxy runtimeProxy; + private ISystemComponent keyboardLayout; + private ISystemComponent powerSupply; + private ISystemComponent wirelessNetwork; private ISystemInfo systemInfo; + private ITaskbar taskbar; private IText text; private ITextResource textResource; private IUserInterfaceFactory uiFactory; private IWindowMonitor windowMonitor; internal IClientController ClientController { get; private set; } - internal Taskbar Taskbar { get; private set; } internal void BuildObjectGraph(Action shutdown) { @@ -82,18 +87,21 @@ namespace SafeExamBrowser.Client InitializeLogging(); InitializeText(); + actionCenter = new ActionCenter(); + keyboardLayout = new KeyboardLayout(new ModuleLogger(logger, nameof(KeyboardLayout)), text); messageBox = new MessageBox(text); + powerSupply = new PowerSupply(new ModuleLogger(logger, nameof(PowerSupply)), text); processMonitor = new ProcessMonitor(new ModuleLogger(logger, nameof(ProcessMonitor)), nativeMethods); uiFactory = new UserInterfaceFactory(text); runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), new ModuleLogger(logger, nameof(RuntimeProxy))); + taskbar = new Taskbar(new ModuleLogger(logger, nameof(taskbar))); windowMonitor = new WindowMonitor(new ModuleLogger(logger, nameof(WindowMonitor)), nativeMethods); + wirelessNetwork = new WirelessNetwork(new ModuleLogger(logger, nameof(WirelessNetwork)), text); var displayMonitor = new DisplayMonitor(new ModuleLogger(logger, nameof(DisplayMonitor)), nativeMethods); var explorerShell = new ExplorerShell(new ModuleLogger(logger, nameof(ExplorerShell)), nativeMethods); var hashAlgorithm = new HashAlgorithm(); - Taskbar = new Taskbar(new ModuleLogger(logger, nameof(Taskbar))); - var operations = new Queue(); operations.Enqueue(new InitializationOperation(logger)); @@ -104,18 +112,33 @@ namespace SafeExamBrowser.Client operations.Enqueue(new LazyInitializationOperation(BuildClientHostOperation)); operations.Enqueue(new LazyInitializationOperation(BuildClientHostDisconnectionOperation)); operations.Enqueue(new LazyInitializationOperation(BuildKeyboardInterceptorOperation)); + operations.Enqueue(new LazyInitializationOperation(BuildMouseInterceptorOperation)); operations.Enqueue(new LazyInitializationOperation(BuildWindowMonitorOperation)); operations.Enqueue(new LazyInitializationOperation(BuildProcessMonitorOperation)); - operations.Enqueue(new DisplayMonitorOperation(displayMonitor, logger, Taskbar)); + operations.Enqueue(new DisplayMonitorOperation(displayMonitor, logger, taskbar)); + operations.Enqueue(new LazyInitializationOperation(BuildActionCenterOperation)); operations.Enqueue(new LazyInitializationOperation(BuildTaskbarOperation)); operations.Enqueue(new LazyInitializationOperation(BuildBrowserOperation)); operations.Enqueue(new ClipboardOperation(logger, nativeMethods)); - operations.Enqueue(new LazyInitializationOperation(BuildMouseInterceptorOperation)); operations.Enqueue(new DelegateOperation(UpdateClientControllerDependencies)); var sequence = new OperationSequence(logger, operations); - ClientController = new ClientController(displayMonitor, explorerShell, hashAlgorithm, logger, messageBox, sequence, processMonitor, runtimeProxy, shutdown, Taskbar, text, uiFactory, windowMonitor); + ClientController = new ClientController( + actionCenter, + displayMonitor, + explorerShell, + hashAlgorithm, + logger, + messageBox, + sequence, + processMonitor, + runtimeProxy, + shutdown, + taskbar, + text, + uiFactory, + windowMonitor); } internal void LogStartupInformation() @@ -173,12 +196,41 @@ namespace SafeExamBrowser.Client textResource = new XmlTextResource(path); } + private IOperation BuildActionCenterOperation() + { + var aboutInfo = new AboutNotificationInfo(text); + var aboutController = new AboutNotificationController(configuration.AppConfig, uiFactory); + var logInfo = new LogNotificationInfo(text); + var logController = new LogNotificationController(logger, uiFactory); + var activators = new IActionCenterActivator[] + { + new KeyboardActivator(new ModuleLogger(logger, nameof(KeyboardActivator))), + new TouchActivator(new ModuleLogger(logger, nameof(TouchActivator))) + }; + var operation = new ActionCenterOperation( + actionCenter, + activators, + logger, + aboutInfo, + aboutController, + logInfo, + logController, + keyboardLayout, + powerSupply, + wirelessNetwork, + configuration.Settings.ActionCenter, + systemInfo, + uiFactory); + + return operation; + } + private IOperation BuildBrowserOperation() { var moduleLogger = new ModuleLogger(logger, "BrowserController"); var browserController = new BrowserApplicationController(configuration.AppConfig, configuration.Settings.Browser, messageBox, moduleLogger, text, uiFactory); var browserInfo = new BrowserApplicationInfo(); - var operation = new BrowserOperation(browserController, browserInfo, logger, Taskbar, uiFactory); + var operation = new BrowserOperation(browserController, browserInfo, logger, taskbar, uiFactory); this.browserController = browserController; @@ -232,12 +284,21 @@ namespace SafeExamBrowser.Client { var aboutInfo = new AboutNotificationInfo(text); var aboutController = new AboutNotificationController(configuration.AppConfig, uiFactory); - var keyboardLayout = new KeyboardLayout(new ModuleLogger(logger, nameof(KeyboardLayout)), text); - var logController = new LogNotificationController(logger, uiFactory); var logInfo = new LogNotificationInfo(text); - var powerSupply = new PowerSupply(new ModuleLogger(logger, nameof(PowerSupply)), text); - var wirelessNetwork = new WirelessNetwork(new ModuleLogger(logger, nameof(WirelessNetwork)), text); - var operation = new TaskbarOperation(logger, aboutInfo, aboutController, logInfo, logController, keyboardLayout, powerSupply, wirelessNetwork, systemInfo, Taskbar, configuration.Settings.Taskbar, text, uiFactory); + var logController = new LogNotificationController(logger, uiFactory); + var operation = new TaskbarOperation( + logger, + aboutInfo, + aboutController, + logInfo, + logController, + keyboardLayout, + powerSupply, + wirelessNetwork, + systemInfo, + taskbar, + configuration.Settings.Taskbar, + uiFactory); return operation; } diff --git a/SafeExamBrowser.Client/Notifications/AboutNotificationController.cs b/SafeExamBrowser.Client/Notifications/AboutNotificationController.cs index cd65f48b..96e3f5aa 100644 --- a/SafeExamBrowser.Client/Notifications/AboutNotificationController.cs +++ b/SafeExamBrowser.Client/Notifications/AboutNotificationController.cs @@ -9,7 +9,7 @@ using SafeExamBrowser.Contracts.Client; using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.UserInterface; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; using SafeExamBrowser.Contracts.UserInterface.Windows; namespace SafeExamBrowser.Client.Notifications diff --git a/SafeExamBrowser.Client/Notifications/LogNotificationController.cs b/SafeExamBrowser.Client/Notifications/LogNotificationController.cs index 81581a60..52093e68 100644 --- a/SafeExamBrowser.Client/Notifications/LogNotificationController.cs +++ b/SafeExamBrowser.Client/Notifications/LogNotificationController.cs @@ -9,7 +9,7 @@ using SafeExamBrowser.Contracts.Client; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.UserInterface; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; using SafeExamBrowser.Contracts.UserInterface.Windows; namespace SafeExamBrowser.Client.Notifications diff --git a/SafeExamBrowser.Client/Operations/ActionCenterOperation.cs b/SafeExamBrowser.Client/Operations/ActionCenterOperation.cs new file mode 100644 index 00000000..31f8aacf --- /dev/null +++ b/SafeExamBrowser.Client/Operations/ActionCenterOperation.cs @@ -0,0 +1,91 @@ +/* + * 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.Collections.Generic; +using SafeExamBrowser.Contracts.Client; +using SafeExamBrowser.Contracts.Configuration.Settings; +using SafeExamBrowser.Contracts.Core.OperationModel; +using SafeExamBrowser.Contracts.Core.OperationModel.Events; +using SafeExamBrowser.Contracts.Logging; +using SafeExamBrowser.Contracts.SystemComponents; +using SafeExamBrowser.Contracts.UserInterface; +using SafeExamBrowser.Contracts.UserInterface.Shell; + +namespace SafeExamBrowser.Client.Operations +{ + internal class ActionCenterOperation : IOperation + { + private IActionCenter actionCenter; + private IEnumerable activators; + private ILogger logger; + private INotificationInfo aboutInfo; + private INotificationController aboutController; + private INotificationInfo logInfo; + private INotificationController logController; + private ISystemComponent keyboardLayout; + private ISystemComponent powerSupply; + private ISystemComponent wirelessNetwork; + private ActionCenterSettings settings; + private ISystemInfo systemInfo; + private IUserInterfaceFactory uiFactory; + + public event ActionRequiredEventHandler ActionRequired { add { } remove { } } + public event StatusChangedEventHandler StatusChanged; + + public ActionCenterOperation( + IActionCenter actionCenter, + IEnumerable activators, + ILogger logger, + INotificationInfo aboutInfo, + INotificationController aboutController, + INotificationInfo logInfo, + INotificationController logController, + ISystemComponent keyboardLayout, + ISystemComponent powerSupply, + ISystemComponent wirelessNetwork, + ActionCenterSettings settings, + ISystemInfo systemInfo, + IUserInterfaceFactory uiFactory) + { + this.actionCenter = actionCenter; + this.activators = activators; + this.logger = logger; + this.aboutInfo = aboutInfo; + this.aboutController = aboutController; + this.logInfo = logInfo; + this.logController = logController; + this.keyboardLayout = keyboardLayout; + this.powerSupply = powerSupply; + this.wirelessNetwork = wirelessNetwork; + this.systemInfo = systemInfo; + this.settings = settings; + this.uiFactory = uiFactory; + } + + public OperationResult Perform() + { + foreach (var activator in activators) + { + actionCenter.Register(activator); + activator.Start(); + } + + return OperationResult.Success; + } + + public OperationResult Revert() + { + foreach (var activator in activators) + { + activator.Stop(); + } + + return OperationResult.Success; + } + } +} diff --git a/SafeExamBrowser.Client/Operations/BrowserOperation.cs b/SafeExamBrowser.Client/Operations/BrowserOperation.cs index e665e379..b372c63e 100644 --- a/SafeExamBrowser.Client/Operations/BrowserOperation.cs +++ b/SafeExamBrowser.Client/Operations/BrowserOperation.cs @@ -12,7 +12,7 @@ using SafeExamBrowser.Contracts.Core.OperationModel.Events; using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.UserInterface; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; namespace SafeExamBrowser.Client.Operations { diff --git a/SafeExamBrowser.Client/Operations/DisplayMonitorOperation.cs b/SafeExamBrowser.Client/Operations/DisplayMonitorOperation.cs index f58c108b..731e013b 100644 --- a/SafeExamBrowser.Client/Operations/DisplayMonitorOperation.cs +++ b/SafeExamBrowser.Client/Operations/DisplayMonitorOperation.cs @@ -11,7 +11,7 @@ using SafeExamBrowser.Contracts.Core.OperationModel.Events; using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Monitoring; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; namespace SafeExamBrowser.Client.Operations { diff --git a/SafeExamBrowser.Client/Operations/TaskbarOperation.cs b/SafeExamBrowser.Client/Operations/TaskbarOperation.cs index d0a049ba..dec4aee1 100644 --- a/SafeExamBrowser.Client/Operations/TaskbarOperation.cs +++ b/SafeExamBrowser.Client/Operations/TaskbarOperation.cs @@ -14,7 +14,7 @@ using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.SystemComponents; using SafeExamBrowser.Contracts.UserInterface; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; namespace SafeExamBrowser.Client.Operations { @@ -32,7 +32,6 @@ namespace SafeExamBrowser.Client.Operations private ISystemInfo systemInfo; private ITaskbar taskbar; private IUserInterfaceFactory uiFactory; - private IText text; public event ActionRequiredEventHandler ActionRequired { add { } remove { } } public event StatusChangedEventHandler StatusChanged; @@ -49,7 +48,6 @@ namespace SafeExamBrowser.Client.Operations ISystemInfo systemInfo, ITaskbar taskbar, TaskbarSettings settings, - IText text, IUserInterfaceFactory uiFactory) { this.aboutInfo = aboutInfo; @@ -62,37 +60,44 @@ namespace SafeExamBrowser.Client.Operations this.settings = settings; this.systemInfo = systemInfo; this.taskbar = taskbar; - this.text = text; this.uiFactory = uiFactory; this.wirelessNetwork = wirelessNetwork; } public OperationResult Perform() { - logger.Info("Initializing taskbar..."); StatusChanged?.Invoke(TextKey.OperationStatus_InitializeTaskbar); - AddAboutNotification(); - taskbar.ShowClock = settings.ShowClock; - - if (settings.AllowApplicationLog) + if (settings.EnableTaskbar) { - AddLogNotification(); + logger.Info("Initializing taskbar..."); + + AddAboutNotification(); + taskbar.ShowClock = settings.ShowClock; + + if (settings.AllowApplicationLog) + { + AddLogNotification(); + } + + if (settings.AllowKeyboardLayout) + { + AddKeyboardLayoutControl(); + } + + if (settings.AllowWirelessNetwork) + { + AddWirelessNetworkControl(); + } + + if (systemInfo.HasBattery) + { + AddPowerSupplyControl(); + } } - - if (settings.AllowKeyboardLayout) + else { - AddKeyboardLayoutControl(); - } - - if (settings.AllowWirelessNetwork) - { - AddWirelessNetworkControl(); - } - - if (systemInfo.HasBattery) - { - AddPowerSupplyControl(); + logger.Info("Taskbar is disabled, skipping initialization."); } return OperationResult.Success; @@ -100,29 +105,36 @@ namespace SafeExamBrowser.Client.Operations public OperationResult Revert() { - logger.Info("Terminating taskbar..."); StatusChanged?.Invoke(TextKey.OperationStatus_TerminateTaskbar); - aboutController.Terminate(); - - if (settings.AllowApplicationLog) + if (settings.EnableTaskbar) { - logController.Terminate(); + logger.Info("Terminating taskbar..."); + aboutController.Terminate(); + + if (settings.AllowApplicationLog) + { + logController.Terminate(); + } + + if (settings.AllowKeyboardLayout) + { + keyboardLayout.Terminate(); + } + + if (settings.AllowWirelessNetwork) + { + wirelessNetwork.Terminate(); + } + + if (systemInfo.HasBattery) + { + powerSupply.Terminate(); + } } - - if (settings.AllowKeyboardLayout) + else { - keyboardLayout.Terminate(); - } - - if (settings.AllowWirelessNetwork) - { - wirelessNetwork.Terminate(); - } - - if (systemInfo.HasBattery) - { - powerSupply.Terminate(); + logger.Info("Taskbar was disabled, skipping termination."); } return OperationResult.Success; diff --git a/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj b/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj index a8b50edf..12e31887 100644 --- a/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj +++ b/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj @@ -72,6 +72,7 @@ + diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs index 980d22a4..7b9963f7 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs @@ -88,6 +88,8 @@ namespace SafeExamBrowser.Configuration.ConfigurationData { var settings = new Settings(); + settings.ActionCenter.EnableActionCenter = true; + settings.Browser.StartUrl = "https://www.safeexambrowser.org/start"; settings.Browser.AllowConfigurationDownloads = true; settings.Browser.AllowDeveloperConsole = false; @@ -139,12 +141,12 @@ namespace SafeExamBrowser.Configuration.ConfigurationData settings.Taskbar.AllowApplicationLog = false; settings.Taskbar.AllowKeyboardLayout = true; settings.Taskbar.AllowWirelessNetwork = false; + settings.Taskbar.EnableTaskbar = true; settings.Taskbar.ShowClock = true; // TODO: Default values for testing of alpha version only, remove for final release! settings.Browser.AllowDeveloperConsole = true; settings.Browser.MainWindowSettings.AllowAddressBar = true; - settings.KioskMode = KioskMode.None; settings.Taskbar.AllowApplicationLog = true; return settings; diff --git a/SafeExamBrowser.Contracts/Applications/IApplicationController.cs b/SafeExamBrowser.Contracts/Applications/IApplicationController.cs index 8772dcdb..00877f43 100644 --- a/SafeExamBrowser.Contracts/Applications/IApplicationController.cs +++ b/SafeExamBrowser.Contracts/Applications/IApplicationController.cs @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; namespace SafeExamBrowser.Contracts.Applications { diff --git a/SafeExamBrowser.Contracts/Applications/IApplicationInfo.cs b/SafeExamBrowser.Contracts/Applications/IApplicationInfo.cs index 1c317c38..bedaa8c7 100644 --- a/SafeExamBrowser.Contracts/Applications/IApplicationInfo.cs +++ b/SafeExamBrowser.Contracts/Applications/IApplicationInfo.cs @@ -11,7 +11,7 @@ using SafeExamBrowser.Contracts.Core; namespace SafeExamBrowser.Contracts.Applications { /// - /// The information about a (third-party) application which can be accessed via the . + /// The information about a (third-party) application which can be accessed via the shell. /// public interface IApplicationInfo { diff --git a/SafeExamBrowser.Contracts/Applications/IApplicationInstance.cs b/SafeExamBrowser.Contracts/Applications/IApplicationInstance.cs index 7e4a299d..29b49f32 100644 --- a/SafeExamBrowser.Contracts/Applications/IApplicationInstance.cs +++ b/SafeExamBrowser.Contracts/Applications/IApplicationInstance.cs @@ -12,7 +12,7 @@ using SafeExamBrowser.Contracts.UserInterface.Windows; namespace SafeExamBrowser.Contracts.Applications { /// - /// Defines an instance of a (third-party) application which can be accessed via the . + /// Defines an instance of a (third-party) application which can be accessed via the shell. /// public interface IApplicationInstance { diff --git a/SafeExamBrowser.Contracts/Client/INotificationController.cs b/SafeExamBrowser.Contracts/Client/INotificationController.cs index 007c8e06..be847fe5 100644 --- a/SafeExamBrowser.Contracts/Client/INotificationController.cs +++ b/SafeExamBrowser.Contracts/Client/INotificationController.cs @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; namespace SafeExamBrowser.Contracts.Client { diff --git a/SafeExamBrowser.Contracts/Client/INotificationInfo.cs b/SafeExamBrowser.Contracts/Client/INotificationInfo.cs index e5588994..93aefe88 100644 --- a/SafeExamBrowser.Contracts/Client/INotificationInfo.cs +++ b/SafeExamBrowser.Contracts/Client/INotificationInfo.cs @@ -11,7 +11,7 @@ using SafeExamBrowser.Contracts.Core; namespace SafeExamBrowser.Contracts.Client { /// - /// The information about a notification which is part of the . + /// The information about a notification. /// public interface INotificationInfo { diff --git a/SafeExamBrowser.Contracts/Configuration/Settings/ActionCenterSettings.cs b/SafeExamBrowser.Contracts/Configuration/Settings/ActionCenterSettings.cs new file mode 100644 index 00000000..b4c8a819 --- /dev/null +++ b/SafeExamBrowser.Contracts/Configuration/Settings/ActionCenterSettings.cs @@ -0,0 +1,24 @@ +/* + * 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; + +namespace SafeExamBrowser.Contracts.Configuration.Settings +{ + /// + /// Defines all configuration options for the . + /// + [Serializable] + public class ActionCenterSettings + { + /// + /// Determines whether the action center itself is enabled and visible to the user. + /// + public bool EnableActionCenter { get; set; } + } +} diff --git a/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs b/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs index 139f3707..8ce08374 100644 --- a/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs +++ b/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs @@ -17,6 +17,11 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings [Serializable] public class Settings { + /// + /// All action center-related settings. + /// + public ActionCenterSettings ActionCenter { get; set; } + /// /// The hash code of the administrator password for the settings. /// @@ -74,6 +79,7 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings public Settings() { + ActionCenter = new ActionCenterSettings(); Browser = new BrowserSettings(); Keyboard = new KeyboardSettings(); Mouse = new MouseSettings(); diff --git a/SafeExamBrowser.Contracts/Configuration/Settings/TaskbarSettings.cs b/SafeExamBrowser.Contracts/Configuration/Settings/TaskbarSettings.cs index f415e591..411c0692 100644 --- a/SafeExamBrowser.Contracts/Configuration/Settings/TaskbarSettings.cs +++ b/SafeExamBrowser.Contracts/Configuration/Settings/TaskbarSettings.cs @@ -11,7 +11,7 @@ using System; namespace SafeExamBrowser.Contracts.Configuration.Settings { /// - /// Defines all configuration options for the . + /// Defines all configuration options for the . /// [Serializable] public class TaskbarSettings @@ -31,6 +31,11 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings /// public bool AllowWirelessNetwork { get; set; } + /// + /// Determines whether the taskbar itself is enabled and visible to the user. + /// + public bool EnableTaskbar { get; set; } + /// /// Determines whether the current date and time will be rendered in the taskbar. /// diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj index c55f92f3..b30f3897 100644 --- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj +++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj @@ -73,6 +73,7 @@ + @@ -186,26 +187,29 @@ - - - - - - + + + + + + + + + - + - - - - - + + + + + - + diff --git a/SafeExamBrowser.Contracts/SystemComponents/ISystemComponent.cs b/SafeExamBrowser.Contracts/SystemComponents/ISystemComponent.cs index 042783ad..4ef9f60d 100644 --- a/SafeExamBrowser.Contracts/SystemComponents/ISystemComponent.cs +++ b/SafeExamBrowser.Contracts/SystemComponents/ISystemComponent.cs @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; namespace SafeExamBrowser.Contracts.SystemComponents { diff --git a/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs b/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs index 4bac9ad9..c838a8af 100644 --- a/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs +++ b/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs @@ -13,7 +13,7 @@ using SafeExamBrowser.Contracts.Configuration.Settings; using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.UserInterface.Browser; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; using SafeExamBrowser.Contracts.UserInterface.Windows; namespace SafeExamBrowser.Contracts.UserInterface diff --git a/SafeExamBrowser.Contracts/UserInterface/Shell/Events/ActivatorEventHandler.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/ActivatorEventHandler.cs new file mode 100644 index 00000000..6785fc7a --- /dev/null +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/ActivatorEventHandler.cs @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +namespace SafeExamBrowser.Contracts.UserInterface.Shell.Events +{ + /// + /// Event handler fired by an to control the visibility of the . + /// + public delegate void ActivatorEventHandler(); +} diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/ApplicationButtonClickedEventHandler.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/ApplicationButtonClickedEventHandler.cs similarity index 91% rename from SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/ApplicationButtonClickedEventHandler.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/Events/ApplicationButtonClickedEventHandler.cs index 089032a4..a4bf9c11 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/ApplicationButtonClickedEventHandler.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/ApplicationButtonClickedEventHandler.cs @@ -8,7 +8,7 @@ using SafeExamBrowser.Contracts.Applications; -namespace SafeExamBrowser.Contracts.UserInterface.Taskbar.Events +namespace SafeExamBrowser.Contracts.UserInterface.Shell.Events { /// /// Indicates that an has been clicked, optionally specifying the ID of the selected instance (if diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/KeyboardLayoutSelectedEventHandler.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/KeyboardLayoutSelectedEventHandler.cs similarity index 89% rename from SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/KeyboardLayoutSelectedEventHandler.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/Events/KeyboardLayoutSelectedEventHandler.cs index 2a018117..c6ecb118 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/KeyboardLayoutSelectedEventHandler.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/KeyboardLayoutSelectedEventHandler.cs @@ -8,7 +8,7 @@ using SafeExamBrowser.Contracts.SystemComponents; -namespace SafeExamBrowser.Contracts.UserInterface.Taskbar.Events +namespace SafeExamBrowser.Contracts.UserInterface.Shell.Events { /// /// Indicates that a particular has been selected by the user. diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/NotificationButtonClickedEventHandler.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/NotificationButtonClickedEventHandler.cs similarity index 88% rename from SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/NotificationButtonClickedEventHandler.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/Events/NotificationButtonClickedEventHandler.cs index f5a484c5..8fef8ab6 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/NotificationButtonClickedEventHandler.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/NotificationButtonClickedEventHandler.cs @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -namespace SafeExamBrowser.Contracts.UserInterface.Taskbar.Events +namespace SafeExamBrowser.Contracts.UserInterface.Shell.Events { /// /// Indicates that the user clicked on a in the . diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/QuitButtonClickedEventHandler.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/QuitButtonClickedEventHandler.cs similarity index 89% rename from SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/QuitButtonClickedEventHandler.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/Events/QuitButtonClickedEventHandler.cs index 175cc323..8712df75 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/QuitButtonClickedEventHandler.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/QuitButtonClickedEventHandler.cs @@ -8,7 +8,7 @@ using System.ComponentModel; -namespace SafeExamBrowser.Contracts.UserInterface.Taskbar.Events +namespace SafeExamBrowser.Contracts.UserInterface.Shell.Events { /// /// Event handler used to define the control flow when the 's quit button is clicked. diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/WirelessNetworkSelectedEventHandler.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/WirelessNetworkSelectedEventHandler.cs similarity index 89% rename from SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/WirelessNetworkSelectedEventHandler.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/Events/WirelessNetworkSelectedEventHandler.cs index aaec83f0..762f6b30 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/WirelessNetworkSelectedEventHandler.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/WirelessNetworkSelectedEventHandler.cs @@ -8,7 +8,7 @@ using SafeExamBrowser.Contracts.SystemComponents; -namespace SafeExamBrowser.Contracts.UserInterface.Taskbar.Events +namespace SafeExamBrowser.Contracts.UserInterface.Shell.Events { /// /// Indicates that a particular has been selected by the user. diff --git a/SafeExamBrowser.Contracts/UserInterface/Shell/IActionCenter.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/IActionCenter.cs new file mode 100644 index 00000000..e50baa65 --- /dev/null +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/IActionCenter.cs @@ -0,0 +1,36 @@ +/* + * 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.Contracts.UserInterface.Shell +{ + /// + /// The action center is a user interface element via which the user can access and control various aspects of the application. + /// + public interface IActionCenter + { + /// + /// Closes the action center. + /// + void Close(); + + /// + /// Makes the action center invisible. + /// + void Hide(); + + /// + /// Registers the specified activator to control the visibility of the action center. + /// + void Register(IActionCenterActivator activator); + + /// + /// Makes the action center visible. + /// + void Show(); + } +} diff --git a/SafeExamBrowser.Contracts/UserInterface/Shell/IActionCenterActivator.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/IActionCenterActivator.cs new file mode 100644 index 00000000..e59153c6 --- /dev/null +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/IActionCenterActivator.cs @@ -0,0 +1,43 @@ +/* + * 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.Contracts.UserInterface.Shell.Events; + +namespace SafeExamBrowser.Contracts.UserInterface.Shell +{ + /// + /// A module which can be used to control the visibility of the . + /// + public interface IActionCenterActivator + { + /// + /// Fired when the action center should be made visible. + /// + event ActivatorEventHandler Activate; + + /// + /// Fired when the action center should be made invisible. + /// + event ActivatorEventHandler Deactivate; + + /// + /// Fired when the action center visibility should be toggled. + /// + event ActivatorEventHandler Toggle; + + /// + /// Starts monitoring user input events. + /// + void Start(); + + /// + /// Stops monitoring user input events. + /// + void Stop(); + } +} diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/IApplicationButton.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/IApplicationButton.cs similarity index 89% rename from SafeExamBrowser.Contracts/UserInterface/Taskbar/IApplicationButton.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/IApplicationButton.cs index dc79b1a4..5d9a2ffe 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/IApplicationButton.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/IApplicationButton.cs @@ -7,9 +7,9 @@ */ using SafeExamBrowser.Contracts.Applications; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; -namespace SafeExamBrowser.Contracts.UserInterface.Taskbar +namespace SafeExamBrowser.Contracts.UserInterface.Shell { /// /// The button of a (third-party) application which can be loaded into the . diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/INotificationButton.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/INotificationButton.cs similarity index 83% rename from SafeExamBrowser.Contracts/UserInterface/Taskbar/INotificationButton.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/INotificationButton.cs index 1c1697a5..1c065c3b 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/INotificationButton.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/INotificationButton.cs @@ -6,9 +6,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; -namespace SafeExamBrowser.Contracts.UserInterface.Taskbar +namespace SafeExamBrowser.Contracts.UserInterface.Shell { /// /// The button of a notification which can be loaded into the . diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemControl.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemControl.cs similarity index 92% rename from SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemControl.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/ISystemControl.cs index 81a6b1d4..6e3f7062 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemControl.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemControl.cs @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -namespace SafeExamBrowser.Contracts.UserInterface.Taskbar +namespace SafeExamBrowser.Contracts.UserInterface.Shell { /// /// The control of a system component which can be loaded into the . diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemKeyboardLayoutControl.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemKeyboardLayoutControl.cs similarity index 87% rename from SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemKeyboardLayoutControl.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/ISystemKeyboardLayoutControl.cs index e0c723e4..2f8b84e8 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemKeyboardLayoutControl.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemKeyboardLayoutControl.cs @@ -7,9 +7,9 @@ */ using SafeExamBrowser.Contracts.SystemComponents; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; -namespace SafeExamBrowser.Contracts.UserInterface.Taskbar +namespace SafeExamBrowser.Contracts.UserInterface.Shell { /// /// The control of the keyboard layout system component. diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemPowerSupplyControl.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemPowerSupplyControl.cs similarity index 95% rename from SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemPowerSupplyControl.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/ISystemPowerSupplyControl.cs index 0198961d..294bc985 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemPowerSupplyControl.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemPowerSupplyControl.cs @@ -8,7 +8,7 @@ using SafeExamBrowser.Contracts.SystemComponents; -namespace SafeExamBrowser.Contracts.UserInterface.Taskbar +namespace SafeExamBrowser.Contracts.UserInterface.Shell { /// /// The control of the power supply system component. diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemWirelessNetworkControl.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemWirelessNetworkControl.cs similarity index 91% rename from SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemWirelessNetworkControl.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/ISystemWirelessNetworkControl.cs index ea628386..80730a3a 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemWirelessNetworkControl.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemWirelessNetworkControl.cs @@ -8,9 +8,9 @@ using System.Collections.Generic; using SafeExamBrowser.Contracts.SystemComponents; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; -namespace SafeExamBrowser.Contracts.UserInterface.Taskbar +namespace SafeExamBrowser.Contracts.UserInterface.Shell { /// /// The control of the wireless network system component. diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/ITaskbar.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/ITaskbar.cs similarity index 81% rename from SafeExamBrowser.Contracts/UserInterface/Taskbar/ITaskbar.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/ITaskbar.cs index 461e5db9..fd1b8716 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/ITaskbar.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/ITaskbar.cs @@ -6,13 +6,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; -namespace SafeExamBrowser.Contracts.UserInterface.Taskbar +namespace SafeExamBrowser.Contracts.UserInterface.Shell { /// - /// Defines the functionality of the application taskbar. The taskbar is the main user interface element via which the user can access - /// the browser, third-party applications, system controls and so on. + /// The taskbar is a user interface element via which the user can access and control various aspects of the application. /// public interface ITaskbar { @@ -55,5 +54,10 @@ namespace SafeExamBrowser.Contracts.UserInterface.Taskbar /// Moves the taskbar to the bottom of and resizes it according to the current working area. /// void InitializeBounds(); + + /// + /// Shows the taskbar. + /// + void Show(); } } diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/WindowClosingEventHandler.cs b/SafeExamBrowser.Contracts/UserInterface/Windows/Events/WindowClosingEventHandler.cs similarity index 87% rename from SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/WindowClosingEventHandler.cs rename to SafeExamBrowser.Contracts/UserInterface/Windows/Events/WindowClosingEventHandler.cs index 2e9f2ffb..3d42aa64 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Taskbar/Events/WindowClosingEventHandler.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Windows/Events/WindowClosingEventHandler.cs @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -namespace SafeExamBrowser.Contracts.UserInterface.Taskbar.Events +namespace SafeExamBrowser.Contracts.UserInterface.Windows.Events { /// /// Indicates that a window is about to be closed. diff --git a/SafeExamBrowser.Contracts/UserInterface/Windows/IWindow.cs b/SafeExamBrowser.Contracts/UserInterface/Windows/IWindow.cs index 016b51b8..b67433a5 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Windows/IWindow.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Windows/IWindow.cs @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; +using SafeExamBrowser.Contracts.UserInterface.Windows.Events; namespace SafeExamBrowser.Contracts.UserInterface.Windows { diff --git a/SafeExamBrowser.Runtime/CompositionRoot.cs b/SafeExamBrowser.Runtime/CompositionRoot.cs index 29599dac..baf3efec 100644 --- a/SafeExamBrowser.Runtime/CompositionRoot.cs +++ b/SafeExamBrowser.Runtime/CompositionRoot.cs @@ -89,7 +89,18 @@ namespace SafeExamBrowser.Runtime var bootstrapSequence = new OperationSequence(logger, bootstrapOperations); var sessionSequence = new RepeatableOperationSequence(logger, sessionOperations); - RuntimeController = new RuntimeController(appConfig, logger, messageBox, bootstrapSequence, sessionSequence, runtimeHost, serviceProxy, sessionContext, shutdown, text, uiFactory); + RuntimeController = new RuntimeController( + appConfig, + logger, + messageBox, + bootstrapSequence, + sessionSequence, + runtimeHost, + serviceProxy, + sessionContext, + shutdown, + text, + uiFactory); } internal void LogStartupInformation() @@ -126,11 +137,30 @@ namespace SafeExamBrowser.Runtime var xmlParser = new XmlParser(ModuleLogger(nameof(XmlParser))); var xmlSerializer = new XmlSerializer(ModuleLogger(nameof(XmlSerializer))); - configuration = new ConfigurationRepository(certificateStore, new HashAlgorithm(), repositoryLogger, executable.Location, programCopyright, programTitle, programVersion); + configuration = new ConfigurationRepository( + certificateStore, + new HashAlgorithm(), + repositoryLogger, + executable.Location, + programCopyright, + programTitle, + programVersion); appConfig = configuration.InitializeAppConfig(); - configuration.Register(new BinaryParser(compressor, new HashAlgorithm(), ModuleLogger(nameof(BinaryParser)), passwordEncryption, publicKeyEncryption, symmetricEncryption, xmlParser)); - configuration.Register(new BinarySerializer(compressor, ModuleLogger(nameof(BinarySerializer)), passwordEncryption, publicKeyEncryption, symmetricEncryption, xmlSerializer)); + configuration.Register(new BinaryParser( + compressor, + new HashAlgorithm(), + ModuleLogger(nameof(BinaryParser)), + passwordEncryption, + publicKeyEncryption, + symmetricEncryption, xmlParser)); + configuration.Register(new BinarySerializer( + compressor, + ModuleLogger(nameof(BinarySerializer)), + passwordEncryption, + publicKeyEncryption, + symmetricEncryption, + xmlSerializer)); configuration.Register(new XmlParser(ModuleLogger(nameof(XmlParser)))); configuration.Register(new XmlSerializer(ModuleLogger(nameof(XmlSerializer)))); configuration.Register(new FileResourceLoader(ModuleLogger(nameof(FileResourceLoader)))); diff --git a/SafeExamBrowser.SystemComponents/KeyboardLayout.cs b/SafeExamBrowser.SystemComponents/KeyboardLayout.cs index e77f8039..c3e6c93c 100644 --- a/SafeExamBrowser.SystemComponents/KeyboardLayout.cs +++ b/SafeExamBrowser.SystemComponents/KeyboardLayout.cs @@ -12,7 +12,7 @@ using System.Windows.Forms; using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.SystemComponents; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; namespace SafeExamBrowser.SystemComponents { diff --git a/SafeExamBrowser.SystemComponents/PowerSupply.cs b/SafeExamBrowser.SystemComponents/PowerSupply.cs index 24235e76..7f660a1a 100644 --- a/SafeExamBrowser.SystemComponents/PowerSupply.cs +++ b/SafeExamBrowser.SystemComponents/PowerSupply.cs @@ -11,7 +11,7 @@ using System.Timers; using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.SystemComponents; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; using PowerLineStatus = System.Windows.Forms.PowerLineStatus; using SystemInformation = System.Windows.Forms.SystemInformation; diff --git a/SafeExamBrowser.SystemComponents/WirelessNetwork.cs b/SafeExamBrowser.SystemComponents/WirelessNetwork.cs index 0cb1280a..31d519d4 100644 --- a/SafeExamBrowser.SystemComponents/WirelessNetwork.cs +++ b/SafeExamBrowser.SystemComponents/WirelessNetwork.cs @@ -13,7 +13,7 @@ using System.Timers; using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.SystemComponents; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; using SimpleWifi; using SimpleWifi.Win32; using SimpleWifi.Win32.Interop; diff --git a/SafeExamBrowser.UserInterface.Desktop/AboutWindow.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/AboutWindow.xaml.cs index 110a060d..82e2dbd4 100644 --- a/SafeExamBrowser.UserInterface.Desktop/AboutWindow.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/AboutWindow.xaml.cs @@ -10,8 +10,8 @@ using System.Windows; using System.Windows.Documents; using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.I18n; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; using SafeExamBrowser.Contracts.UserInterface.Windows; +using SafeExamBrowser.Contracts.UserInterface.Windows.Events; namespace SafeExamBrowser.UserInterface.Desktop { diff --git a/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml b/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml new file mode 100644 index 00000000..a81b676a --- /dev/null +++ b/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml.cs new file mode 100644 index 00000000..b4330287 --- /dev/null +++ b/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml.cs @@ -0,0 +1,137 @@ +/* + * 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; +using System.Windows.Media.Animation; +using SafeExamBrowser.Contracts.UserInterface.Shell; + +namespace SafeExamBrowser.UserInterface.Desktop +{ + public partial class ActionCenter : Window, IActionCenter + { + public ActionCenter() + { + InitializeComponent(); + RegisterEvents(); + } + + public new void Close() + { + Dispatcher.Invoke(base.Close); + } + + public new void Hide() + { + Dispatcher.Invoke(HideAnimated); + } + + public void Register(IActionCenterActivator activator) + { + activator.Activate += Activator_Activate; + activator.Deactivate += Activator_Deactivate; + activator.Toggle += Activator_Toggle; + } + + public new void Show() + { + Dispatcher.Invoke(ShowAnimated); + } + + private void HideAnimated() + { + var storyboard = new Storyboard(); + var animation = new DoubleAnimation + { + EasingFunction = new CircleEase { EasingMode = EasingMode.EaseOut }, + From = 0, + To = -Width, + Duration = new Duration(TimeSpan.FromMilliseconds(500)) + }; + + Storyboard.SetTarget(animation, this); + Storyboard.SetTargetProperty(animation, new PropertyPath(LeftProperty)); + + storyboard.Children.Add(animation); + storyboard.Completed += (o, args) => Dispatcher.Invoke(base.Hide); + storyboard.Begin(); + } + + private void ShowAnimated() + { + var storyboard = new Storyboard(); + var animation = new DoubleAnimation + { + EasingFunction = new CircleEase { EasingMode = EasingMode.EaseOut }, + From = -Width, + To = 0, + Duration = new Duration(TimeSpan.FromMilliseconds(500)) + }; + + Storyboard.SetTarget(animation, this); + Storyboard.SetTargetProperty(animation, new PropertyPath(LeftProperty)); + + InitializeBounds(); + base.Show(); + Activate(); + + storyboard.Children.Add(animation); + storyboard.Completed += (o, args) => Dispatcher.Invoke(Activate); + storyboard.Begin(); + } + + private void InitializeBounds() + { + Height = SystemParameters.WorkArea.Height; + Top = 0; + Left = -Width; + } + + private void RegisterEvents() + { + Deactivated += (o, args) => HideAnimated(); + } + + private void Activator_Activate() + { + Dispatcher.InvokeAsync(() => + { + if (Visibility != Visibility.Visible) + { + ShowAnimated(); + } + }); + } + + private void Activator_Deactivate() + { + Dispatcher.InvokeAsync(() => + { + if (Visibility == Visibility.Visible) + { + HideAnimated(); + } + }); + } + + private void Activator_Toggle() + { + Dispatcher.InvokeAsync(() => + { + if (Visibility != Visibility.Visible) + { + ShowAnimated(); + } + else + { + HideAnimated(); + } + }); + } + } +} diff --git a/SafeExamBrowser.UserInterface.Desktop/BrowserWindow.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/BrowserWindow.xaml.cs index 9c1c50ad..e83f333e 100644 --- a/SafeExamBrowser.UserInterface.Desktop/BrowserWindow.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/BrowserWindow.xaml.cs @@ -18,8 +18,8 @@ using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface.Browser; using SafeExamBrowser.Contracts.UserInterface.Browser.Events; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; using SafeExamBrowser.Contracts.UserInterface.Windows; +using SafeExamBrowser.Contracts.UserInterface.Windows.Events; using SafeExamBrowser.UserInterface.Desktop.Utilities; namespace SafeExamBrowser.UserInterface.Desktop @@ -117,33 +117,12 @@ namespace SafeExamBrowser.UserInterface.Desktop private void InitializeBrowserWindow(IBrowserControl browserControl) { - var originalBrush = MenuButton.Background; - if (browserControl is System.Windows.Forms.Control control) { BrowserControlHost.Child = control; } - BackwardButton.Click += (o, args) => BackwardNavigationRequested?.Invoke(); - Closing += (o, args) => closing?.Invoke(); - ForwardButton.Click += (o, args) => ForwardNavigationRequested?.Invoke(); - MenuButton.Click += (o, args) => MenuPopup.IsOpen = !MenuPopup.IsOpen; - MenuButton.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => MenuPopup.IsOpen = MenuPopup.IsMouseOver)); - MenuPopup.Closed += (o, args) => { MenuButton.Background = originalBrush; }; - MenuPopup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => MenuPopup.IsOpen = IsMouseOver)); - MenuPopup.Opened += (o, args) => { MenuButton.Background = Brushes.LightGray; }; - KeyUp += BrowserWindow_KeyUp; - ReloadButton.Click += (o, args) => ReloadRequested?.Invoke(); - UrlTextBox.GotKeyboardFocus += (o, args) => UrlTextBox.SelectAll(); - UrlTextBox.GotMouseCapture += UrlTextBox_GotMouseCapture; - UrlTextBox.LostKeyboardFocus += (o, args) => UrlTextBox.Tag = null; - UrlTextBox.LostFocus += (o, args) => UrlTextBox.Tag = null; - UrlTextBox.KeyUp += UrlTextBox_KeyUp; - UrlTextBox.MouseDoubleClick += (o, args) => UrlTextBox.SelectAll(); - ZoomInButton.Click += (o, args) => ZoomInRequested?.Invoke(); - ZoomOutButton.Click += (o, args) => ZoomOutRequested?.Invoke(); - ZoomResetButton.Click += (o, args) => ZoomResetRequested?.Invoke(); - + RegisterEvents(); ApplySettings(); LoadIcons(); LoadText(); @@ -174,6 +153,31 @@ namespace SafeExamBrowser.UserInterface.Desktop } } + private void RegisterEvents() + { + var originalBrush = MenuButton.Background; + + BackwardButton.Click += (o, args) => BackwardNavigationRequested?.Invoke(); + Closing += (o, args) => closing?.Invoke(); + ForwardButton.Click += (o, args) => ForwardNavigationRequested?.Invoke(); + MenuButton.Click += (o, args) => MenuPopup.IsOpen = !MenuPopup.IsOpen; + MenuButton.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => MenuPopup.IsOpen = MenuPopup.IsMouseOver)); + MenuPopup.Closed += (o, args) => { MenuButton.Background = originalBrush; }; + MenuPopup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => MenuPopup.IsOpen = IsMouseOver)); + MenuPopup.Opened += (o, args) => { MenuButton.Background = Brushes.LightGray; }; + KeyUp += BrowserWindow_KeyUp; + ReloadButton.Click += (o, args) => ReloadRequested?.Invoke(); + UrlTextBox.GotKeyboardFocus += (o, args) => UrlTextBox.SelectAll(); + UrlTextBox.GotMouseCapture += UrlTextBox_GotMouseCapture; + UrlTextBox.LostKeyboardFocus += (o, args) => UrlTextBox.Tag = null; + UrlTextBox.LostFocus += (o, args) => UrlTextBox.Tag = null; + UrlTextBox.KeyUp += UrlTextBox_KeyUp; + UrlTextBox.MouseDoubleClick += (o, args) => UrlTextBox.SelectAll(); + ZoomInButton.Click += (o, args) => ZoomInRequested?.Invoke(); + ZoomOutButton.Click += (o, args) => ZoomOutRequested?.Invoke(); + ZoomResetButton.Click += (o, args) => ZoomResetRequested?.Invoke(); + } + private void ApplySettings() { if (isMainWindow) diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationButton.xaml.cs index 5a3baf0b..bd25ff78 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationButton.xaml.cs @@ -14,8 +14,8 @@ using System.Windows.Controls; using System.Windows.Media; using System.Windows.Threading; using SafeExamBrowser.Contracts.Applications; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; +using SafeExamBrowser.Contracts.UserInterface.Shell; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; using SafeExamBrowser.UserInterface.Desktop.Utilities; namespace SafeExamBrowser.UserInterface.Desktop.Controls diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationInstanceButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationInstanceButton.xaml.cs index ff183558..6d9b351b 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationInstanceButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationInstanceButton.xaml.cs @@ -10,7 +10,7 @@ using System.Windows; using System.Windows.Controls; using SafeExamBrowser.Contracts.Applications; using SafeExamBrowser.Contracts.Core; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; using SafeExamBrowser.UserInterface.Desktop.Utilities; namespace SafeExamBrowser.UserInterface.Desktop.Controls diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/KeyboardLayoutControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/KeyboardLayoutControl.xaml.cs index c5ec1a53..9906b210 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/KeyboardLayoutControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/KeyboardLayoutControl.xaml.cs @@ -12,8 +12,8 @@ using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Media; using SafeExamBrowser.Contracts.SystemComponents; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; +using SafeExamBrowser.Contracts.UserInterface.Shell; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; namespace SafeExamBrowser.UserInterface.Desktop.Controls { diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/NotificationButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/NotificationButton.xaml.cs index e31db8d1..3c336fa8 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/NotificationButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/NotificationButton.xaml.cs @@ -9,8 +9,8 @@ using System.Windows; using System.Windows.Controls; using SafeExamBrowser.Contracts.Client; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; +using SafeExamBrowser.Contracts.UserInterface.Shell; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; using SafeExamBrowser.UserInterface.Desktop.Utilities; namespace SafeExamBrowser.UserInterface.Desktop.Controls diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/PowerSupplyControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/PowerSupplyControl.xaml.cs index 8d21ad91..74c6f8ea 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/PowerSupplyControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/PowerSupplyControl.xaml.cs @@ -11,7 +11,7 @@ using System.Windows.Controls; using System.Windows.Media; using System.Windows.Threading; using SafeExamBrowser.Contracts.SystemComponents; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; namespace SafeExamBrowser.UserInterface.Desktop.Controls { diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/QuitButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/QuitButton.xaml.cs index 2439ade3..54f6dd63 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/QuitButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/QuitButton.xaml.cs @@ -10,7 +10,7 @@ using System; using System.ComponentModel; using System.Windows; using System.Windows.Controls; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; using SafeExamBrowser.UserInterface.Desktop.Utilities; namespace SafeExamBrowser.UserInterface.Desktop.Controls diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/WirelessNetworkControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/WirelessNetworkControl.xaml.cs index 035425a2..6dce0dc2 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/WirelessNetworkControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/WirelessNetworkControl.xaml.cs @@ -14,8 +14,8 @@ using System.Windows.Controls; using System.Windows.Media; using FontAwesome.WPF; using SafeExamBrowser.Contracts.SystemComponents; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; +using SafeExamBrowser.Contracts.UserInterface.Shell; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; using SafeExamBrowser.UserInterface.Desktop.Utilities; namespace SafeExamBrowser.UserInterface.Desktop.Controls diff --git a/SafeExamBrowser.UserInterface.Desktop/LogWindow.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/LogWindow.xaml.cs index 1a297548..1666394c 100644 --- a/SafeExamBrowser.UserInterface.Desktop/LogWindow.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/LogWindow.xaml.cs @@ -10,8 +10,8 @@ using System.ComponentModel; using System.Windows; using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; using SafeExamBrowser.Contracts.UserInterface.Windows; +using SafeExamBrowser.Contracts.UserInterface.Windows.Events; using SafeExamBrowser.UserInterface.Desktop.ViewModels; namespace SafeExamBrowser.UserInterface.Desktop diff --git a/SafeExamBrowser.UserInterface.Desktop/PasswordDialog.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/PasswordDialog.xaml.cs index 51628563..2dcec636 100644 --- a/SafeExamBrowser.UserInterface.Desktop/PasswordDialog.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/PasswordDialog.xaml.cs @@ -9,8 +9,8 @@ using System.Windows; using System.Windows.Input; using SafeExamBrowser.Contracts.I18n; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; using SafeExamBrowser.Contracts.UserInterface.Windows; +using SafeExamBrowser.Contracts.UserInterface.Windows.Events; namespace SafeExamBrowser.UserInterface.Desktop { diff --git a/SafeExamBrowser.UserInterface.Desktop/RuntimeWindow.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/RuntimeWindow.xaml.cs index 3a72ddf3..914186f7 100644 --- a/SafeExamBrowser.UserInterface.Desktop/RuntimeWindow.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/RuntimeWindow.xaml.cs @@ -11,8 +11,8 @@ using System.Windows.Documents; using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; using SafeExamBrowser.Contracts.UserInterface.Windows; +using SafeExamBrowser.Contracts.UserInterface.Windows.Events; using SafeExamBrowser.UserInterface.Desktop.ViewModels; namespace SafeExamBrowser.UserInterface.Desktop diff --git a/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj b/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj index fba1440e..6bfcfe28 100644 --- a/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj +++ b/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj @@ -68,6 +68,9 @@ AboutWindow.xaml + + ActionCenter.xaml + BrowserWindow.xaml @@ -126,6 +129,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/SafeExamBrowser.UserInterface.Desktop/SplashScreen.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/SplashScreen.xaml.cs index cc3ce4b9..550e6b95 100644 --- a/SafeExamBrowser.UserInterface.Desktop/SplashScreen.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/SplashScreen.xaml.cs @@ -10,8 +10,8 @@ using System.Windows; using System.Windows.Documents; using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.I18n; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; using SafeExamBrowser.Contracts.UserInterface.Windows; +using SafeExamBrowser.Contracts.UserInterface.Windows.Events; using SafeExamBrowser.UserInterface.Desktop.ViewModels; namespace SafeExamBrowser.UserInterface.Desktop diff --git a/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml b/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml index cc5553db..5e976ef7 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml @@ -5,9 +5,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls" xmlns:s="clr-namespace:System;assembly=mscorlib" - mc:Ignorable="d" - Title="Taskbar" Background="#FFF0F0F0" Height="40" Width="750" WindowStyle="None" Topmost="True" Visibility="Visible" - ResizeMode="NoResize" Icon="./Images/SafeExamBrowser.ico"> + mc:Ignorable="d" Title="Taskbar" Background="#FFF0F0F0" Height="40" Width="750" WindowStyle="None" Topmost="True" ResizeMode="NoResize" Icon="./Images/SafeExamBrowser.ico"> diff --git a/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml.cs index 0c65c7f3..e922d75e 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml.cs @@ -9,8 +9,8 @@ using System.ComponentModel; using System.Windows; using SafeExamBrowser.Contracts.Logging; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; -using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events; +using SafeExamBrowser.Contracts.UserInterface.Shell; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; using SafeExamBrowser.UserInterface.Desktop.Utilities; namespace SafeExamBrowser.UserInterface.Desktop @@ -94,6 +94,11 @@ namespace SafeExamBrowser.UserInterface.Desktop }); } + public new void Show() + { + Dispatcher.Invoke(base.Show); + } + private void QuitButton_Clicked(CancelEventArgs args) { QuitButtonClicked?.Invoke(args); diff --git a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs index 2cb02c55..387318d0 100644 --- a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs @@ -18,7 +18,7 @@ using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface.Browser; -using SafeExamBrowser.Contracts.UserInterface.Taskbar; +using SafeExamBrowser.Contracts.UserInterface.Shell; using SafeExamBrowser.Contracts.UserInterface.Windows; using SafeExamBrowser.UserInterface.Desktop.Controls; diff --git a/SafeExamBrowser.WindowsApi/Constants/ACCESS_MASK.cs b/SafeExamBrowser.WindowsApi/Constants/AccessMask.cs similarity index 96% rename from SafeExamBrowser.WindowsApi/Constants/ACCESS_MASK.cs rename to SafeExamBrowser.WindowsApi/Constants/AccessMask.cs index 38a9f2ec..fb385ffb 100644 --- a/SafeExamBrowser.WindowsApi/Constants/ACCESS_MASK.cs +++ b/SafeExamBrowser.WindowsApi/Constants/AccessMask.cs @@ -14,7 +14,7 @@ namespace SafeExamBrowser.WindowsApi.Constants /// See https://docs.microsoft.com/de-de/windows/desktop/SecAuthZ/access-mask /// [Flags] - internal enum ACCESS_MASK : uint + internal enum AccessMask : uint { DESKTOP_NONE = 0, DESKTOP_READOBJECTS = 0x0001, diff --git a/SafeExamBrowser.WindowsApi/Constants/Constant.cs b/SafeExamBrowser.WindowsApi/Constants/Constant.cs index a563a7b8..30afdb97 100644 --- a/SafeExamBrowser.WindowsApi/Constants/Constant.cs +++ b/SafeExamBrowser.WindowsApi/Constants/Constant.cs @@ -32,6 +32,20 @@ namespace SafeExamBrowser.WindowsApi.Constants /// internal const int MIN_ALL = 419; + /// + /// Bitmask to evaluate the origin of a mouse event. + /// + /// See https://docs.microsoft.com/en-us/windows/desktop/tablet/system-events-and-mouse-messages. + /// + internal const uint MOUSEEVENTF_MASK = 0xFFFFFF00; + + /// + /// The constant for a mouse event generated by a touch interface. + /// + /// See https://docs.microsoft.com/en-us/windows/desktop/tablet/system-events-and-mouse-messages. + /// + internal const uint MOUSEEVENTF_FROMTOUCH = 0xFF515700; + /// /// Specifies the default priority class for processes, i.e. a process with no special scheduling needs. /// diff --git a/SafeExamBrowser.WindowsApi/Constants/VirtualKeyCode.cs b/SafeExamBrowser.WindowsApi/Constants/VirtualKeyCode.cs new file mode 100644 index 00000000..14adb28d --- /dev/null +++ b/SafeExamBrowser.WindowsApi/Constants/VirtualKeyCode.cs @@ -0,0 +1,24 @@ +/* + * 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.Constants +{ + /// + /// See https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes. + /// + internal enum VirtualKeyCode + { + A = 0x41, + Delete = 0x2E, + LeftAlt = 0xA4, + LeftControl = 0xA2, + LeftWindows = 0x5B, + RightAlt = 0xA5, + RightControl = 0xA3 + } +} diff --git a/SafeExamBrowser.WindowsApi/Delegates/HookDelegate.cs b/SafeExamBrowser.WindowsApi/Delegates/HookDelegate.cs index cf8d31c1..a49cd09d 100644 --- a/SafeExamBrowser.WindowsApi/Delegates/HookDelegate.cs +++ b/SafeExamBrowser.WindowsApi/Delegates/HookDelegate.cs @@ -13,5 +13,5 @@ namespace SafeExamBrowser.WindowsApi.Delegates /// /// See https://docs.microsoft.com/de-de/windows/desktop/api/winuser/nc-winuser-hookproc /// - internal delegate IntPtr HookDelegate(int code, IntPtr wParam, IntPtr lParam); + internal delegate IntPtr HookDelegate(int nCode, IntPtr wParam, IntPtr lParam); } diff --git a/SafeExamBrowser.WindowsApi/DesktopFactory.cs b/SafeExamBrowser.WindowsApi/DesktopFactory.cs index f836a165..58b335f9 100644 --- a/SafeExamBrowser.WindowsApi/DesktopFactory.cs +++ b/SafeExamBrowser.WindowsApi/DesktopFactory.cs @@ -28,7 +28,7 @@ namespace SafeExamBrowser.WindowsApi { logger.Debug($"Attempting to create new desktop '{name}'..."); - var handle = User32.CreateDesktop(name, IntPtr.Zero, IntPtr.Zero, 0, (uint) ACCESS_MASK.GENERIC_ALL, IntPtr.Zero); + var handle = User32.CreateDesktop(name, IntPtr.Zero, IntPtr.Zero, 0, (uint) AccessMask.GENERIC_ALL, IntPtr.Zero); if (handle == IntPtr.Zero) { diff --git a/SafeExamBrowser.WindowsApi/KeyboardActivator.cs b/SafeExamBrowser.WindowsApi/KeyboardActivator.cs new file mode 100644 index 00000000..afbd748c --- /dev/null +++ b/SafeExamBrowser.WindowsApi/KeyboardActivator.cs @@ -0,0 +1,110 @@ +/* + * 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.Contracts.Logging; +using SafeExamBrowser.Contracts.UserInterface.Shell; +using SafeExamBrowser.Contracts.UserInterface.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; + private IntPtr handle; + private HookDelegate hookDelegate; + private ILogger logger; + + public event ActivatorEventHandler Activate { add { } remove { } } + public event ActivatorEventHandler Deactivate { add { } remove { } } + public event ActivatorEventHandler Toggle; + + public KeyboardActivator(ILogger logger) + { + this.logger = logger; + } + + 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 CallbackOnCollectedDelegate 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) + { + 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."); + Toggle?.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; + } + } +} diff --git a/SafeExamBrowser.WindowsApi/Monitoring/KeyboardHook.cs b/SafeExamBrowser.WindowsApi/Monitoring/KeyboardHook.cs index a7391a18..40c34a69 100644 --- a/SafeExamBrowser.WindowsApi/Monitoring/KeyboardHook.cs +++ b/SafeExamBrowser.WindowsApi/Monitoring/KeyboardHook.cs @@ -17,12 +17,6 @@ namespace SafeExamBrowser.WindowsApi.Monitoring { internal class KeyboardHook { - private const int LEFT_CTRL = 162; - private const int RIGHT_CTRL = 163; - private const int LEFT_ALT = 164; - private const int RIGHT_ALT = 165; - private const int DELETE = 46; - private bool altPressed, ctrlPressed; private HookDelegate hookDelegate; @@ -40,7 +34,7 @@ namespace SafeExamBrowser.WindowsApi.Monitoring var module = process.MainModule; var moduleHandle = Kernel32.GetModuleHandle(module.ModuleName); - // IMORTANT: + // 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 CallbackOnCollectedDelegate error and subsequent application crash! hookDelegate = new HookDelegate(LowLevelKeyboardProc); @@ -108,16 +102,16 @@ namespace SafeExamBrowser.WindowsApi.Monitoring { var keyCode = keyData.KeyCode; - if (keyCode == LEFT_CTRL || keyCode == RIGHT_CTRL) + if (keyCode == (uint) VirtualKeyCode.LeftControl || keyCode == (uint) VirtualKeyCode.RightControl) { ctrlPressed = IsPressed(wParam); } - else if (keyCode == LEFT_ALT || keyCode == RIGHT_ALT) + else if (keyCode == (uint) VirtualKeyCode.LeftAlt || keyCode == (uint) VirtualKeyCode.RightAlt) { altPressed = IsPressed(wParam); } - if (ctrlPressed && altPressed && keyCode == DELETE) + if (ctrlPressed && altPressed && keyCode == (uint) VirtualKeyCode.Delete) { // When the Secure Attention Sequence is pressed, the WM_KEYUP / WM_SYSKEYUP messages for CTRL and ALT get lost... ctrlPressed = false; diff --git a/SafeExamBrowser.WindowsApi/Monitoring/MouseHook.cs b/SafeExamBrowser.WindowsApi/Monitoring/MouseHook.cs index f04794f0..f6f459e1 100644 --- a/SafeExamBrowser.WindowsApi/Monitoring/MouseHook.cs +++ b/SafeExamBrowser.WindowsApi/Monitoring/MouseHook.cs @@ -33,7 +33,7 @@ namespace SafeExamBrowser.WindowsApi.Monitoring var module = process.MainModule; var moduleHandle = Kernel32.GetModuleHandle(module.ModuleName); - // IMORTANT: + // 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 CallbackOnCollectedDelegate error and subsequent application crash! hookDelegate = new HookDelegate(LowLevelMouseProc); diff --git a/SafeExamBrowser.WindowsApi/Monitoring/SystemHook.cs b/SafeExamBrowser.WindowsApi/Monitoring/SystemHook.cs index 587c388d..26460a47 100644 --- a/SafeExamBrowser.WindowsApi/Monitoring/SystemHook.cs +++ b/SafeExamBrowser.WindowsApi/Monitoring/SystemHook.cs @@ -36,7 +36,7 @@ namespace SafeExamBrowser.WindowsApi.Monitoring internal void Attach() { - // IMORTANT: + // 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 CallbackOnCollectedDelegate error and subsequent application crash! eventDelegate = new EventDelegate(LowLevelSystemProc); diff --git a/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj b/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj index b9df673a..47eb3bb3 100644 --- a/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj +++ b/SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj @@ -54,6 +54,7 @@ + @@ -61,11 +62,13 @@ + - + + diff --git a/SafeExamBrowser.WindowsApi/TouchActivator.cs b/SafeExamBrowser.WindowsApi/TouchActivator.cs new file mode 100644 index 00000000..bbdf737f --- /dev/null +++ b/SafeExamBrowser.WindowsApi/TouchActivator.cs @@ -0,0 +1,121 @@ +/* + * 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.Contracts.Logging; +using SafeExamBrowser.Contracts.UserInterface.Shell; +using SafeExamBrowser.Contracts.UserInterface.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; + private ILogger logger; + + public event ActivatorEventHandler Activate; + public event ActivatorEventHandler Deactivate { add { } remove { } } + public event ActivatorEventHandler Toggle { add { } remove { } } + + public TouchActivator(ILogger logger) + { + this.logger = logger; + } + + 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 CallbackOnCollectedDelegate 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 && !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; + + if (isTouch) + { + if (message == Constant.WM_LBUTTONUP) + { + isDown = false; + } + + if (message == Constant.WM_LBUTTONDOWN && 0 < mouseData.Point.X && mouseData.Point.X < 50) + { + 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); + + if (isDown && position.X > 200) + { + logger.Debug("Detected activation gesture for action center."); + Activate?.Invoke(); + } + } + + private bool Ignore(int wParam) + { + // For performance reasons, ignore mouse movement and wheel rotation... + return wParam == Constant.WM_MOUSEMOVE || wParam == Constant.WM_MOUSEWHEEL; + } + } +} diff --git a/SafeExamBrowser.WindowsApi/User32.cs b/SafeExamBrowser.WindowsApi/User32.cs index 9426836d..1234e1a4 100644 --- a/SafeExamBrowser.WindowsApi/User32.cs +++ b/SafeExamBrowser.WindowsApi/User32.cs @@ -48,6 +48,9 @@ namespace SafeExamBrowser.WindowsApi [DllImport("user32.dll", SetLastError = true)] internal static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + [DllImport("user32.dll", SetLastError = true)] + internal static extern bool GetCursorPos(ref POINT pt); + [DllImport("user32.dll", SetLastError = true)] internal static extern IntPtr GetThreadDesktop(int dwThreadId);