SEBWIN-342: Removed UI dependencies from keyboard system control.

This commit is contained in:
dbuechel 2019-08-30 15:59:51 +02:00
parent 487e89693a
commit d8752b5558
27 changed files with 436 additions and 499 deletions

View file

@ -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<ITerminationActivator> terminationActivator;
private Mock<INotificationInfo> aboutInfo;
private Mock<INotificationController> aboutController;
private Mock<IKeyboard> keyboard;
private Mock<INotificationInfo> logInfo;
private Mock<INotificationController> logController;
// TODO
//private Mock<ISystemComponent<ISystemAudioControl>> audio;
//private Mock<ISystemComponent<ISystemKeyboardLayoutControl>> keyboardLayout;
//private Mock<ISystemComponent<ISystemPowerSupplyControl>> powerSupply;
//private Mock<ISystemComponent<ISystemWirelessNetworkControl>> wirelessNetwork;
private Mock<ISystemInfo> systemInfo;
@ -55,11 +56,11 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
logger = new Mock<ILogger>();
aboutInfo = new Mock<INotificationInfo>();
aboutController = new Mock<INotificationController>();
keyboard = new Mock<IKeyboard>();
logInfo = new Mock<INotificationInfo>();
logController = new Mock<INotificationController>();
// TODO
//audio = new Mock<ISystemComponent<ISystemAudioControl>>();
//keyboardLayout = new Mock<ISystemComponent<ISystemKeyboardLayoutControl>>();
//powerSupply = new Mock<ISystemComponent<ISystemPowerSupplyControl>>();
//wirelessNetwork = new Mock<ISystemComponent<ISystemWirelessNetworkControl>>();
systemInfo = new Mock<ISystemInfo>();
@ -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<Location>())).Returns(new Mock<ISystemAudioControl>().Object);
uiFactory.Setup(f => f.CreateKeyboardLayoutControl(It.IsAny<Location>())).Returns(new Mock<ISystemKeyboardLayoutControl>().Object);
uiFactory.Setup(f => f.CreateKeyboardLayoutControl(It.IsAny<IKeyboard>(), It.IsAny<Location>())).Returns(new Mock<ISystemControl>().Object);
uiFactory.Setup(f => f.CreatePowerSupplyControl(It.IsAny<Location>())).Returns(new Mock<ISystemPowerSupplyControl>().Object);
uiFactory.Setup(f => f.CreateWirelessNetworkControl(It.IsAny<Location>())).Returns(new Mock<ISystemWirelessNetworkControl>().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<ISystemAudioControl>()), Times.Once);
actionCenter.Verify(a => a.AddSystemControl(It.IsAny<ISystemKeyboardLayoutControl>()), Times.Once);
actionCenter.Verify(a => a.AddSystemControl(It.IsAny<ISystemPowerSupplyControl>()), Times.Once);
actionCenter.Verify(a => a.AddSystemControl(It.IsAny<ISystemWirelessNetworkControl>()), Times.Once);
taskbar.Verify(t => t.AddSystemControl(It.IsAny<ISystemAudioControl>()), Times.Once);
taskbar.Verify(t => t.AddSystemControl(It.IsAny<ISystemKeyboardLayoutControl>()), Times.Once);
taskbar.Verify(t => t.AddSystemControl(It.IsAny<ISystemPowerSupplyControl>()), Times.Once);
taskbar.Verify(t => t.AddSystemControl(It.IsAny<ISystemWirelessNetworkControl>()), Times.Once);
keyboard.Verify(k => k.Initialize(), Times.Once);
actionCenter.Verify(a => a.AddSystemControl(It.IsAny<ISystemControl>()), Times.Exactly(4));
taskbar.Verify(t => t.AddSystemControl(It.IsAny<ISystemControl>()), 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<Location>())).Returns(new Mock<ISystemAudioControl>().Object);
uiFactory.Setup(f => f.CreateKeyboardLayoutControl(It.IsAny<Location>())).Returns(new Mock<ISystemKeyboardLayoutControl>().Object);
uiFactory.Setup(f => f.CreateKeyboardLayoutControl(It.IsAny<IKeyboard>(), It.IsAny<Location>())).Returns(new Mock<ISystemControl>().Object);
uiFactory.Setup(f => f.CreatePowerSupplyControl(It.IsAny<Location>())).Returns(new Mock<ISystemPowerSupplyControl>().Object);
uiFactory.Setup(f => f.CreateWirelessNetworkControl(It.IsAny<Location>())).Returns(new Mock<ISystemWirelessNetworkControl>().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<ISystemAudioControl>()), Times.Never);
actionCenter.Verify(a => a.AddSystemControl(It.IsAny<ISystemKeyboardLayoutControl>()), Times.Never);
actionCenter.Verify(a => a.AddSystemControl(It.IsAny<ISystemPowerSupplyControl>()), Times.Never);
actionCenter.Verify(a => a.AddSystemControl(It.IsAny<ISystemWirelessNetworkControl>()), Times.Never);
taskbar.Verify(t => t.AddSystemControl(It.IsAny<ISystemAudioControl>()), Times.Never);
taskbar.Verify(t => t.AddSystemControl(It.IsAny<ISystemKeyboardLayoutControl>()), Times.Never);
taskbar.Verify(t => t.AddSystemControl(It.IsAny<ISystemPowerSupplyControl>()), Times.Never);
taskbar.Verify(t => t.AddSystemControl(It.IsAny<ISystemWirelessNetworkControl>()), Times.Never);
keyboard.Verify(k => k.Initialize(), Times.Once);
actionCenter.Verify(a => a.AddSystemControl(It.IsAny<ISystemControl>()), Times.Never);
taskbar.Verify(t => t.AddSystemControl(It.IsAny<ISystemControl>()), 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);
}

