SEBWIN-536, #349: Fixed keyboard system component to correctly display all installed keyboard layouts / input languages.

This commit is contained in:
Damian Büchel 2022-04-26 16:45:53 +02:00
parent 05430f6926
commit a4d1904b81
15 changed files with 101 additions and 53 deletions

View file

@ -20,6 +20,11 @@ namespace SafeExamBrowser.SystemComponents.Contracts.Keyboard
/// </summary>
string CultureCode { get; }
/// <summary>
/// The culture name of this keyboard layout.
/// </summary>
string CultureName { get; }
/// <summary>
/// The unique identifier of the keyboard layout.
/// </summary>
@ -33,6 +38,6 @@ namespace SafeExamBrowser.SystemComponents.Contracts.Keyboard
/// <summary>
/// The name of this keyboard layout.
/// </summary>
string Name { get; }
string LayoutName { get; }
}
}

View file

@ -10,6 +10,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Input;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
@ -19,9 +20,10 @@ namespace SafeExamBrowser.SystemComponents.Keyboard
{
public class Keyboard : IKeyboard
{
private IList<KeyboardLayout> layouts;
private ILogger logger;
private CultureInfo originalLanguage;
private readonly IList<KeyboardLayout> layouts;
private readonly ILogger logger;
private InputLanguage originalLanguage;
public event LayoutChangedEventHandler LayoutChanged;
@ -33,68 +35,71 @@ namespace SafeExamBrowser.SystemComponents.Keyboard
public void ActivateLayout(Guid layoutId)
{
var layout = layouts.FirstOrDefault(l => l.Id == layoutId);
var layout = layouts.First(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}'!");
}
logger.Info($"Changing keyboard layout to {layout}...");
InputLanguage.CurrentInputLanguage = layout.InputLanguage;
layout.IsCurrent = true;
LayoutChanged?.Invoke(layout);
}
public void Initialize()
{
originalLanguage = InputLanguageManager.Current.CurrentInputLanguage;
originalLanguage = InputLanguage.CurrentInputLanguage;
logger.Info($"Saved current keyboard layout {ToString(originalLanguage)}.");
foreach (CultureInfo info in InputLanguageManager.Current.AvailableInputLanguages)
foreach (InputLanguage language in InputLanguage.InstalledInputLanguages)
{
var layout = new KeyboardLayout
{
CultureCode = info.ThreeLetterISOLanguageName.ToUpper(),
CultureInfo = info,
IsCurrent = originalLanguage.Equals(info),
Name = info.NativeName
CultureCode = language.Culture.ThreeLetterISOLanguageName.ToUpper(),
CultureName = language.Culture.NativeName,
InputLanguage = language,
IsCurrent = originalLanguage.Equals(language),
LayoutName = language.LayoutName
};
layouts.Add(layout);
logger.Info($"Detected keyboard layout {ToString(info)}.");
logger.Info($"Detected keyboard layout {layout}.");
}
InputLanguageManager.Current.InputLanguageChanged += Current_InputLanguageChanged;
InputLanguageManager.Current.InputLanguageChanged += InputLanguageManager_InputLanguageChanged;
}
public IEnumerable<IKeyboardLayout> GetLayouts()
{
return layouts;
return new List<KeyboardLayout>(layouts.OrderBy(l => l.CultureName));
}
public void Terminate()
{
InputLanguageManager.Current.InputLanguageChanged -= Current_InputLanguageChanged;
InputLanguageManager.Current.InputLanguageChanged -= InputLanguageManager_InputLanguageChanged;
if (originalLanguage != null)
{
InputLanguageManager.Current.CurrentInputLanguage = originalLanguage;
InputLanguage.CurrentInputLanguage = originalLanguage;
logger.Info($"Restored original keyboard layout {ToString(originalLanguage)}.");
}
}
private void Current_InputLanguageChanged(object sender, InputLanguageEventArgs e)
private void InputLanguageManager_InputLanguageChanged(object sender, InputLanguageEventArgs e)
{
var layout = layouts.First(l => l.CultureInfo.Equals(e.NewLanguage));
var layout = layouts.First(l => l.InputLanguage.Culture.Equals(e.NewLanguage));
logger.Info($"Detected keyboard layout change from {ToString(e.PreviousLanguage)} to {ToString(e.NewLanguage)}.");
layout.IsCurrent = true;
LayoutChanged?.Invoke(layout);
}
private string ToString(CultureInfo info)
private string ToString(InputLanguage language)
{
return $"'{info.DisplayName}' ({info.ThreeLetterISOLanguageName.ToUpper()})";
return $"'{language.Culture.NativeName}' [{language.Culture.ThreeLetterISOLanguageName.ToUpper()}, {language.LayoutName}]";
}
private string ToString(CultureInfo culture)
{
return $"'{culture.NativeName}' [{culture.ThreeLetterISOLanguageName.ToUpper()}]";
}
}
}

