diff --git a/SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs index c6d58ca9..0782e18e 100644 --- a/SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs @@ -15,6 +15,7 @@ using SafeExamBrowser.Configuration.Contracts.Settings; using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.SystemComponents.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.Shell; using SafeExamBrowser.WindowsApi.Contracts; @@ -32,11 +33,11 @@ namespace SafeExamBrowser.Client.UnitTests.Operations private Mock terminationActivator; private Mock aboutInfo; private Mock aboutController; + private Mock keyboard; private Mock logInfo; private Mock logController; // TODO //private Mock> audio; - //private Mock> keyboardLayout; //private Mock> powerSupply; //private Mock> wirelessNetwork; private Mock systemInfo; @@ -55,11 +56,11 @@ namespace SafeExamBrowser.Client.UnitTests.Operations logger = new Mock(); aboutInfo = new Mock(); aboutController = new Mock(); + keyboard = new Mock(); logInfo = new Mock(); logController = new Mock(); // TODO //audio = new Mock>(); - //keyboardLayout = new Mock>(); //powerSupply = new Mock>(); //wirelessNetwork = new Mock>(); systemInfo = new Mock(); @@ -78,11 +79,11 @@ namespace SafeExamBrowser.Client.UnitTests.Operations logger.Object, aboutInfo.Object, aboutController.Object, + keyboard.Object, logInfo.Object, logController.Object, // TODO //audio.Object, - //keyboardLayout.Object, //powerSupply.Object, //wirelessNetwork.Object, systemInfo.Object, @@ -196,7 +197,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations systemInfo.SetupGet(s => s.HasBattery).Returns(true); uiFactory.Setup(f => f.CreateAudioControl(It.IsAny())).Returns(new Mock().Object); - uiFactory.Setup(f => f.CreateKeyboardLayoutControl(It.IsAny())).Returns(new Mock().Object); + uiFactory.Setup(f => f.CreateKeyboardLayoutControl(It.IsAny(), It.IsAny())).Returns(new Mock().Object); uiFactory.Setup(f => f.CreatePowerSupplyControl(It.IsAny())).Returns(new Mock().Object); uiFactory.Setup(f => f.CreateWirelessNetworkControl(It.IsAny())).Returns(new Mock().Object); @@ -204,17 +205,11 @@ namespace SafeExamBrowser.Client.UnitTests.Operations // TODO //audio.Verify(a => a.Initialize(), Times.Once); - //keyboardLayout.Verify(k => k.Initialize(), Times.Once); //powerSupply.Verify(p => p.Initialize(), Times.Once); //wirelessNetwork.Verify(w => w.Initialize(), Times.Once); - actionCenter.Verify(a => a.AddSystemControl(It.IsAny()), Times.Once); - actionCenter.Verify(a => a.AddSystemControl(It.IsAny()), Times.Once); - actionCenter.Verify(a => a.AddSystemControl(It.IsAny()), Times.Once); - actionCenter.Verify(a => a.AddSystemControl(It.IsAny()), Times.Once); - taskbar.Verify(t => t.AddSystemControl(It.IsAny()), Times.Once); - taskbar.Verify(t => t.AddSystemControl(It.IsAny()), Times.Once); - taskbar.Verify(t => t.AddSystemControl(It.IsAny()), Times.Once); - taskbar.Verify(t => t.AddSystemControl(It.IsAny()), Times.Once); + keyboard.Verify(k => k.Initialize(), Times.Once); + actionCenter.Verify(a => a.AddSystemControl(It.IsAny()), Times.Exactly(4)); + taskbar.Verify(t => t.AddSystemControl(It.IsAny()), Times.Exactly(4)); } [TestMethod] @@ -231,7 +226,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations systemInfo.SetupGet(s => s.HasBattery).Returns(false); uiFactory.Setup(f => f.CreateAudioControl(It.IsAny())).Returns(new Mock().Object); - uiFactory.Setup(f => f.CreateKeyboardLayoutControl(It.IsAny())).Returns(new Mock().Object); + uiFactory.Setup(f => f.CreateKeyboardLayoutControl(It.IsAny(), It.IsAny())).Returns(new Mock().Object); uiFactory.Setup(f => f.CreatePowerSupplyControl(It.IsAny())).Returns(new Mock().Object); uiFactory.Setup(f => f.CreateWirelessNetworkControl(It.IsAny())).Returns(new Mock().Object); @@ -239,17 +234,11 @@ namespace SafeExamBrowser.Client.UnitTests.Operations // TODO //audio.Verify(a => a.Initialize(), Times.Once); - //keyboardLayout.Verify(k => k.Initialize(), Times.Once); //powerSupply.Verify(p => p.Initialize(), Times.Once); //wirelessNetwork.Verify(w => w.Initialize(), Times.Once); - actionCenter.Verify(a => a.AddSystemControl(It.IsAny()), Times.Never); - actionCenter.Verify(a => a.AddSystemControl(It.IsAny()), Times.Never); - actionCenter.Verify(a => a.AddSystemControl(It.IsAny()), Times.Never); - actionCenter.Verify(a => a.AddSystemControl(It.IsAny()), Times.Never); - taskbar.Verify(t => t.AddSystemControl(It.IsAny()), Times.Never); - taskbar.Verify(t => t.AddSystemControl(It.IsAny()), Times.Never); - taskbar.Verify(t => t.AddSystemControl(It.IsAny()), Times.Never); - taskbar.Verify(t => t.AddSystemControl(It.IsAny()), Times.Never); + keyboard.Verify(k => k.Initialize(), Times.Once); + actionCenter.Verify(a => a.AddSystemControl(It.IsAny()), Times.Never); + taskbar.Verify(t => t.AddSystemControl(It.IsAny()), Times.Never); } [TestMethod] @@ -304,7 +293,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations logController.Verify(c => c.Terminate(), Times.Once); // TODO //audio.Verify(a => a.Terminate(), Times.Once); - //keyboardLayout.Verify(k => k.Terminate(), Times.Once); + keyboard.Verify(k => k.Terminate(), Times.Once); //powerSupply.Verify(p => p.Terminate(), Times.Once); //wirelessNetwork.Verify(w => w.Terminate(), Times.Once); } diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index 707421b2..a2293e21 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -256,7 +256,7 @@ namespace SafeExamBrowser.Client var aboutInfo = new AboutNotificationInfo(text); var aboutController = new AboutNotificationController(configuration.AppConfig, uiFactory); var audio = new Audio(configuration.Settings.Audio, new ModuleLogger(logger, nameof(Audio)), text); - var keyboardLayout = new KeyboardLayout(new ModuleLogger(logger, nameof(KeyboardLayout)), text); + var keyboard = new Keyboard(new ModuleLogger(logger, nameof(Keyboard)), text); var logInfo = new LogNotificationInfo(text); var logController = new LogNotificationController(logger, uiFactory); var powerSupply = new PowerSupply(new ModuleLogger(logger, nameof(PowerSupply)), text); @@ -273,11 +273,11 @@ namespace SafeExamBrowser.Client logger, aboutInfo, aboutController, + keyboard, logInfo, logController, // TODO //audio, - //keyboardLayout, //powerSupply, //wirelessNetwork, systemInfo, diff --git a/SafeExamBrowser.Client/Operations/ShellOperation.cs b/SafeExamBrowser.Client/Operations/ShellOperation.cs index dcea5638..3aaa91bf 100644 --- a/SafeExamBrowser.Client/Operations/ShellOperation.cs +++ b/SafeExamBrowser.Client/Operations/ShellOperation.cs @@ -14,6 +14,7 @@ using SafeExamBrowser.Core.Contracts.OperationModel.Events; using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.SystemComponents.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.Shell; using SafeExamBrowser.WindowsApi.Contracts; @@ -28,10 +29,10 @@ namespace SafeExamBrowser.Client.Operations private ILogger logger; private INotificationInfo aboutInfo; private INotificationController aboutController; + private IKeyboard keyboard; private INotificationInfo logInfo; private INotificationController logController; // TODO private ISystemComponent audio; - // TODO private ISystemComponent keyboardLayout; // TODO private ISystemComponent powerSupply; // TODO private ISystemComponent wirelessNetwork; private ISystemInfo systemInfo; @@ -51,10 +52,10 @@ namespace SafeExamBrowser.Client.Operations ILogger logger, INotificationInfo aboutInfo, INotificationController aboutController, + IKeyboard keyboard, INotificationInfo logInfo, INotificationController logController, - // TODO ISystemComponent audio, - // TODO ISystemComponent keyboardLayout, + // TODO ISystemComponent audio, // TODO ISystemComponent powerSupply, // TODO ISystemComponent wirelessNetwork, ISystemInfo systemInfo, @@ -69,11 +70,11 @@ namespace SafeExamBrowser.Client.Operations this.actionCenter = actionCenter; this.activators = activators; this.actionCenterSettings = actionCenterSettings; + this.keyboard = keyboard; this.logger = logger; this.logInfo = logInfo; this.logController = logController; // TODO this.audio = audio; - // TODO this.keyboardLayout = keyboardLayout; // TODO this.powerSupply = powerSupply; this.systemInfo = systemInfo; this.taskbarSettings = taskbarSettings; @@ -169,7 +170,7 @@ namespace SafeExamBrowser.Client.Operations { // TODO //audio.Initialize(); - //keyboardLayout.Initialize(); + keyboard.Initialize(); //powerSupply.Initialize(); //wirelessNetwork.Initialize(); } @@ -254,10 +255,7 @@ namespace SafeExamBrowser.Client.Operations { if (actionCenterSettings.ShowKeyboardLayout) { - var control = uiFactory.CreateKeyboardLayoutControl(Location.ActionCenter); - - // TODO keyboardLayout.Register(control); - actionCenter.AddSystemControl(control); + actionCenter.AddSystemControl(uiFactory.CreateKeyboardLayoutControl(keyboard, Location.ActionCenter)); } } @@ -265,10 +263,7 @@ namespace SafeExamBrowser.Client.Operations { if (taskbarSettings.ShowKeyboardLayout) { - var control = uiFactory.CreateKeyboardLayoutControl(Location.Taskbar); - - // TODO keyboardLayout.Register(control); - taskbar.AddSystemControl(control); + taskbar.AddSystemControl(uiFactory.CreateKeyboardLayoutControl(keyboard, Location.Taskbar)); } } @@ -339,9 +334,9 @@ namespace SafeExamBrowser.Client.Operations { // TODO //audio.Terminate(); - //keyboardLayout.Terminate(); //powerSupply.Terminate(); //wirelessNetwork.Terminate(); + keyboard.Terminate(); } } } diff --git a/SafeExamBrowser.SystemComponents.Contracts/ISystemComponent.cs b/SafeExamBrowser.SystemComponents.Contracts/ISystemComponent.cs index 9ed69a80..67ff5600 100644 --- a/SafeExamBrowser.SystemComponents.Contracts/ISystemComponent.cs +++ b/SafeExamBrowser.SystemComponents.Contracts/ISystemComponent.cs @@ -9,22 +9,15 @@ namespace SafeExamBrowser.SystemComponents.Contracts { /// - /// Defines the functionality of a system component (e.g. the power supply). Each system component can get multiple - /// assigned, which in turn allow the user to interact with or get information about the underlying system component. + /// Defines the functionality of a system component (e.g. the power supply). /// - public interface ISystemComponent// TODO where TControl : ISystemControl + public interface ISystemComponent { /// /// Initializes the resources and operations of the component. /// void Initialize(); - // TODO - ///// - ///// Registers a system control which will be loaded into shell. - ///// - //void Register(TControl control); - /// /// Instructs the component to stop any running operations and releases all used resources. /// diff --git a/SafeExamBrowser.UserInterface.Contracts/Shell/Events/KeyboardLayoutSelectedEventHandler.cs b/SafeExamBrowser.SystemComponents.Contracts/Keyboard/Events/KeyboardLayoutChangedEventHandler.cs similarity index 60% rename from SafeExamBrowser.UserInterface.Contracts/Shell/Events/KeyboardLayoutSelectedEventHandler.cs rename to SafeExamBrowser.SystemComponents.Contracts/Keyboard/Events/KeyboardLayoutChangedEventHandler.cs index 39f1527f..59b93716 100644 --- a/SafeExamBrowser.UserInterface.Contracts/Shell/Events/KeyboardLayoutSelectedEventHandler.cs +++ b/SafeExamBrowser.SystemComponents.Contracts/Keyboard/Events/KeyboardLayoutChangedEventHandler.cs @@ -6,12 +6,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System; - -namespace SafeExamBrowser.UserInterface.Contracts.Shell.Events +namespace SafeExamBrowser.SystemComponents.Contracts.Keyboard.Events { /// - /// Indicates that a keyboard layout has been selected by the user. + /// Indicates that the active keyboard layout has changed. /// - public delegate void KeyboardLayoutSelectedEventHandler(Guid id); + public delegate void KeyboardLayoutChangedEventHandler(IKeyboardLayout layout); } diff --git a/SafeExamBrowser.SystemComponents.Contracts/Keyboard/IKeyboard.cs b/SafeExamBrowser.SystemComponents.Contracts/Keyboard/IKeyboard.cs new file mode 100644 index 00000000..f622777b --- /dev/null +++ b/SafeExamBrowser.SystemComponents.Contracts/Keyboard/IKeyboard.cs @@ -0,0 +1,35 @@ +/* + * 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.Collections.Generic; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard.Events; + +namespace SafeExamBrowser.SystemComponents.Contracts.Keyboard +{ + /// + /// Defines the functionality of the keyboard system component. + /// + public interface IKeyboard : ISystemComponent + { + /// + /// Fired when the active keyboard layout changed. + /// + event KeyboardLayoutChangedEventHandler LayoutChanged; + + /// + /// Activates the keyboard layout with the given identifier. + /// + void ActivateLayout(Guid id); + + /// + /// Gets all currently available keyboard layouts. + /// + IEnumerable GetLayouts(); + } +} diff --git a/SafeExamBrowser.SystemComponents.Contracts/IKeyboardLayout.cs b/SafeExamBrowser.SystemComponents.Contracts/Keyboard/IKeyboardLayout.cs similarity index 80% rename from SafeExamBrowser.SystemComponents.Contracts/IKeyboardLayout.cs rename to SafeExamBrowser.SystemComponents.Contracts/Keyboard/IKeyboardLayout.cs index 3d50675c..0747aa8c 100644 --- a/SafeExamBrowser.SystemComponents.Contracts/IKeyboardLayout.cs +++ b/SafeExamBrowser.SystemComponents.Contracts/Keyboard/IKeyboardLayout.cs @@ -8,7 +8,7 @@ using System; -namespace SafeExamBrowser.SystemComponents.Contracts +namespace SafeExamBrowser.SystemComponents.Contracts.Keyboard { /// /// Defines a keyboard layout which can be loaded by the application. @@ -25,6 +25,11 @@ namespace SafeExamBrowser.SystemComponents.Contracts /// Guid Id { get; } + /// + /// Indicates whether this is the currently active keyboard layout. + /// + bool IsCurrent { get; } + /// /// The name of this keyboard layout. /// diff --git a/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj b/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj index 3e6bf405..a43f50e9 100644 --- a/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj +++ b/SafeExamBrowser.SystemComponents.Contracts/SafeExamBrowser.SystemComponents.Contracts.csproj @@ -54,7 +54,9 @@ - + + + @@ -63,5 +65,6 @@ + \ No newline at end of file diff --git a/SafeExamBrowser.SystemComponents/Keyboard.cs b/SafeExamBrowser.SystemComponents/Keyboard.cs new file mode 100644 index 00000000..fec56ef9 --- /dev/null +++ b/SafeExamBrowser.SystemComponents/Keyboard.cs @@ -0,0 +1,103 @@ +/* + * 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.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Windows.Input; +using SafeExamBrowser.I18n.Contracts; +using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard.Events; + +namespace SafeExamBrowser.SystemComponents +{ + public class Keyboard : IKeyboard + { + private IList layouts; + private ILogger logger; + private CultureInfo originalLanguage; + private IText text; + + public event KeyboardLayoutChangedEventHandler LayoutChanged; + + public Keyboard(ILogger logger, IText text) + { + this.layouts = new List(); + this.logger = logger; + this.text = text; + } + + public void ActivateLayout(Guid layoutId) + { + var layout = layouts.FirstOrDefault(l => l.Id == layoutId); + + if (layout != default(KeyboardLayout)) + { + logger.Info($"Changing keyboard layout to {ToString(layout.CultureInfo)}."); + InputLanguageManager.Current.CurrentInputLanguage = layout.CultureInfo; + } + else + { + logger.Error($"Could not find keyboard layout with id '{layoutId}'!"); + } + } + + public void Initialize() + { + originalLanguage = InputLanguageManager.Current.CurrentInputLanguage; + logger.Info($"Saved current keyboard layout {ToString(originalLanguage)}."); + + foreach (CultureInfo info in InputLanguageManager.Current.AvailableInputLanguages) + { + var layout = new KeyboardLayout + { + CultureCode = info.ThreeLetterISOLanguageName.ToUpper(), + CultureInfo = info, + IsCurrent = originalLanguage.Equals(info), + Name = info.NativeName + }; + + layouts.Add(layout); + logger.Info($"Detected keyboard layout {ToString(info)}."); + } + + InputLanguageManager.Current.InputLanguageChanged += Current_InputLanguageChanged; + } + + public IEnumerable GetLayouts() + { + return layouts; + } + + public void Terminate() + { + InputLanguageManager.Current.InputLanguageChanged -= Current_InputLanguageChanged; + + if (originalLanguage != null) + { + InputLanguageManager.Current.CurrentInputLanguage = originalLanguage; + logger.Info($"Restored original keyboard layout {ToString(originalLanguage)}."); + } + } + + private void Current_InputLanguageChanged(object sender, InputLanguageEventArgs e) + { + var layout = layouts.First(l => l.CultureInfo.Equals(e.NewLanguage)); + + logger.Info($"Detected keyboard layout change from {ToString(e.PreviousLanguage)} to {ToString(e.NewLanguage)}."); + LayoutChanged?.Invoke(layout); + } + + private string ToString(CultureInfo info) + { + return $"'{info.DisplayName}' ({info.ThreeLetterISOLanguageName.ToUpper()})"; + } + } +} diff --git a/SafeExamBrowser.SystemComponents/KeyboardLayout.cs b/SafeExamBrowser.SystemComponents/KeyboardLayout.cs index 8d02d8bd..155c04a4 100644 --- a/SafeExamBrowser.SystemComponents/KeyboardLayout.cs +++ b/SafeExamBrowser.SystemComponents/KeyboardLayout.cs @@ -7,123 +7,23 @@ */ using System; -using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Windows.Input; -using SafeExamBrowser.I18n.Contracts; -using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; namespace SafeExamBrowser.SystemComponents { - public class KeyboardLayout // TODO: ISystemComponent + internal class KeyboardLayout : IKeyboardLayout { - private const int TWO_SECONDS = 2000; + internal CultureInfo CultureInfo { get; set; } - private KeyboardLayoutDefinition currentLayout; - private IList layouts; - private ILogger logger; - private CultureInfo originalLanguage; - // TODOprivate IList controls; - private IText text; + public string CultureCode { get; set; } + public Guid Id { get; } + public bool IsCurrent { get; set; } + public string Name { get; set; } - public KeyboardLayout(ILogger logger, IText text) + public KeyboardLayout() { - // TODOthis.controls = new List(); - this.layouts = new List(); - this.logger = logger; - this.text = text; - } - - public void Initialize() - { - originalLanguage = InputLanguageManager.Current.CurrentInputLanguage; - logger.Info($"Saved current keyboard layout {ToString(originalLanguage)}."); - - foreach (CultureInfo info in InputLanguageManager.Current.AvailableInputLanguages) - { - var layout = new KeyboardLayoutDefinition - { - CultureCode = info.ThreeLetterISOLanguageName.ToUpper(), - CultureInfo = info, - Name = info.NativeName - }; - - if (originalLanguage.Equals(info)) - { - currentLayout = layout; - } - - layouts.Add(layout); - logger.Info($"Detected keyboard layout {ToString(info)}."); - } - - InputLanguageManager.Current.InputLanguageChanged += Current_InputLanguageChanged; - } - - // TODO - //public void Register(ISystemKeyboardLayoutControl control) - //{ - // foreach (var layout in layouts) - // { - // control.Add(layout); - // } - - // control.LayoutSelected += Control_LayoutSelected; - // control.SetCurrent(currentLayout); - // control.SetInformation(GetInfoTextFor(currentLayout)); - - // controls.Add(control); - //} - - public void Terminate() - { - InputLanguageManager.Current.InputLanguageChanged -= Current_InputLanguageChanged; - - if (originalLanguage != null) - { - InputLanguageManager.Current.CurrentInputLanguage = originalLanguage; - logger.Info($"Restored original keyboard layout {ToString(originalLanguage)}."); - } - - // TODO - //foreach (var control in controls) - //{ - // control.Close(); - //} - } - - private void Control_LayoutSelected(Guid id) - { - var layout = layouts.First(l => l.Id == id); - - logger.Info($"Changing keyboard layout to {ToString(layout.CultureInfo)}."); - InputLanguageManager.Current.CurrentInputLanguage = layout.CultureInfo; - } - - private void Current_InputLanguageChanged(object sender, InputLanguageEventArgs e) - { - var newLayout = layouts.First(l => l.CultureInfo.Equals(e.NewLanguage)); - - logger.Info($"Detected keyboard layout change from {ToString(e.PreviousLanguage)} to {ToString(e.NewLanguage)}."); - currentLayout = newLayout; - - // TODO - //foreach (var control in controls) - //{ - // control.SetCurrent(newLayout); - // control.SetInformation(GetInfoTextFor(newLayout)); - //} - } - - private string GetInfoTextFor(KeyboardLayoutDefinition layout) - { - return text.Get(TextKey.SystemControl_KeyboardLayoutTooltip).Replace("%%LAYOUT%%", layout.CultureInfo.NativeName); - } - - private string ToString(CultureInfo info) - { - return $"'{info.DisplayName}' ({info.ThreeLetterISOLanguageName.ToUpper()})"; + Id = Guid.NewGuid(); } } } diff --git a/SafeExamBrowser.SystemComponents/KeyboardLayoutDefinition.cs b/SafeExamBrowser.SystemComponents/KeyboardLayoutDefinition.cs deleted file mode 100644 index d8811a89..00000000 --- a/SafeExamBrowser.SystemComponents/KeyboardLayoutDefinition.cs +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -using System; -using System.Globalization; -using SafeExamBrowser.SystemComponents.Contracts; - -namespace SafeExamBrowser.SystemComponents -{ - internal class KeyboardLayoutDefinition : IKeyboardLayout - { - internal CultureInfo CultureInfo { get; set; } - - public string CultureCode { get; set; } - public Guid Id { get; } - public string Name { get; set; } - - public KeyboardLayoutDefinition() - { - Id = Guid.NewGuid(); - } - } -} diff --git a/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj b/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj index 235d6cc8..d1397e34 100644 --- a/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj +++ b/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj @@ -63,8 +63,8 @@ - + diff --git a/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs index 8dfdf627..8db9d949 100644 --- a/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Contracts/IUserInterfaceFactory.cs @@ -12,6 +12,7 @@ using SafeExamBrowser.Configuration.Contracts; using SafeExamBrowser.Configuration.Contracts.Settings; using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.UserInterface.Contracts.Browser; using SafeExamBrowser.UserInterface.Contracts.Shell; using SafeExamBrowser.UserInterface.Contracts.Windows; @@ -46,7 +47,7 @@ namespace SafeExamBrowser.UserInterface.Contracts /// /// Creates a system control which allows to change the keyboard layout of the computer. /// - ISystemKeyboardLayoutControl CreateKeyboardLayoutControl(Location location); + ISystemControl CreateKeyboardLayoutControl(IKeyboard keyboard, Location location); /// /// Creates a new log window which runs on its own thread. diff --git a/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj b/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj index dd7d9509..fea91ce6 100644 --- a/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj +++ b/SafeExamBrowser.UserInterface.Contracts/SafeExamBrowser.UserInterface.Contracts.csproj @@ -67,10 +67,8 @@ - - @@ -80,7 +78,6 @@ - @@ -117,6 +114,10 @@ {64ea30fb-11d4-436a-9c2b-88566285363e} SafeExamBrowser.Logging.Contracts + + {903129c6-e236-493b-9ad6-c6a57f647a3a} + SafeExamBrowser.SystemComponents.Contracts + \ No newline at end of file diff --git a/SafeExamBrowser.UserInterface.Contracts/Shell/Events/ApplicationControlClickedEventHandler.cs b/SafeExamBrowser.UserInterface.Contracts/Shell/Events/ApplicationControlClickedEventHandler.cs deleted file mode 100644 index 7894671b..00000000 --- a/SafeExamBrowser.UserInterface.Contracts/Shell/Events/ApplicationControlClickedEventHandler.cs +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -using SafeExamBrowser.Core.Contracts; - -namespace SafeExamBrowser.UserInterface.Contracts.Shell.Events -{ - /// - /// Indicates that an has been clicked, optionally specifying the identifier of the selected instance (if - /// multiple instances of the same application are running). - /// - public delegate void ApplicationControlClickedEventHandler(InstanceIdentifier id = null); -} diff --git a/SafeExamBrowser.UserInterface.Contracts/Shell/ISystemControl.cs b/SafeExamBrowser.UserInterface.Contracts/Shell/ISystemControl.cs index be5c2fbe..914e1ba2 100644 --- a/SafeExamBrowser.UserInterface.Contracts/Shell/ISystemControl.cs +++ b/SafeExamBrowser.UserInterface.Contracts/Shell/ISystemControl.cs @@ -13,14 +13,10 @@ namespace SafeExamBrowser.UserInterface.Contracts.Shell /// public interface ISystemControl { + // TODO: Check if needed after all changes! /// /// Closes the control and / or any associated user interface elements. /// void Close(); - - /// - /// Sets the information text of the system control. - /// - void SetInformation(string text); } } diff --git a/SafeExamBrowser.UserInterface.Contracts/Shell/ISystemKeyboardLayoutControl.cs b/SafeExamBrowser.UserInterface.Contracts/Shell/ISystemKeyboardLayoutControl.cs deleted file mode 100644 index b40b2afb..00000000 --- a/SafeExamBrowser.UserInterface.Contracts/Shell/ISystemKeyboardLayoutControl.cs +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -using SafeExamBrowser.UserInterface.Contracts.Shell.Events; - -namespace SafeExamBrowser.UserInterface.Contracts.Shell -{ - /// - /// The control of the keyboard layout system component. - /// - public interface ISystemKeyboardLayoutControl : ISystemControl - { - /// - /// Event fired when the user selected a keyboard layout. - /// - event KeyboardLayoutSelectedEventHandler LayoutSelected; - - // TODO - ///// - ///// Adds the given layout to the list of selectable keyboard layouts. - ///// - //void Add(IKeyboardLayout layout); - - ///// - ///// Defines the given keyboard layout as the currently active one. - ///// - //void SetCurrent(IKeyboardLayout layout); - } -} diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutButton.xaml.cs index b6480aa9..4142c155 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutButton.xaml.cs @@ -9,8 +9,7 @@ using System; using System.Windows; using System.Windows.Controls; -using SafeExamBrowser.SystemComponents.Contracts; -using SafeExamBrowser.UserInterface.Contracts.Shell.Events; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; namespace SafeExamBrowser.UserInterface.Desktop.Controls { @@ -18,28 +17,18 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls { private IKeyboardLayout layout; - public event KeyboardLayoutSelectedEventHandler LayoutSelected; - - public string CultureCode - { - set { CultureCodeTextBlock.Text = value; } - } - public bool IsCurrent { set { IsCurrentTextBlock.Visibility = value ? Visibility.Visible : Visibility.Hidden; } } - public string LayoutName - { - set { LayoutNameTextBlock.Text = value; } - } - public Guid LayoutId { get { return layout.Id; } } + public event EventHandler LayoutSelected; + public ActionCenterKeyboardLayoutButton(IKeyboardLayout layout) { this.layout = layout; @@ -50,7 +39,9 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls private void InitializeEvents() { - Button.Click += (o, args) => LayoutSelected?.Invoke(layout.Id); + Button.Click += (o, args) => LayoutSelected?.Invoke(this, EventArgs.Empty); + CultureCodeTextBlock.Text = layout.CultureCode; + LayoutNameTextBlock.Text = layout.Name; } } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutControl.xaml.cs index 981812e5..dfb7627a 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutControl.xaml.cs @@ -6,70 +6,41 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Media; -using SafeExamBrowser.SystemComponents.Contracts; +using SafeExamBrowser.I18n.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.UserInterface.Contracts.Shell; -using SafeExamBrowser.UserInterface.Contracts.Shell.Events; namespace SafeExamBrowser.UserInterface.Desktop.Controls { - public partial class ActionCenterKeyboardLayoutControl : UserControl, ISystemKeyboardLayoutControl + public partial class ActionCenterKeyboardLayoutControl : UserControl, ISystemControl { - public event KeyboardLayoutSelectedEventHandler LayoutSelected; + private IKeyboard keyboard; + private IText text; - public ActionCenterKeyboardLayoutControl() + public ActionCenterKeyboardLayoutControl(IKeyboard keyboard, IText text) { + this.keyboard = keyboard; + this.text = text; + InitializeComponent(); InitializeKeyboardLayoutControl(); } - public void Add(IKeyboardLayout layout) - { - Dispatcher.Invoke(() => - { - var button = new ActionCenterKeyboardLayoutButton(layout); - - button.LayoutSelected += Button_LayoutSelected; - button.CultureCode = layout.CultureCode; - button.LayoutName = layout.Name; - - LayoutsStackPanel.Children.Add(button); - }); - } - public void Close() { Dispatcher.Invoke(() => Popup.IsOpen = false); } - public void SetCurrent(IKeyboardLayout layout) - { - Dispatcher.Invoke(() => - { - foreach (var child in LayoutsStackPanel.Children) - { - if (child is ActionCenterKeyboardLayoutButton layoutButton) - { - layoutButton.IsCurrent = layout.Id == layoutButton.LayoutId; - } - } - - Text.Text = layout.Name; - }); - } - - public void SetInformation(string text) - { - Dispatcher.Invoke(() => Button.ToolTip = text); - } - private void InitializeKeyboardLayoutControl() { var originalBrush = Grid.Background; + InitializeLayouts(); + + keyboard.LayoutChanged += Keyboard_LayoutChanged; Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); @@ -77,10 +48,47 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls Popup.Closed += (o, args) => Grid.Background = originalBrush; } - private void Button_LayoutSelected(Guid id) + private void Keyboard_LayoutChanged(IKeyboardLayout layout) + { + Dispatcher.InvokeAsync(() => SetCurrent(layout)); + } + + private void InitializeLayouts() + { + foreach (var layout in keyboard.GetLayouts()) + { + var button = new ActionCenterKeyboardLayoutButton(layout); + + button.LayoutSelected += (o, args) => ActivateLayout(layout); + LayoutsStackPanel.Children.Add(button); + + if (layout.IsCurrent) + { + SetCurrent(layout); + } + } + } + + private void ActivateLayout(IKeyboardLayout layout) { Popup.IsOpen = false; - LayoutSelected?.Invoke(id); + keyboard.ActivateLayout(layout.Id); + } + + private void SetCurrent(IKeyboardLayout layout) + { + var tooltip = text.Get(TextKey.SystemControl_KeyboardLayoutTooltip).Replace("%%LAYOUT%%", layout.Name); + + foreach (var child in LayoutsStackPanel.Children) + { + if (child is ActionCenterKeyboardLayoutButton layoutButton) + { + layoutButton.IsCurrent = layout.Id == layoutButton.LayoutId; + } + } + + Text.Text = layout.Name; + Button.ToolTip = tooltip; } } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarKeyboardLayoutButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarKeyboardLayoutButton.xaml.cs index 643ae29f..a329b920 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarKeyboardLayoutButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarKeyboardLayoutButton.xaml.cs @@ -9,8 +9,7 @@ using System; using System.Windows; using System.Windows.Controls; -using SafeExamBrowser.SystemComponents.Contracts; -using SafeExamBrowser.UserInterface.Contracts.Shell.Events; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; namespace SafeExamBrowser.UserInterface.Desktop.Controls { @@ -18,39 +17,31 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls { private IKeyboardLayout layout; - public event KeyboardLayoutSelectedEventHandler LayoutSelected; - - public string CultureCode - { - set { CultureCodeTextBlock.Text = value; } - } - public bool IsCurrent { set { IsCurrentTextBlock.Visibility = value ? Visibility.Visible : Visibility.Hidden; } } - public string LayoutName - { - set { LayoutNameTextBlock.Text = value; } - } - public Guid LayoutId { get { return layout.Id; } } + public event EventHandler LayoutSelected; + public TaskbarKeyboardLayoutButton(IKeyboardLayout layout) { this.layout = layout; InitializeComponent(); - InitializeEvents(); + InitializeLayoutButton(); } - private void InitializeEvents() + private void InitializeLayoutButton() { - Button.Click += (o, args) => LayoutSelected?.Invoke(layout.Id); + Button.Click += (o, args) => LayoutSelected?.Invoke(this, EventArgs.Empty); + CultureCodeTextBlock.Text = layout.CultureCode; + LayoutNameTextBlock.Text = layout.Name; } } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarKeyboardLayoutControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarKeyboardLayoutControl.xaml.cs index a7cef3cb..a8202338 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarKeyboardLayoutControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarKeyboardLayoutControl.xaml.cs @@ -11,68 +11,38 @@ using System.Linq; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Media; -using SafeExamBrowser.SystemComponents.Contracts; +using SafeExamBrowser.I18n.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.UserInterface.Contracts.Shell; -using SafeExamBrowser.UserInterface.Contracts.Shell.Events; namespace SafeExamBrowser.UserInterface.Desktop.Controls { - public partial class TaskbarKeyboardLayoutControl : UserControl, ISystemKeyboardLayoutControl + public partial class TaskbarKeyboardLayoutControl : UserControl, ISystemControl { - public event KeyboardLayoutSelectedEventHandler LayoutSelected; + private IKeyboard keyboard; + private IText text; - public TaskbarKeyboardLayoutControl() + public TaskbarKeyboardLayoutControl(IKeyboard keyboard, IText text) { + this.keyboard = keyboard; + this.text = text; + InitializeComponent(); InitializeKeyboardLayoutControl(); } - public void Add(IKeyboardLayout layout) - { - Dispatcher.Invoke(() => - { - var button = new TaskbarKeyboardLayoutButton(layout); - - button.LayoutSelected += Button_LayoutSelected; - button.CultureCode = layout.CultureCode; - button.LayoutName = layout.Name; - - LayoutsStackPanel.Children.Add(button); - }); - } - public void Close() { Dispatcher.Invoke(() => Popup.IsOpen = false); } - public void SetCurrent(IKeyboardLayout layout) - { - Dispatcher.Invoke(() => - { - var name = layout.Name?.Length > 3 ? String.Join(string.Empty, layout.Name.Split(' ').Where(s => Char.IsLetter(s.First())).Select(s => s.First())) : layout.Name; - - foreach (var child in LayoutsStackPanel.Children) - { - if (child is TaskbarKeyboardLayoutButton layoutButton) - { - layoutButton.IsCurrent = layout.Id == layoutButton.LayoutId; - } - } - - LayoutCultureCode.Text = layout.CultureCode; - }); - } - - public void SetInformation(string text) - { - Dispatcher.Invoke(() => Button.ToolTip = text); - } - private void InitializeKeyboardLayoutControl() { var originalBrush = Button.Background; + InitializeLayouts(); + + keyboard.LayoutChanged += Keyboard_LayoutChanged; Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); @@ -90,10 +60,48 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls }; } - private void Button_LayoutSelected(Guid id) + private void Keyboard_LayoutChanged(IKeyboardLayout layout) + { + Dispatcher.InvokeAsync(() => SetCurrent(layout)); + } + + private void InitializeLayouts() + { + foreach (var layout in keyboard.GetLayouts()) + { + var button = new TaskbarKeyboardLayoutButton(layout); + + button.LayoutSelected += (o, args) => ActivateLayout(layout); + LayoutsStackPanel.Children.Add(button); + + if (layout.IsCurrent) + { + SetCurrent(layout); + } + } + } + + private void ActivateLayout(IKeyboardLayout layout) { Popup.IsOpen = false; - LayoutSelected?.Invoke(id); + keyboard.ActivateLayout(layout.Id); + } + + private void SetCurrent(IKeyboardLayout layout) + { + var name = layout.Name?.Length > 3 ? String.Join(string.Empty, layout.Name.Split(' ').Where(s => Char.IsLetter(s.First())).Select(s => s.First())) : layout.Name; + var tooltip = text.Get(TextKey.SystemControl_KeyboardLayoutTooltip).Replace("%%LAYOUT%%", layout.Name); + + foreach (var child in LayoutsStackPanel.Children) + { + if (child is TaskbarKeyboardLayoutButton layoutButton) + { + layoutButton.IsCurrent = layout.Id == layoutButton.LayoutId; + } + } + + LayoutCultureCode.Text = layout.CultureCode; + Button.ToolTip = tooltip; } } } diff --git a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs index 3d5a0131..e2d9cbe7 100644 --- a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs @@ -16,6 +16,7 @@ using SafeExamBrowser.Configuration.Contracts; using SafeExamBrowser.Configuration.Contracts.Settings; using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.Browser; using SafeExamBrowser.UserInterface.Contracts.Shell; @@ -69,15 +70,15 @@ namespace SafeExamBrowser.UserInterface.Desktop return new BrowserWindow(control, settings, isMainWindow, text); } - public ISystemKeyboardLayoutControl CreateKeyboardLayoutControl(Location location) + public ISystemControl CreateKeyboardLayoutControl(IKeyboard keyboard, Location location) { if (location == Location.ActionCenter) { - return new ActionCenterKeyboardLayoutControl(); + return new ActionCenterKeyboardLayoutControl(keyboard, text); } else { - return new TaskbarKeyboardLayoutControl(); + return new TaskbarKeyboardLayoutControl(keyboard, text); } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterKeyboardLayoutButton.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterKeyboardLayoutButton.xaml.cs index 711af748..d59f6d0c 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterKeyboardLayoutButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterKeyboardLayoutButton.xaml.cs @@ -9,8 +9,7 @@ using System; using System.Windows; using System.Windows.Controls; -using SafeExamBrowser.SystemComponents.Contracts; -using SafeExamBrowser.UserInterface.Contracts.Shell.Events; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; namespace SafeExamBrowser.UserInterface.Mobile.Controls { @@ -18,28 +17,18 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls { private IKeyboardLayout layout; - public event KeyboardLayoutSelectedEventHandler LayoutSelected; - - public string CultureCode - { - set { CultureCodeTextBlock.Text = value; } - } - public bool IsCurrent { set { IsCurrentTextBlock.Visibility = value ? Visibility.Visible : Visibility.Hidden; } } - public string LayoutName - { - set { LayoutNameTextBlock.Text = value; } - } - public Guid LayoutId { get { return layout.Id; } } + public event EventHandler LayoutSelected; + public ActionCenterKeyboardLayoutButton(IKeyboardLayout layout) { this.layout = layout; @@ -50,7 +39,9 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls private void InitializeEvents() { - Button.Click += (o, args) => LayoutSelected?.Invoke(layout.Id); + Button.Click += (o, args) => LayoutSelected?.Invoke(this, EventArgs.Empty); + CultureCodeTextBlock.Text = layout.CultureCode; + LayoutNameTextBlock.Text = layout.Name; } } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterKeyboardLayoutControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterKeyboardLayoutControl.xaml.cs index 208945b5..7a8f5f2d 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterKeyboardLayoutControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenterKeyboardLayoutControl.xaml.cs @@ -6,70 +6,41 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Media; -using SafeExamBrowser.SystemComponents.Contracts; +using SafeExamBrowser.I18n.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.UserInterface.Contracts.Shell; -using SafeExamBrowser.UserInterface.Contracts.Shell.Events; namespace SafeExamBrowser.UserInterface.Mobile.Controls { - public partial class ActionCenterKeyboardLayoutControl : UserControl, ISystemKeyboardLayoutControl + public partial class ActionCenterKeyboardLayoutControl : UserControl, ISystemControl { - public event KeyboardLayoutSelectedEventHandler LayoutSelected; + private IKeyboard keyboard; + private IText text; - public ActionCenterKeyboardLayoutControl() + public ActionCenterKeyboardLayoutControl(IKeyboard keyboard, IText text) { + this.keyboard = keyboard; + this.text = text; + InitializeComponent(); InitializeKeyboardLayoutControl(); } - public void Add(IKeyboardLayout layout) - { - Dispatcher.Invoke(() => - { - var button = new ActionCenterKeyboardLayoutButton(layout); - - button.LayoutSelected += Button_LayoutSelected; - button.CultureCode = layout.CultureCode; - button.LayoutName = layout.Name; - - LayoutsStackPanel.Children.Add(button); - }); - } - public void Close() { Dispatcher.Invoke(() => Popup.IsOpen = false); } - public void SetCurrent(IKeyboardLayout layout) - { - Dispatcher.Invoke(() => - { - foreach (var child in LayoutsStackPanel.Children) - { - if (child is ActionCenterKeyboardLayoutButton layoutButton) - { - layoutButton.IsCurrent = layout.Id == layoutButton.LayoutId; - } - } - - Text.Text = layout.Name; - }); - } - - public void SetInformation(string text) - { - Dispatcher.Invoke(() => Button.ToolTip = text); - } - private void InitializeKeyboardLayoutControl() { var originalBrush = Grid.Background; + InitializeLayouts(); + + keyboard.LayoutChanged += Keyboard_LayoutChanged; Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); @@ -77,10 +48,47 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls Popup.Closed += (o, args) => Grid.Background = originalBrush; } - private void Button_LayoutSelected(Guid id) + private void Keyboard_LayoutChanged(IKeyboardLayout layout) + { + Dispatcher.InvokeAsync(() => SetCurrent(layout)); + } + + private void InitializeLayouts() + { + foreach (var layout in keyboard.GetLayouts()) + { + var button = new ActionCenterKeyboardLayoutButton(layout); + + button.LayoutSelected += (o, args) => ActivateLayout(layout); + LayoutsStackPanel.Children.Add(button); + + if (layout.IsCurrent) + { + SetCurrent(layout); + } + } + } + + private void ActivateLayout(IKeyboardLayout layout) { Popup.IsOpen = false; - LayoutSelected?.Invoke(id); + keyboard.ActivateLayout(layout.Id); + } + + private void SetCurrent(IKeyboardLayout layout) + { + var tooltip = text.Get(TextKey.SystemControl_KeyboardLayoutTooltip).Replace("%%LAYOUT%%", layout.Name); + + foreach (var child in LayoutsStackPanel.Children) + { + if (child is ActionCenterKeyboardLayoutButton layoutButton) + { + layoutButton.IsCurrent = layout.Id == layoutButton.LayoutId; + } + } + + Text.Text = layout.Name; + Button.ToolTip = tooltip; } } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarKeyboardLayoutButton.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarKeyboardLayoutButton.xaml.cs index 1b3ed060..42c2a023 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarKeyboardLayoutButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarKeyboardLayoutButton.xaml.cs @@ -9,8 +9,7 @@ using System; using System.Windows; using System.Windows.Controls; -using SafeExamBrowser.SystemComponents.Contracts; -using SafeExamBrowser.UserInterface.Contracts.Shell.Events; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; namespace SafeExamBrowser.UserInterface.Mobile.Controls { @@ -18,39 +17,31 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls { private IKeyboardLayout layout; - public event KeyboardLayoutSelectedEventHandler LayoutSelected; - - public string CultureCode - { - set { CultureCodeTextBlock.Text = value; } - } - public bool IsCurrent { set { IsCurrentTextBlock.Visibility = value ? Visibility.Visible : Visibility.Hidden; } } - public string LayoutName - { - set { LayoutNameTextBlock.Text = value; } - } - public Guid LayoutId { get { return layout.Id; } } + public event EventHandler LayoutSelected; + public TaskbarKeyboardLayoutButton(IKeyboardLayout layout) { this.layout = layout; InitializeComponent(); - InitializeEvents(); + InitializeLayoutButton(); } - private void InitializeEvents() + private void InitializeLayoutButton() { - Button.Click += (o, args) => LayoutSelected?.Invoke(layout.Id); + Button.Click += (o, args) => LayoutSelected?.Invoke(this, EventArgs.Empty); + CultureCodeTextBlock.Text = layout.CultureCode; + LayoutNameTextBlock.Text = layout.Name; } } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarKeyboardLayoutControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarKeyboardLayoutControl.xaml.cs index 169a89a9..9e6f862b 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarKeyboardLayoutControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/TaskbarKeyboardLayoutControl.xaml.cs @@ -11,68 +11,38 @@ using System.Linq; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Media; -using SafeExamBrowser.SystemComponents.Contracts; +using SafeExamBrowser.I18n.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.UserInterface.Contracts.Shell; -using SafeExamBrowser.UserInterface.Contracts.Shell.Events; namespace SafeExamBrowser.UserInterface.Mobile.Controls { - public partial class TaskbarKeyboardLayoutControl : UserControl, ISystemKeyboardLayoutControl + public partial class TaskbarKeyboardLayoutControl : UserControl, ISystemControl { - public event KeyboardLayoutSelectedEventHandler LayoutSelected; + private IKeyboard keyboard; + private IText text; - public TaskbarKeyboardLayoutControl() + public TaskbarKeyboardLayoutControl(IKeyboard keyboard, IText text) { + this.keyboard = keyboard; + this.text = text; + InitializeComponent(); InitializeKeyboardLayoutControl(); } - public void Add(IKeyboardLayout layout) - { - Dispatcher.Invoke(() => - { - var button = new TaskbarKeyboardLayoutButton(layout); - - button.LayoutSelected += Button_LayoutSelected; - button.CultureCode = layout.CultureCode; - button.LayoutName = layout.Name; - - LayoutsStackPanel.Children.Add(button); - }); - } - public void Close() { Dispatcher.Invoke(() => Popup.IsOpen = false); } - public void SetCurrent(IKeyboardLayout layout) - { - Dispatcher.Invoke(() => - { - var name = layout.Name?.Length > 3 ? String.Join(string.Empty, layout.Name.Split(' ').Where(s => Char.IsLetter(s.First())).Select(s => s.First())) : layout.Name; - - foreach (var child in LayoutsStackPanel.Children) - { - if (child is TaskbarKeyboardLayoutButton layoutButton) - { - layoutButton.IsCurrent = layout.Id == layoutButton.LayoutId; - } - } - - LayoutCultureCode.Text = layout.CultureCode; - }); - } - - public void SetInformation(string text) - { - Dispatcher.Invoke(() => Button.ToolTip = text); - } - private void InitializeKeyboardLayoutControl() { var originalBrush = Button.Background; + InitializeLayouts(); + + keyboard.LayoutChanged += Keyboard_LayoutChanged; Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); @@ -90,10 +60,48 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls }; } - private void Button_LayoutSelected(Guid id) + private void Keyboard_LayoutChanged(IKeyboardLayout layout) + { + Dispatcher.InvokeAsync(() => SetCurrent(layout)); + } + + private void InitializeLayouts() + { + foreach (var layout in keyboard.GetLayouts()) + { + var button = new TaskbarKeyboardLayoutButton(layout); + + button.LayoutSelected += (o, args) => ActivateLayout(layout); + LayoutsStackPanel.Children.Add(button); + + if (layout.IsCurrent) + { + SetCurrent(layout); + } + } + } + + private void ActivateLayout(IKeyboardLayout layout) { Popup.IsOpen = false; - LayoutSelected?.Invoke(id); + keyboard.ActivateLayout(layout.Id); + } + + private void SetCurrent(IKeyboardLayout layout) + { + var name = layout.Name?.Length > 3 ? String.Join(string.Empty, layout.Name.Split(' ').Where(s => Char.IsLetter(s.First())).Select(s => s.First())) : layout.Name; + var tooltip = text.Get(TextKey.SystemControl_KeyboardLayoutTooltip).Replace("%%LAYOUT%%", layout.Name); + + foreach (var child in LayoutsStackPanel.Children) + { + if (child is TaskbarKeyboardLayoutButton layoutButton) + { + layoutButton.IsCurrent = layout.Id == layoutButton.LayoutId; + } + } + + LayoutCultureCode.Text = layout.CultureCode; + Button.ToolTip = tooltip; } } } diff --git a/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs index de7a37a5..c9a61493 100644 --- a/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Mobile/UserInterfaceFactory.cs @@ -16,6 +16,7 @@ using SafeExamBrowser.Configuration.Contracts; using SafeExamBrowser.Configuration.Contracts.Settings; using SafeExamBrowser.I18n.Contracts; using SafeExamBrowser.Logging.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Keyboard; using SafeExamBrowser.UserInterface.Contracts; using SafeExamBrowser.UserInterface.Contracts.Browser; using SafeExamBrowser.UserInterface.Contracts.Shell; @@ -69,15 +70,15 @@ namespace SafeExamBrowser.UserInterface.Mobile return new BrowserWindow(control, settings, isMainWindow, text); } - public ISystemKeyboardLayoutControl CreateKeyboardLayoutControl(Location location) + public ISystemControl CreateKeyboardLayoutControl(IKeyboard keyboard, Location location) { if (location == Location.ActionCenter) { - return new ActionCenterKeyboardLayoutControl(); + return new ActionCenterKeyboardLayoutControl(keyboard, text); } else { - return new TaskbarKeyboardLayoutControl(); + return new TaskbarKeyboardLayoutControl(keyboard, text); } }