View file

@ -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,

View file

@ -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<ISystemAudioControl> audio;
// TODO private ISystemComponent<ISystemKeyboardLayoutControl> keyboardLayout;
// TODO private ISystemComponent<ISystemPowerSupplyControl> powerSupply;
// TODO private ISystemComponent<ISystemWirelessNetworkControl> 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<ISystemAudioControl> audio,
// TODO ISystemComponent<ISystemKeyboardLayoutControl> keyboardLayout,
// TODO ISystemComponent<ISystemAudioControl> audio,
// TODO ISystemComponent<ISystemPowerSupplyControl> powerSupply,
// TODO ISystemComponent<ISystemWirelessNetworkControl> 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();
}
}
}

View file

@ -9,22 +9,15 @@
namespace SafeExamBrowser.SystemComponents.Contracts
{
/// <summary>
/// Defines the functionality of a system component (e.g. the power supply). Each system component can get multiple <see cref="ISystemControl"/>
/// 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).
/// </summary>
public interface ISystemComponent// TODO <TControl> where TControl : ISystemControl
public interface ISystemComponent
{
/// <summary>
/// Initializes the resources and operations of the component.
/// </summary>
void Initialize();
// TODO
///// <summary>
///// Registers a system control which will be loaded into shell.
///// </summary>
//void Register(TControl control);
/// <summary>
/// Instructs the component to stop any running operations and releases all used resources.
/// </summary>

View file

@ -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
{
/// <summary>
/// Indicates that a keyboard layout has been selected by the user.
/// Indicates that the active keyboard layout has changed.
/// </summary>
public delegate void KeyboardLayoutSelectedEventHandler(Guid id);
public delegate void KeyboardLayoutChangedEventHandler(IKeyboardLayout layout);
}

View file

@ -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
{
/// <summary>
/// Defines the functionality of the keyboard system component.
/// </summary>
public interface IKeyboard : ISystemComponent
{
/// <summary>
/// Fired when the active keyboard layout changed.
/// </summary>
event KeyboardLayoutChangedEventHandler LayoutChanged;
/// <summary>
/// Activates the keyboard layout with the given identifier.
/// </summary>
void ActivateLayout(Guid id);
/// <summary>
/// Gets all currently available keyboard layouts.
/// </summary>
IEnumerable<IKeyboardLayout> GetLayouts();
}
}

View file

@ -8,7 +8,7 @@
using System;
namespace SafeExamBrowser.SystemComponents.Contracts
namespace SafeExamBrowser.SystemComponents.Contracts.Keyboard
{
/// <summary>
/// Defines a keyboard layout which can be loaded by the application.
@ -25,6 +25,11 @@ namespace SafeExamBrowser.SystemComponents.Contracts
/// </summary>
Guid Id { get; }
/// <summary>
/// Indicates whether this is the currently active keyboard layout.
/// </summary>
bool IsCurrent { get; }
/// <summary>
/// The name of this keyboard layout.
/// </summary>

View file

@ -54,7 +54,9 @@
</ItemGroup>
<ItemGroup>
<Compile Include="BatteryChargeStatus.cs" />
<Compile Include="IKeyboardLayout.cs" />
<Compile Include="Keyboard\Events\KeyboardLayoutChangedEventHandler.cs" />
<Compile Include="Keyboard\IKeyboard.cs" />
<Compile Include="Keyboard\IKeyboardLayout.cs" />
<Compile Include="ISystemComponent.cs" />
<Compile Include="ISystemInfo.cs" />
<Compile Include="IUserInfo.cs" />
@ -63,5 +65,6 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WirelessNetworkStatus.cs" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -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<KeyboardLayout> layouts;
private ILogger logger;
private CultureInfo originalLanguage;
private IText text;
public event KeyboardLayoutChangedEventHandler LayoutChanged;
public Keyboard(ILogger logger, IText text)
{
this.layouts = new List<KeyboardLayout>();
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<IKeyboardLayout> 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()})";
}
}
}