View file

@ -7,23 +7,29 @@
*/
using System;
using System.Globalization;
using System.Windows.Forms;
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
namespace SafeExamBrowser.SystemComponents.Keyboard
{
internal class KeyboardLayout : IKeyboardLayout
{
internal CultureInfo CultureInfo { get; set; }
internal InputLanguage InputLanguage { get; set; }
public string CultureCode { get; set; }
public string CultureName { get; set; }
public Guid Id { get; }
public bool IsCurrent { get; set; }
public string Name { get; set; }
public string LayoutName { get; set; }
public KeyboardLayout()
{
Id = Guid.NewGuid();
}
public override string ToString()
{
return $"'{CultureName}' [{CultureCode}, {LayoutName}]";
}
}
}

View file

@ -1,8 +1,9 @@
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter.KeyboardLayoutButton" x:ClassModifier="internal"
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter.KeyboardLayoutButton" x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:fa="http://schemas.fontawesome.io/icons/"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="250">
<UserControl.Resources>
@ -23,7 +24,13 @@
</Grid.ColumnDefinitions>
<TextBlock x:Name="IsCurrentTextBlock" Grid.Column="0" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden">•</TextBlock>
<TextBlock x:Name="CultureCodeTextBlock" Grid.Column="1" FontWeight="Bold" HorizontalAlignment="Left" Margin="10,0,5,0" VerticalAlignment="Center" />
<TextBlock x:Name="LayoutNameTextBlock" Grid.Column="2" Foreground="White" HorizontalAlignment="Left" Margin="5,0,10,0" VerticalAlignment="Center" />
<StackPanel Grid.Column="2" VerticalAlignment="Center">
<TextBlock x:Name="CultureNameTextBlock" Foreground="White" HorizontalAlignment="Left" Margin="5,0,10,0" TextDecorations="Underline" VerticalAlignment="Center" />
<StackPanel Orientation="Horizontal">
<fa:ImageAwesome Foreground="LightGray" Height="10" Icon="KeyboardOutline" Margin="5,0" />
<TextBlock x:Name="LayoutNameTextBlock" Foreground="LightGray" HorizontalAlignment="Left" Margin="0,0,10,0" VerticalAlignment="Center" />
</StackPanel>
</StackPanel>
</Grid>
</Button>
</Grid>

View file

@ -15,7 +15,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
{
internal partial class KeyboardLayoutButton : UserControl
{
private IKeyboardLayout layout;
private readonly IKeyboardLayout layout;
internal bool IsCurrent
{
@ -41,7 +41,8 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
{
Button.Click += (o, args) => LayoutSelected?.Invoke(this, EventArgs.Empty);
CultureCodeTextBlock.Text = layout.CultureCode;
LayoutNameTextBlock.Text = layout.Name;
CultureNameTextBlock.Text = layout.CultureName;
LayoutNameTextBlock.Text = layout.LayoutName;
}
}
}

View file

@ -77,7 +77,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
private void SetCurrent(IKeyboardLayout layout)
{
var tooltip = text.Get(TextKey.SystemControl_KeyboardLayoutTooltip).Replace("%%LAYOUT%%", layout.Name);
var tooltip = text.Get(TextKey.SystemControl_KeyboardLayoutTooltip).Replace("%%LAYOUT%%", layout.CultureName);
foreach (var child in LayoutsStackPanel.Children)
{
@ -87,7 +87,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter
}
}
Text.Text = layout.Name;
Text.Text = layout.CultureName;
Button.ToolTip = tooltip;
}
}

