diff --git a/SafeExamBrowser.Configuration/Settings.cs b/SafeExamBrowser.Configuration/Settings.cs
index fdcb7c0e..b5cfedc6 100644
--- a/SafeExamBrowser.Configuration/Settings.cs
+++ b/SafeExamBrowser.Configuration/Settings.cs
@@ -28,7 +28,7 @@ namespace SafeExamBrowser.Configuration
}
public bool AllowApplicationLog => true;
-
+ public bool AllowKeyboardLayout => true;
public string AppDataFolderName => "SafeExamBrowser";
public string ApplicationLogFile
@@ -37,9 +37,7 @@ namespace SafeExamBrowser.Configuration
}
public IBrowserSettings Browser { get; private set; }
-
public IKeyboardSettings Keyboard { get; private set; }
-
public IMouseSettings Mouse { get; private set; }
public string LogFolderPath
diff --git a/SafeExamBrowser.Contracts/Configuration/Settings/ISettings.cs b/SafeExamBrowser.Contracts/Configuration/Settings/ISettings.cs
index c777ec57..c2fb15a3 100644
--- a/SafeExamBrowser.Contracts/Configuration/Settings/ISettings.cs
+++ b/SafeExamBrowser.Contracts/Configuration/Settings/ISettings.cs
@@ -15,6 +15,11 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
///
bool AllowApplicationLog { get; }
+ ///
+ /// Determines whether the user may switch the keyboard layout during runtime.
+ ///
+ bool AllowKeyboardLayout { get; }
+
///
/// The name used for the application data folder.
///
diff --git a/SafeExamBrowser.Contracts/I18n/TextKey.cs b/SafeExamBrowser.Contracts/I18n/TextKey.cs
index ab03bb45..2b84a3fd 100644
--- a/SafeExamBrowser.Contracts/I18n/TextKey.cs
+++ b/SafeExamBrowser.Contracts/I18n/TextKey.cs
@@ -41,6 +41,7 @@ namespace SafeExamBrowser.Contracts.I18n
SplashScreen_StopProcessMonitoring,
SplashScreen_StopWindowMonitoring,
SplashScreen_TerminateBrowser,
+ SplashScreen_TerminateTaskbar,
SplashScreen_WaitExplorerStartup,
SplashScreen_WaitExplorerTermination,
SystemControl_BatteryCharged,
@@ -48,6 +49,7 @@ namespace SafeExamBrowser.Contracts.I18n
SystemControl_BatteryChargeCriticalWarning,
SystemControl_BatteryChargeLowInfo,
SystemControl_BatteryRemainingCharge,
+ SystemControl_KeyboardLayoutTooltip,
Version
}
}
diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj
index 06f174d7..c5142fc6 100644
--- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj
+++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj
@@ -87,12 +87,14 @@
+
+
diff --git a/SafeExamBrowser.Contracts/SystemComponents/IKeyboardLayout.cs b/SafeExamBrowser.Contracts/SystemComponents/IKeyboardLayout.cs
new file mode 100644
index 00000000..36efdf56
--- /dev/null
+++ b/SafeExamBrowser.Contracts/SystemComponents/IKeyboardLayout.cs
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+using System;
+
+namespace SafeExamBrowser.Contracts.SystemComponents
+{
+ public interface IKeyboardLayout
+ {
+ ///
+ /// The three-letter ISO code of the culture to which this keyboard layout is associated.
+ ///
+ string CultureCode { get; }
+
+ ///
+ /// The unique identifier of the keyboard layout.
+ ///
+ Guid Id { get; }
+
+ ///
+ /// Specifies whether this is the current keyboard layout.
+ ///
+ bool IsCurrent { get; }
+
+ ///
+ /// The name of this keyboard layout.
+ ///
+ string Name { get; }
+ }
+}
diff --git a/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs b/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs
index 5a483300..531405f2 100644
--- a/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs
+++ b/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs
@@ -41,6 +41,11 @@ namespace SafeExamBrowser.Contracts.UserInterface
///
INotificationButton CreateNotification(INotificationInfo info);
+ ///
+ /// Creates a system control which allows to change the keyboard layout of the computer.
+ ///
+ ISystemKeyboardLayoutControl CreateKeyboardLayoutControl();
+
///
/// Creates a system control displaying the power supply status of the computer.
///
diff --git a/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemKeyboardLayoutControl.cs b/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemKeyboardLayoutControl.cs
new file mode 100644
index 00000000..0bcc9f39
--- /dev/null
+++ b/SafeExamBrowser.Contracts/UserInterface/Taskbar/ISystemKeyboardLayoutControl.cs
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+using SafeExamBrowser.Contracts.SystemComponents;
+
+namespace SafeExamBrowser.Contracts.UserInterface.Taskbar
+{
+ public delegate void KeyboardLayoutSelectedEventHandler(IKeyboardLayout layout);
+
+ public interface ISystemKeyboardLayoutControl : ISystemControl
+ {
+ ///
+ /// Event fired when the user selected a keyboard layout.
+ ///
+ event KeyboardLayoutSelectedEventHandler LayoutSelected;
+
+ ///
+ /// Adds the given layout to the list of selectable keyboard layouts.
+ ///
+ void Add(IKeyboardLayout layout);
+ }
+}
diff --git a/SafeExamBrowser.Core/Behaviour/Operations/TaskbarOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/TaskbarOperation.cs
index f24e4a73..189c75bf 100644
--- a/SafeExamBrowser.Core/Behaviour/Operations/TaskbarOperation.cs
+++ b/SafeExamBrowser.Core/Behaviour/Operations/TaskbarOperation.cs
@@ -21,8 +21,9 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
public class TaskbarOperation : IOperation
{
private ILogger logger;
- private INotificationController aboutController, logController;
+ private INotificationController logController;
private ISettings settings;
+ private ISystemComponent keyboardLayout;
private ISystemComponent powerSupply;
private ISystemInfo systemInfo;
private ITaskbar taskbar;
@@ -34,6 +35,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
public TaskbarOperation(
ILogger logger,
ISettings settings,
+ ISystemComponent keyboardLayout,
ISystemComponent powerSupply,
ISystemInfo systemInfo,
ITaskbar taskbar,
@@ -42,6 +44,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
{
this.logger = logger;
this.settings = settings;
+ this.keyboardLayout = keyboardLayout;
this.powerSupply = powerSupply;
this.systemInfo = systemInfo;
this.taskbar = taskbar;
@@ -59,16 +62,31 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
CreateLogNotification();
}
+ if (settings.AllowKeyboardLayout)
+ {
+ AddKeyboardLayoutControl();
+ }
+
if (systemInfo.HasBattery)
{
- CreatePowerSupplyComponent();
+ AddPowerSupplyControl();
}
}
public void Revert()
{
- logController?.Terminate();
- aboutController?.Terminate();
+ logger.Info("Terminating taskbar...");
+ SplashScreen.UpdateText(TextKey.SplashScreen_TerminateTaskbar);
+
+ if (settings.AllowApplicationLog)
+ {
+ logController?.Terminate();
+ }
+
+ if (settings.AllowKeyboardLayout)
+ {
+ keyboardLayout.Terminate();
+ }
if (systemInfo.HasBattery)
{
@@ -76,6 +94,22 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
}
}
+ private void AddKeyboardLayoutControl()
+ {
+ var control = uiFactory.CreateKeyboardLayoutControl();
+
+ keyboardLayout.Initialize(control);
+ taskbar.AddSystemControl(control);
+ }
+
+ private void AddPowerSupplyControl()
+ {
+ var control = uiFactory.CreatePowerSupplyControl();
+
+ powerSupply.Initialize(control);
+ taskbar.AddSystemControl(control);
+ }
+
private void CreateLogNotification()
{
var logInfo = new LogNotificationInfo(text);
@@ -86,13 +120,5 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
taskbar.AddNotification(logNotification);
}
-
- private void CreatePowerSupplyComponent()
- {
- var control = uiFactory.CreatePowerSupplyControl();
-
- powerSupply.Initialize(control);
- taskbar.AddSystemControl(control);
- }
}
}
diff --git a/SafeExamBrowser.Core/I18n/Text.xml b/SafeExamBrowser.Core/I18n/Text.xml
index 58850c3f..cdb789b7 100644
--- a/SafeExamBrowser.Core/I18n/Text.xml
+++ b/SafeExamBrowser.Core/I18n/Text.xml
@@ -1,37 +1,39 @@
- Open Console
- Application Log
- An unexpected error occurred during the shutdown procedure! Please consult the application log for more information...
- Shutdown Error
- An unexpected error occurred during the startup procedure! Please consult the application log for more information...
- Startup Error
- About Safe Exam Browser
- Application Log
- Emptying clipboard
- Initializing browser
- Initializing process monitoring
- Initializing taskbar
- Initializing window monitoring
- Initializing working area
- Restoring working area
- Initiating shutdown procedure
- Starting event handling
- Starting keyboard interception
- Starting mouse interception
- Initiating startup procedure
- Stopping event handling
- Stopping keyboard interception
- Stopping mouse interception
- Stopping process monitoring
- Stopping window monitoring
- Terminating browser
- Waiting for Windows explorer to start up
- Waiting for Windows explorer to shut down
- Plugged in, charging... (%%CHARGE%%%)
- Fully charged (%%CHARGE%%%)
- The battery charge is critically low. Please connect your computer to a power supply!
- The battery charge is getting low. Consider connecting your computer to a power supply in time...
- %%HOURS%%h %%MINUTES%%min remaining (%%CHARGE%%%)
- Version
+ Open Console
+ Application Log
+ An unexpected error occurred during the shutdown procedure! Please consult the application log for more information...
+ Shutdown Error
+ An unexpected error occurred during the startup procedure! Please consult the application log for more information...
+ Startup Error
+ About Safe Exam Browser
+ Application Log
+ Emptying clipboard
+ Initializing browser
+ Initializing process monitoring
+ Initializing taskbar
+ Initializing window monitoring
+ Initializing working area
+ Restoring working area
+ Initiating shutdown procedure
+ Starting event handling
+ Starting keyboard interception
+ Starting mouse interception
+ Initiating startup procedure
+ Stopping event handling
+ Stopping keyboard interception
+ Stopping mouse interception
+ Stopping process monitoring
+ Stopping window monitoring
+ Terminating browser
+ Terminating taskbar
+ Waiting for Windows explorer to start up
+ Waiting for Windows explorer to shut down
+ Plugged in, charging... (%%CHARGE%%%)
+ Fully charged (%%CHARGE%%%)
+ The battery charge is critically low. Please connect your computer to a power supply!
+ The battery charge is getting low. Consider connecting your computer to a power supply in time...
+ %%HOURS%%h %%MINUTES%%min remaining (%%CHARGE%%%)
+ Click to choose a different keyboard layout...
+ Version
\ No newline at end of file
diff --git a/SafeExamBrowser.SystemComponents/KeyboardLayout.cs b/SafeExamBrowser.SystemComponents/KeyboardLayout.cs
new file mode 100644
index 00000000..852915bd
--- /dev/null
+++ b/SafeExamBrowser.SystemComponents/KeyboardLayout.cs
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows.Forms;
+using SafeExamBrowser.Contracts.I18n;
+using SafeExamBrowser.Contracts.Logging;
+using SafeExamBrowser.Contracts.SystemComponents;
+using SafeExamBrowser.Contracts.UserInterface.Taskbar;
+
+namespace SafeExamBrowser.SystemComponents
+{
+ public class KeyboardLayout : ISystemComponent
+ {
+ private IList layouts = new List();
+ private ILogger logger;
+ private InputLanguage originalLanguage;
+ private ISystemKeyboardLayoutControl control;
+ private IText text;
+
+ public KeyboardLayout(ILogger logger, IText text)
+ {
+ this.logger = logger;
+ this.text = text;
+ }
+
+ public void Initialize(ISystemKeyboardLayoutControl control)
+ {
+ this.control = control;
+
+ originalLanguage = InputLanguage.CurrentInputLanguage;
+ control.LayoutSelected += Control_LayoutSelected;
+ control.SetTooltip(text.Get(TextKey.SystemControl_KeyboardLayoutTooltip));
+
+ logger.Info($"Saved current keyboard layout {ToString(originalLanguage)}.");
+
+ foreach (InputLanguage language in InputLanguage.InstalledInputLanguages)
+ {
+ var layout = new KeyboardLayoutDefinition
+ {
+ CultureCode = language.Culture.ThreeLetterISOLanguageName.ToUpper(),
+ IsCurrent = originalLanguage.Equals(language),
+ Language = language,
+ Name = language.LayoutName
+ };
+
+ control.Add(layout);
+ layouts.Add(layout);
+
+ logger.Info($"Added keyboard layout {ToString(language)} to system control.");
+ }
+ }
+
+ public void Terminate()
+ {
+ control?.Close();
+
+ if (originalLanguage != null)
+ {
+ InputLanguage.CurrentInputLanguage = originalLanguage;
+ logger.Info($"Restored original keyboard layout {ToString(originalLanguage)}.");
+ }
+ }
+
+ private void Control_LayoutSelected(IKeyboardLayout layout)
+ {
+ var language = layouts.First(l => l.Id == layout.Id).Language;
+
+ InputLanguage.CurrentInputLanguage = language;
+
+ foreach (var l in layouts)
+ {
+ l.IsCurrent = l.Id == layout.Id;
+ }
+
+ logger.Info($"Changed keyboard layout to {ToString(language)}.");
+ }
+
+ private string ToString(InputLanguage language)
+ {
+ return $"'{language.LayoutName}' ({language.Culture.ThreeLetterISOLanguageName.ToUpper()})";
+ }
+ }
+}
diff --git a/SafeExamBrowser.SystemComponents/KeyboardLayoutDefinition.cs b/SafeExamBrowser.SystemComponents/KeyboardLayoutDefinition.cs
new file mode 100644
index 00000000..e143be74
--- /dev/null
+++ b/SafeExamBrowser.SystemComponents/KeyboardLayoutDefinition.cs
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+using System;
+using System.Windows.Forms;
+using SafeExamBrowser.Contracts.SystemComponents;
+
+namespace SafeExamBrowser.SystemComponents
+{
+ internal class KeyboardLayoutDefinition : IKeyboardLayout
+ {
+ internal InputLanguage Language { get; set; }
+
+ public string CultureCode { get; set; }
+ public Guid Id { get; }
+ public bool IsCurrent { get; set; }
+ public string Name { get; set; }
+
+ public KeyboardLayoutDefinition()
+ {
+ Id = Guid.NewGuid();
+ }
+ }
+}
diff --git a/SafeExamBrowser.SystemComponents/PowerSupply.cs b/SafeExamBrowser.SystemComponents/PowerSupply.cs
index 6e7804a4..d0c78ab4 100644
--- a/SafeExamBrowser.SystemComponents/PowerSupply.cs
+++ b/SafeExamBrowser.SystemComponents/PowerSupply.cs
@@ -47,11 +47,6 @@ namespace SafeExamBrowser.SystemComponents
logger.Info("Started monitoring the power supply.");
}
- private void Timer_Elapsed(object sender, ElapsedEventArgs e)
- {
- UpdateControl();
- }
-
public void Terminate()
{
timer?.Stop();
@@ -59,6 +54,11 @@ namespace SafeExamBrowser.SystemComponents
logger.Info("Stopped monitoring the power supply.");
}
+ private void Timer_Elapsed(object sender, ElapsedEventArgs e)
+ {
+ UpdateControl();
+ }
+
private void UpdateControl()
{
var charge = SystemInformation.PowerStatus.BatteryLifePercent;
diff --git a/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj b/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj
index 80d5eb7f..549b1e6b 100644
--- a/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj
+++ b/SafeExamBrowser.SystemComponents/SafeExamBrowser.SystemComponents.csproj
@@ -53,6 +53,8 @@
+
+
diff --git a/SafeExamBrowser.UserInterface.Classic/Controls/ApplicationButton.xaml.cs b/SafeExamBrowser.UserInterface.Classic/Controls/ApplicationButton.xaml.cs
index f415ee7b..2ee2a771 100644
--- a/SafeExamBrowser.UserInterface.Classic/Controls/ApplicationButton.xaml.cs
+++ b/SafeExamBrowser.UserInterface.Classic/Controls/ApplicationButton.xaml.cs
@@ -53,7 +53,7 @@ namespace SafeExamBrowser.UserInterface.Classic.Controls
Button.MouseEnter += (o, args) => InstancePopup.IsOpen = instances.Count > 1;
Button.MouseLeave += (o, args) => InstancePopup.IsOpen = InstancePopup.IsMouseOver;
- InstancePopup.MouseLeave += (o, args) => InstancePopup.IsOpen = false || IsMouseOver;
+ InstancePopup.MouseLeave += (o, args) => InstancePopup.IsOpen = IsMouseOver;
InstancePopup.Opened += (o, args) =>
{
diff --git a/SafeExamBrowser.UserInterface.Classic/Controls/KeyboardLayoutButton.xaml b/SafeExamBrowser.UserInterface.Classic/Controls/KeyboardLayoutButton.xaml
new file mode 100644
index 00000000..bfde3547
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Classic/Controls/KeyboardLayoutButton.xaml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SafeExamBrowser.UserInterface.Classic/Controls/KeyboardLayoutButton.xaml.cs b/SafeExamBrowser.UserInterface.Classic/Controls/KeyboardLayoutButton.xaml.cs
new file mode 100644
index 00000000..1616fe9f
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Classic/Controls/KeyboardLayoutButton.xaml.cs
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+using System.Windows;
+using System.Windows.Controls;
+
+namespace SafeExamBrowser.UserInterface.Classic.Controls
+{
+ public partial class KeyboardLayoutButton : UserControl
+ {
+ public event RoutedEventHandler Click;
+
+ 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 KeyboardLayoutButton()
+ {
+ InitializeComponent();
+
+ Button.Click += (o, args) => Click?.Invoke(o, args);
+ }
+ }
+}
diff --git a/SafeExamBrowser.UserInterface.Classic/Controls/KeyboardLayoutControl.xaml b/SafeExamBrowser.UserInterface.Classic/Controls/KeyboardLayoutControl.xaml
new file mode 100644
index 00000000..f1a96092
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Classic/Controls/KeyboardLayoutControl.xaml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+
+
+
+
+
+
diff --git a/SafeExamBrowser.UserInterface.Classic/Controls/KeyboardLayoutControl.xaml.cs b/SafeExamBrowser.UserInterface.Classic/Controls/KeyboardLayoutControl.xaml.cs
new file mode 100644
index 00000000..64f97bc1
--- /dev/null
+++ b/SafeExamBrowser.UserInterface.Classic/Controls/KeyboardLayoutControl.xaml.cs
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2017 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.Linq;
+using System.Windows.Controls;
+using System.Windows.Media;
+using SafeExamBrowser.Contracts.SystemComponents;
+using SafeExamBrowser.Contracts.UserInterface.Taskbar;
+
+namespace SafeExamBrowser.UserInterface.Classic.Controls
+{
+ public partial class KeyboardLayoutControl : UserControl, ISystemKeyboardLayoutControl
+ {
+ public event KeyboardLayoutSelectedEventHandler LayoutSelected;
+
+ public KeyboardLayoutControl()
+ {
+ InitializeComponent();
+ InitializeKeyboardLayoutControl();
+ }
+
+ public void Add(IKeyboardLayout layout)
+ {
+ var button = new KeyboardLayoutButton();
+
+ button.Click += (o, args) =>
+ {
+ SetCurrent(button, layout);
+ Popup.IsOpen = false;
+ LayoutSelected?.Invoke(layout);
+ };
+ button.CultureCode = layout.CultureCode;
+ button.LayoutName = layout.Name;
+
+ LayoutsStackPanel.Children.Add(button);
+
+ if (layout.IsCurrent)
+ {
+ SetCurrent(button, layout);
+ }
+ }
+
+ public void Close()
+ {
+ Popup.IsOpen = false;
+ }
+
+ public void SetTooltip(string text)
+ {
+ Button.ToolTip = text;
+ }
+
+ private void InitializeKeyboardLayoutControl()
+ {
+ var originalBrush = Button.Background;
+
+ Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
+ Button.MouseLeave += (o, args) => Popup.IsOpen = Popup.IsMouseOver;
+ Popup.MouseLeave += (o, args) => Popup.IsOpen = IsMouseOver;
+
+ Popup.Opened += (o, args) =>
+ {
+ Background = Brushes.LightBlue;
+ Button.Background = Brushes.LightBlue;
+ };
+
+ Popup.Closed += (o, args) =>
+ {
+ Background = originalBrush;
+ Button.Background = originalBrush;
+ };
+ }
+
+ private void SetCurrent(KeyboardLayoutButton button, IKeyboardLayout layout)
+ {
+ var name = layout.Name?.Length > 3 ? String.Join(string.Empty, layout.Name.Split(' ').Select(s => s.First())) : layout.Name;
+
+ foreach (var child in LayoutsStackPanel.Children)
+ {
+ if (child is KeyboardLayoutButton)
+ {
+ (child as KeyboardLayoutButton).IsCurrent = false;
+ }
+ }
+
+ button.IsCurrent = true;
+ LayoutCultureCode.Text = layout.CultureCode;
+ LayoutName.Text = name;
+ }
+ }
+}
diff --git a/SafeExamBrowser.UserInterface.Classic/Images/Reload.xaml b/SafeExamBrowser.UserInterface.Classic/Images/Reload.xaml
index 0418cca3..eb620713 100644
--- a/SafeExamBrowser.UserInterface.Classic/Images/Reload.xaml
+++ b/SafeExamBrowser.UserInterface.Classic/Images/Reload.xaml
@@ -1,4 +1,4 @@
-