View file

@ -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<ISystemKeyboardLayoutControl>
internal class KeyboardLayout : IKeyboardLayout
{
private const int TWO_SECONDS = 2000;
internal CultureInfo CultureInfo { get; set; }
private KeyboardLayoutDefinition currentLayout;
private IList<KeyboardLayoutDefinition> layouts;
private ILogger logger;
private CultureInfo originalLanguage;
// TODOprivate IList<ISystemKeyboardLayoutControl> 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<ISystemKeyboardLayoutControl>();
this.layouts = new List<KeyboardLayoutDefinition>();
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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -63,8 +63,8 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Audio.cs" />
<Compile Include="KeyboardLayoutDefinition.cs" />
<Compile Include="KeyboardLayout.cs" />
<Compile Include="Keyboard.cs" />
<Compile Include="PowerSupply.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SystemInfo.cs" />

View file

@ -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
/// <summary>
/// Creates a system control which allows to change the keyboard layout of the computer.
/// </summary>
ISystemKeyboardLayoutControl CreateKeyboardLayoutControl(Location location);
ISystemControl CreateKeyboardLayoutControl(IKeyboard keyboard, Location location);
/// <summary>
/// Creates a new log window which runs on its own thread.

View file

@ -67,10 +67,8 @@
<Compile Include="MessageBox\MessageBoxResult.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Shell\Events\ActivatorEventHandler.cs" />
<Compile Include="Shell\Events\ApplicationControlClickedEventHandler.cs" />
<Compile Include="Shell\Events\AudioMuteRequestedEventHandler.cs" />
<Compile Include="Shell\Events\AudioVolumeSelectedEventHandler.cs" />
<Compile Include="Shell\Events\KeyboardLayoutSelectedEventHandler.cs" />
<Compile Include="Shell\Events\NotificationControlClickedEventHandler.cs" />
<Compile Include="Shell\Events\QuitButtonClickedEventHandler.cs" />
<Compile Include="Shell\Events\WirelessNetworkSelectedEventHandler.cs" />
@ -80,7 +78,6 @@
<Compile Include="Shell\INotificationControl.cs" />
<Compile Include="Shell\ISystemAudioControl.cs" />
<Compile Include="Shell\ISystemControl.cs" />
<Compile Include="Shell\ISystemKeyboardLayoutControl.cs" />
<Compile Include="Shell\ISystemPowerSupplyControl.cs" />
<Compile Include="Shell\ISystemWirelessNetworkControl.cs" />
<Compile Include="Shell\ITaskbar.cs" />
@ -117,6 +114,10 @@
<Project>{64ea30fb-11d4-436a-9c2b-88566285363e}</Project>
<Name>SafeExamBrowser.Logging.Contracts</Name>
</ProjectReference>
<ProjectReference Include="..\SafeExamBrowser.SystemComponents.Contracts\SafeExamBrowser.SystemComponents.Contracts.csproj">
<Project>{903129c6-e236-493b-9ad6-c6a57f647a3a}</Project>
<Name>SafeExamBrowser.SystemComponents.Contracts</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -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
{
/// <summary>
/// Indicates that an <see cref="IApplicationControl"/> has been clicked, optionally specifying the identifier of the selected instance (if
/// multiple instances of the same application are running).
/// </summary>
public delegate void ApplicationControlClickedEventHandler(InstanceIdentifier id = null);
}

View file

@ -13,14 +13,10 @@ namespace SafeExamBrowser.UserInterface.Contracts.Shell
/// </summary>
public interface ISystemControl
{
// TODO: Check if needed after all changes!
/// <summary>
/// Closes the control and / or any associated user interface elements.
/// </summary>
void Close();
/// <summary>
/// Sets the information text of the system control.
/// </summary>
void SetInformation(string text);
}
}

View file

@ -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
{
/// <summary>
/// The control of the keyboard layout system component.
/// </summary>
public interface ISystemKeyboardLayoutControl : ISystemControl
{
/// <summary>
/// Event fired when the user selected a keyboard layout.
/// </summary>
event KeyboardLayoutSelectedEventHandler LayoutSelected;
// TODO
///// <summary>
///// Adds the given layout to the list of selectable keyboard layouts.
///// </summary>
//void Add(IKeyboardLayout layout);
///// <summary>
///// Defines the given keyboard layout as the currently active one.
///// </summary>
//void SetCurrent(IKeyboardLayout layout);
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}