View file

@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:fa="http://schemas.fontawesome.io/icons/"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="250">
<UserControl.Resources>
@ -23,7 +24,13 @@
</Grid.ColumnDefinitions>
<TextBlock x:Name="IsCurrentTextBlock" Grid.Column="0" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden">•</TextBlock>
<TextBlock x:Name="CultureCodeTextBlock" Grid.Column="1" FontWeight="Bold" HorizontalAlignment="Left" Margin="10,0,5,0" VerticalAlignment="Center" />
<TextBlock x:Name="LayoutNameTextBlock" Grid.Column="2" Foreground="Gray" HorizontalAlignment="Left" Margin="5,0,10,0" VerticalAlignment="Center" />
<StackPanel Grid.Column="2" VerticalAlignment="Center">
<TextBlock x:Name="CultureNameTextBlock" HorizontalAlignment="Left" Margin="5,0,10,0" TextDecorations="Underline" VerticalAlignment="Center" />
<StackPanel Orientation="Horizontal">
<fa:ImageAwesome Foreground="Gray" Height="10" Icon="KeyboardOutline" Margin="5,0" />
<TextBlock x:Name="LayoutNameTextBlock" Foreground="Gray" HorizontalAlignment="Left" Margin="0,0,10,0" VerticalAlignment="Center" />
</StackPanel>
</StackPanel>
</Grid>
</Button>
</Grid>

View file

@ -15,7 +15,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
{
internal partial class KeyboardLayoutButton : UserControl
{
private IKeyboardLayout layout;
private readonly IKeyboardLayout layout;
internal bool IsCurrent
{
@ -41,7 +41,8 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
{
Button.Click += (o, args) => LayoutSelected?.Invoke(this, EventArgs.Empty);
CultureCodeTextBlock.Text = layout.CultureCode;
LayoutNameTextBlock.Text = layout.Name;
CultureNameTextBlock.Text = layout.CultureName;
LayoutNameTextBlock.Text = layout.LayoutName;
}
}
}

View file

@ -100,8 +100,8 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar
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);
var name = layout.CultureName?.Length > 3 ? String.Join(string.Empty, layout.CultureName.Split(' ').Where(s => Char.IsLetter(s.First())).Select(s => s.First())) : layout.CultureName;
var tooltip = text.Get(TextKey.SystemControl_KeyboardLayoutTooltip).Replace("%%LAYOUT%%", layout.CultureName);
foreach (var child in LayoutsStackPanel.Children)
{

View file

@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:fa="http://schemas.fontawesome.io/icons/"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Mobile.Controls"
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="250">
<UserControl.Resources>
@ -23,7 +24,13 @@
</Grid.ColumnDefinitions>
<TextBlock x:Name="IsCurrentTextBlock" Grid.Column="0" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden">•</TextBlock>
<TextBlock x:Name="CultureCodeTextBlock" Grid.Column="1" FontWeight="Bold" HorizontalAlignment="Left" Margin="10,0,5,0" VerticalAlignment="Center" />
<TextBlock x:Name="LayoutNameTextBlock" Grid.Column="2" Foreground="White" HorizontalAlignment="Left" Margin="5,0,10,0" VerticalAlignment="Center" />
<StackPanel Grid.Column="2" VerticalAlignment="Center">
<TextBlock x:Name="CultureNameTextBlock" Foreground="White" HorizontalAlignment="Left" Margin="5,0,10,0" TextDecorations="Underline" VerticalAlignment="Center" />
<StackPanel Orientation="Horizontal">
<fa:ImageAwesome Foreground="LightGray" Height="10" Icon="KeyboardOutline" Margin="5,0" />
<TextBlock x:Name="LayoutNameTextBlock" Foreground="LightGray" HorizontalAlignment="Left" Margin="0,0,10,0" VerticalAlignment="Center" />
</StackPanel>
</StackPanel>
</Grid>
</Button>
</Grid>

View file

@ -15,7 +15,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
{
internal partial class KeyboardLayoutButton : UserControl
{
private IKeyboardLayout layout;
private readonly IKeyboardLayout layout;
internal bool IsCurrent
{
@ -41,7 +41,8 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
{
Button.Click += (o, args) => LayoutSelected?.Invoke(this, EventArgs.Empty);
CultureCodeTextBlock.Text = layout.CultureCode;
LayoutNameTextBlock.Text = layout.Name;
CultureNameTextBlock.Text = layout.CultureName;
LayoutNameTextBlock.Text = layout.LayoutName;
}
}
}

View file

@ -77,7 +77,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
private void SetCurrent(IKeyboardLayout layout)
{
var tooltip = text.Get(TextKey.SystemControl_KeyboardLayoutTooltip).Replace("%%LAYOUT%%", layout.Name);
var tooltip = text.Get(TextKey.SystemControl_KeyboardLayoutTooltip).Replace("%%LAYOUT%%", layout.CultureName);
foreach (var child in LayoutsStackPanel.Children)
{
@ -87,7 +87,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
}
}
Text.Text = layout.Name;
Text.Text = layout.CultureName;
Button.ToolTip = tooltip;
}
}

View file

@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:fa="http://schemas.fontawesome.io/icons/"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Mobile.Controls"
mc:Ignorable="d" d:DesignHeight="40" d:DesignWidth="250">
<UserControl.Resources>
@ -23,7 +24,13 @@
</Grid.ColumnDefinitions>
<TextBlock x:Name="IsCurrentTextBlock" Grid.Column="0" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Hidden">•</TextBlock>
<TextBlock x:Name="CultureCodeTextBlock" Grid.Column="1" FontWeight="Bold" HorizontalAlignment="Left" Margin="10,0,5,0" VerticalAlignment="Center" />
<TextBlock x:Name="LayoutNameTextBlock" Grid.Column="2" Foreground="Gray" HorizontalAlignment="Left" Margin="5,0,10,0" VerticalAlignment="Center" />
<StackPanel Grid.Column="2" VerticalAlignment="Center">
<TextBlock x:Name="CultureNameTextBlock" HorizontalAlignment="Left" Margin="5,0,10,0" TextDecorations="Underline" VerticalAlignment="Center" />
<StackPanel Orientation="Horizontal">
<fa:ImageAwesome Foreground="Gray" Height="10" Icon="KeyboardOutline" Margin="5,0" />
<TextBlock x:Name="LayoutNameTextBlock" Foreground="Gray" HorizontalAlignment="Left" Margin="0,0,10,0" VerticalAlignment="Center" />
</StackPanel>
</StackPanel>
</Grid>
</Button>
</Grid>

View file

@ -15,7 +15,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
{
internal partial class KeyboardLayoutButton : UserControl
{
private IKeyboardLayout layout;
private readonly IKeyboardLayout layout;
internal bool IsCurrent
{
@ -41,7 +41,8 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
{
Button.Click += (o, args) => LayoutSelected?.Invoke(this, EventArgs.Empty);
CultureCodeTextBlock.Text = layout.CultureCode;
LayoutNameTextBlock.Text = layout.Name;
CultureNameTextBlock.Text = layout.CultureName;
LayoutNameTextBlock.Text = layout.LayoutName;
}
}
}

View file

@ -100,8 +100,8 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar
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);
var name = layout.CultureName?.Length > 3 ? String.Join(string.Empty, layout.CultureName.Split(' ').Where(s => Char.IsLetter(s.First())).Select(s => s.First())) : layout.CultureName;
var tooltip = text.Get(TextKey.SystemControl_KeyboardLayoutTooltip).Replace("%%LAYOUT%%", layout.CultureName);
foreach (var child in LayoutsStackPanel.Children)
{