diff --git a/SafeExamBrowser.I18n.Contracts/TextKey.cs b/SafeExamBrowser.I18n.Contracts/TextKey.cs index b45a251b..da2ce5a7 100644 --- a/SafeExamBrowser.I18n.Contracts/TextKey.cs +++ b/SafeExamBrowser.I18n.Contracts/TextKey.cs @@ -26,6 +26,7 @@ namespace SafeExamBrowser.I18n.Contracts Browser_PrintNotAllowed, Browser_Tooltip, BrowserWindow_BackwardButton, + BrowserWindow_CloseButton, BrowserWindow_DeveloperConsoleMenuItem, BrowserWindow_Downloading, BrowserWindow_DownloadCancelled, @@ -37,6 +38,9 @@ namespace SafeExamBrowser.I18n.Contracts BrowserWindow_HomeButton, BrowserWindow_MenuButton, BrowserWindow_ReloadButton, + BrowserWindow_SearchNext, + BrowserWindow_SearchPrevious, + BrowserWindow_SearchTextBox, BrowserWindow_UrlTextBox, BrowserWindow_ZoomLevelReset, BrowserWindow_ZoomMenuItem, diff --git a/SafeExamBrowser.I18n/Data/de.xml b/SafeExamBrowser.I18n/Data/de.xml index 2e56014f..f5449e50 100644 --- a/SafeExamBrowser.I18n/Data/de.xml +++ b/SafeExamBrowser.I18n/Data/de.xml @@ -31,7 +31,7 @@ Drucken ist nicht erlaubt gemäss der aktiven Konfiguration. - Browser Applikation + Geöffnete Websites Entwickler-Konsole @@ -69,6 +69,9 @@ Menü + + Schliessen + URL eingeben @@ -84,6 +87,15 @@ Zoom verkleinern + + Text eingeben zum Suchen + + + Nächstes Suchresultat + + + Vorheriges Suchresultat + Build diff --git a/SafeExamBrowser.I18n/Data/en.xml b/SafeExamBrowser.I18n/Data/en.xml index c4c35e5d..df82cb90 100644 --- a/SafeExamBrowser.I18n/Data/en.xml +++ b/SafeExamBrowser.I18n/Data/en.xml @@ -31,7 +31,7 @@ Printing is not allowed according to the current configuration. - Browser Application + Open Webpages Developer Console @@ -69,6 +69,9 @@ Menu + + Close + Enter URL @@ -84,6 +87,15 @@ Decrease Page Zoom + + Enter text to search + + + Next search result + + + Previous search result + Build diff --git a/SafeExamBrowser.I18n/Data/fr.xml b/SafeExamBrowser.I18n/Data/fr.xml index a630e7cd..f0d73ffa 100644 --- a/SafeExamBrowser.I18n/Data/fr.xml +++ b/SafeExamBrowser.I18n/Data/fr.xml @@ -34,7 +34,7 @@ Application du navigateur - Console de développement + Sites web ouverts Chargement… @@ -69,6 +69,9 @@ Menu + + Fermer + Entrer l'URL @@ -84,6 +87,15 @@ Diminuer zoom + + Saisir du texte pour rechercher + + + Résultat de recherche prochain + + + Résultat de recherche précédent + Build diff --git a/SafeExamBrowser.I18n/Data/it.xml b/SafeExamBrowser.I18n/Data/it.xml index c916323b..20fc8a4e 100644 --- a/SafeExamBrowser.I18n/Data/it.xml +++ b/SafeExamBrowser.I18n/Data/it.xml @@ -34,7 +34,7 @@ Applicazione browser - Console di sviluppo + Siti web aperti Download in corso ... @@ -69,6 +69,9 @@ Menu + + Chiudere + Inserisci URL @@ -84,6 +87,15 @@ Diminuire zoom + + Immettere il testo da cercare + + + Risultato della ricerca successiva + + + Risultato della ricerca precedente + Build diff --git a/SafeExamBrowser.I18n/Data/zh.xml b/SafeExamBrowser.I18n/Data/zh.xml index 72cec036..f6f972ca 100644 --- a/SafeExamBrowser.I18n/Data/zh.xml +++ b/SafeExamBrowser.I18n/Data/zh.xml @@ -34,7 +34,7 @@ 根据当前配置不允许打印。 - 浏览器应用程序 + 开放网站 开发者控制台 @@ -66,6 +66,9 @@ 菜单 + + 关闭 + 输入网址 @@ -81,6 +84,15 @@ 减少页面缩放 + + 输入文本进行搜索 + + + 下一个搜索结果 + + + 前一个搜索结果 + 生成 diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/ApplicationButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/ApplicationButton.xaml.cs index db252715..3ecd0db4 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/ApplicationButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/ApplicationButton.xaml.cs @@ -35,7 +35,9 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter Icon.Content = IconResourceLoader.Load(window?.Icon ?? application.Icon); Text.Text = window?.Title ?? application.Name; Button.Click += (o, args) => Clicked?.Invoke(this, EventArgs.Empty); - Button.ToolTip = window?.Title ?? application.Tooltip; + var tooltip = window?.Title ?? application.Tooltip; + Button.ToolTip = tooltip; + System.Windows.Automation.AutomationProperties.SetName(Button, tooltip); if (window != null) { diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/AudioControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/AudioControl.xaml index d81f0bf8..9a9c49a9 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/AudioControl.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/AudioControl.xaml @@ -21,7 +21,7 @@ diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/AudioControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/AudioControl.xaml.cs index 55f7992c..42eb024d 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/AudioControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/AudioControl.xaml.cs @@ -49,13 +49,39 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter audio.VolumeChanged += Audio_VolumeChanged; Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; - Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); + var lastOpenedBySpacePress = false; + Button.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); MuteButton.Click += MuteButton_Click; MutedIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Muted.xaml") }; NoDeviceIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Light_NoDevice.xaml") }; - Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); Popup.Opened += (o, args) => Grid.Background = Brushes.Gray; - Popup.Closed += (o, args) => Grid.Background = originalBrush; + Popup.Closed += (o, args) => + { + Grid.Background = originalBrush; + lastOpenedBySpacePress = false; + }; Volume.ValueChanged += Volume_ValueChanged; if (audio.HasOutputDevice) @@ -114,6 +140,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter this.muted = muted; Button.ToolTip = info; + System.Windows.Automation.AutomationProperties.SetName(Button, info); Text.Text = info; Volume.ValueChanged -= Volume_ValueChanged; Volume.Value = Math.Round(volume * 100); @@ -121,14 +148,18 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter if (muted) { + var tooltip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); + MuteButton.ToolTip = tooltip; + System.Windows.Automation.AutomationProperties.SetName(MuteButton, tooltip); ButtonIcon.Content = IconResourceLoader.Load(MutedIcon); - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); PopupIcon.Content = IconResourceLoader.Load(MutedIcon); } else { + var tooltip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); + MuteButton.ToolTip = tooltip; + System.Windows.Automation.AutomationProperties.SetName(MuteButton, tooltip); ButtonIcon.Content = LoadIcon(volume); - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); PopupIcon.Content = LoadIcon(volume); } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/KeyboardLayoutButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/KeyboardLayoutButton.xaml.cs index 44a6f756..5e5607f8 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/KeyboardLayoutButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/KeyboardLayoutButton.xaml.cs @@ -43,6 +43,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter CultureCodeTextBlock.Text = layout.CultureCode; CultureNameTextBlock.Text = layout.CultureName; LayoutNameTextBlock.Text = layout.LayoutName; + System.Windows.Automation.AutomationProperties.SetName(Button, layout.CultureName); } } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/KeyboardLayoutControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/KeyboardLayoutControl.xaml.cs index 24eaedf8..d9a5a85a 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/KeyboardLayoutControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/KeyboardLayoutControl.xaml.cs @@ -6,7 +6,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System; using System.Threading.Tasks; +using System.Windows.Automation; using System.Windows.Controls; using System.Windows.Media; using SafeExamBrowser.I18n.Contracts; @@ -49,10 +51,36 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter LayoutsStackPanel.Children[0].Focus(); })); }; - 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)); + var lastOpenedBySpacePress = false; + Button.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); Popup.Opened += (o, args) => Grid.Background = Brushes.Gray; - Popup.Closed += (o, args) => Grid.Background = originalBrush; + Popup.Closed += (o, args) => + { + Grid.Background = originalBrush; + lastOpenedBySpacePress = false; + }; } private void Keyboard_LayoutChanged(IKeyboardLayout layout) @@ -96,6 +124,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter Text.Text = layout.CultureName; Button.ToolTip = tooltip; + AutomationProperties.SetName(Button, tooltip); } private void Popup_KeyUp(object sender, System.Windows.Input.KeyEventArgs e) diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkButton.xaml.cs index 8e940f07..ac1dc27a 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkButton.xaml.cs @@ -34,5 +34,10 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter NetworkNameTextBlock.Text = network.Name; SignalStrengthTextBlock.Text = $"{network.SignalStrength}%"; } + + public void SetFocus() + { + Button.Focus(); + } } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkControl.xaml.cs index 4a5beafd..0cb17a58 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/NetworkControl.xaml.cs @@ -45,10 +45,50 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter adapter.Changed += () => Dispatcher.InvokeAsync(Update); 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)); - Popup.Opened += (o, args) => Grid.Background = Brushes.Gray; - Popup.Closed += (o, args) => Grid.Background = originalBrush; + var lastOpenedBySpacePress = false; + Button.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); + Popup.Opened += (o, args) => + { + Grid.Background = Brushes.Gray; + Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() => + { + if (WirelessNetworksStackPanel.Children.Count > 0) + { + var btn = WirelessNetworksStackPanel.Children[0] as NetworkButton; + if (btn != null) + { + btn.SetFocus(); + } + } + })); + }; + Popup.Closed += (o, args) => + { + Grid.Background = originalBrush; + lastOpenedBySpacePress = false; + }; WirelessIcon.Child = GetWirelessIcon(0); Update(); @@ -121,7 +161,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter { Button.ToolTip = text; Text.Text = text; - Button.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, text); + Button.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text); } private UIElement GetWirelessIcon(int signalStrength) diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/PowerSupplyControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/PowerSupplyControl.xaml.cs index 32dfdd95..79dca71f 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/PowerSupplyControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/PowerSupplyControl.xaml.cs @@ -87,7 +87,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter PowerPlug.Visibility = status.IsOnline ? Visibility.Visible : Visibility.Collapsed; Text.Text = tooltip; Warning.Visibility = status.BatteryChargeStatus == BatteryChargeStatus.Critical ? Visibility.Visible : Visibility.Collapsed; - this.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, tooltip); + this.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, tooltip); } private void RenderCharge(double charge, BatteryChargeStatus status) diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/RaiseHandControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/RaiseHandControl.xaml.cs index 2f8d4aa0..5ed86791 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/RaiseHandControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenter/RaiseHandControl.xaml.cs @@ -55,15 +55,41 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenter RaisedIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Hand_Raised.xaml") }; Icon.Content = IconResourceLoader.Load(LoweredIcon); - NotificationButton.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); + var lastOpenedBySpacePress = false; + NotificationButton.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + NotificationButton.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); NotificationButton.PreviewMouseLeftButtonUp += NotificationButton_PreviewMouseLeftButtonUp; NotificationButton.PreviewMouseRightButtonUp += NotificationButton_PreviewMouseRightButtonUp; NotificationButton.ToolTip = text.Get(TextKey.Notification_ProctoringHandLowered); Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback); - Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); Popup.Opened += (o, args) => Grid.Background = Brushes.Gray; - Popup.Closed += (o, args) => Grid.Background = originalBrush; + Popup.Closed += (o, args) => + { + Grid.Background = originalBrush; + lastOpenedBySpacePress = false; + }; Text.Text = text.Get(TextKey.Notification_ProctoringHandLowered); } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/ApplicationControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/ApplicationControl.xaml.cs index eb3c1a31..33f5ec03 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/ApplicationControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/ApplicationControl.xaml.cs @@ -44,6 +44,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar Button.MouseEnter += (o, args) => WindowPopup.IsOpen = WindowStackPanel.Children.Count > 0; Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => WindowPopup.IsOpen = WindowPopup.IsMouseOver || ActiveBar.IsMouseOver)); Button.ToolTip = application.Tooltip; + System.Windows.Automation.AutomationProperties.SetName(Button, application.Tooltip); WindowPopup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(WindowPopup_PlacementCallback); WindowPopup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => WindowPopup.IsOpen = IsMouseOver)); diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/AudioControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/AudioControl.xaml index 229251fc..601e5f1c 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/AudioControl.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/AudioControl.xaml @@ -22,7 +22,7 @@ diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/AudioControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/AudioControl.xaml.cs index 541416ad..2eafc925 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/AudioControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/AudioControl.xaml.cs @@ -48,12 +48,34 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar audio.VolumeChanged += Audio_VolumeChanged; Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; - Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); + var lastOpenedBySpacePress = false; + Button.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); MuteButton.Click += MuteButton_Click; MutedIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Muted.xaml") }; NoDeviceIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_NoDevice.xaml") }; Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback); - Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); Volume.ValueChanged += Volume_ValueChanged; Popup.Opened += (o, args) => @@ -67,6 +89,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar { Background = originalBrush; Button.Background = originalBrush; + lastOpenedBySpacePress = false; }; if (audio.HasOutputDevice) @@ -132,19 +155,24 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar this.muted = muted; Button.ToolTip = info; + System.Windows.Automation.AutomationProperties.SetName(Button, info); Volume.ValueChanged -= Volume_ValueChanged; Volume.Value = Math.Round(volume * 100); Volume.ValueChanged += Volume_ValueChanged; if (muted) { - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); + var tooltip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); + MuteButton.ToolTip = tooltip; + System.Windows.Automation.AutomationProperties.SetName(MuteButton, tooltip); PopupIcon.Content = IconResourceLoader.Load(MutedIcon); ButtonIcon.Content = IconResourceLoader.Load(MutedIcon); } else { - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); + var tooltip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); + MuteButton.ToolTip = tooltip; + System.Windows.Automation.AutomationProperties.SetName(MuteButton, tooltip); PopupIcon.Content = LoadIcon(volume); ButtonIcon.Content = LoadIcon(volume); } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/Clock.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/Clock.xaml index 93517d0f..ea23411a 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/Clock.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/Clock.xaml @@ -11,7 +11,7 @@ - - + + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/KeyboardLayoutButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/KeyboardLayoutButton.xaml.cs index ad74c2fa..ea993856 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/KeyboardLayoutButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/KeyboardLayoutButton.xaml.cs @@ -43,7 +43,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar CultureCodeTextBlock.Text = layout.CultureCode; CultureNameTextBlock.Text = layout.CultureName; LayoutNameTextBlock.Text = layout.LayoutName; - System.Windows.Automation.AutomationProperties.SetHelpText(Button, layout.LayoutName); + System.Windows.Automation.AutomationProperties.SetName(Button, layout.CultureName); } } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/KeyboardLayoutControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/KeyboardLayoutControl.xaml.cs index da280d12..3f4cf0dc 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/KeyboardLayoutControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/KeyboardLayoutControl.xaml.cs @@ -10,6 +10,7 @@ using System; using System.Linq; using System.Threading.Tasks; using System.Windows; +using System.Windows.Automation; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Media; @@ -53,9 +54,31 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar ((LayoutsStackPanel.Children[0] as ContentControl).Content as UIElement).Focus(); }))); }; - Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); + var lastOpenedBySpacePress = false; + Button.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback); - Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); Popup.Opened += (o, args) => { @@ -67,6 +90,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar { Background = originalBrush; Button.Background = originalBrush; + lastOpenedBySpacePress = false; }; } @@ -120,6 +144,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar LayoutCultureCode.Text = layout.CultureCode; Button.ToolTip = tooltip; + AutomationProperties.SetName(Button, tooltip); } private void Popup_KeyUp(object sender, System.Windows.Input.KeyEventArgs e) diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkButton.xaml.cs index cc3ec142..bc1d7025 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkButton.xaml.cs @@ -34,5 +34,10 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar NetworkNameTextBlock.Text = network.Name; SignalStrengthTextBlock.Text = $"{network.SignalStrength}%"; } + + public void SetFocus() + { + Button.Focus(); + } } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkControl.xaml.cs index 3832f57e..b9bf15d9 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NetworkControl.xaml.cs @@ -45,22 +45,56 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar var originalBrush = Button.Background; adapter.Changed += () => Dispatcher.InvokeAsync(Update); + var lastOpenedBySpacePress = false; + Button.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; - Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback); - Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); WirelessIcon.Child = GetWirelessIcon(0); Popup.Opened += (o, args) => { Background = Brushes.LightGray; Button.Background = Brushes.LightGray; + Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() => + { + if (WirelessNetworksStackPanel.Children.Count > 0) + { + var btn = WirelessNetworksStackPanel.Children[0] as NetworkButton; + if (btn != null) + { + btn.SetFocus(); + } + } + })); }; Popup.Closed += (o, args) => { Background = originalBrush; Button.Background = originalBrush; + lastOpenedBySpacePress = false; }; Update(); @@ -87,8 +121,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar if (network.Status == ConnectionStatus.Connected) { WirelessIcon.Child = GetWirelessIcon(network.SignalStrength); - Button.ToolTip = text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name); - Button.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, Button.ToolTip as string); + UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name)); } WirelessNetworksStackPanel.Children.Add(button); @@ -98,7 +131,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar { case ConnectionType.Wired: Button.IsEnabled = false; - Button.ToolTip = text.Get(TextKey.SystemControl_NetworkWiredConnected); + UpdateText(text.Get(TextKey.SystemControl_NetworkWiredConnected)); WiredIcon.Visibility = Visibility.Visible; WirelessIcon.Visibility = Visibility.Collapsed; break; @@ -109,7 +142,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar break; default: Button.IsEnabled = false; - Button.ToolTip = text.Get(TextKey.SystemControl_NetworkNotAvailable); + UpdateText(text.Get(TextKey.SystemControl_NetworkNotAvailable)); WiredIcon.Visibility = Visibility.Visible; WirelessIcon.Visibility = Visibility.Collapsed; break; @@ -118,19 +151,20 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar switch (adapter.Status) { case ConnectionStatus.Connected: + UpdateText(text.Get(TextKey.SystemControl_NetworkWiredConnected)); NetworkStatusIcon.Rotation = 0; NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Globe, Brushes.Green); NetworkStatusIcon.Spin = false; break; case ConnectionStatus.Connecting: - Button.ToolTip = text.Get(TextKey.SystemControl_NetworkWirelessConnecting); + UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnecting)); NetworkStatusIcon.Rotation = 0; NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Cog, Brushes.DimGray); NetworkStatusIcon.Spin = true; NetworkStatusIcon.SpinDuration = 2; break; default: - Button.ToolTip = text.Get(TextKey.SystemControl_NetworkDisconnected); + UpdateText(text.Get(TextKey.SystemControl_NetworkDisconnected)); NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Ban, Brushes.DarkOrange); NetworkStatusIcon.Spin = false; WirelessIcon.Child = GetWirelessIcon(0); @@ -138,6 +172,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar } } + private void UpdateText(string text) + { + Button.ToolTip = text; + Button.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text); + } + private UIElement GetWirelessIcon(int signalStrength) { var icon = signalStrength > 66 ? "100" : (signalStrength > 33 ? "66" : (signalStrength > 0 ? "33" : "0")); diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NotificationButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NotificationButton.xaml.cs index 6c1a7f3f..b415cbf0 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NotificationButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/NotificationButton.xaml.cs @@ -41,6 +41,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar { IconButton.ToolTip = notification.Tooltip; IconButton.Content = IconResourceLoader.Load(notification.IconResource); + System.Windows.Automation.AutomationProperties.SetName(this, notification.Tooltip); } } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/PowerSupplyControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/PowerSupplyControl.xaml.cs index 7c80bb12..d6059666 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/PowerSupplyControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/PowerSupplyControl.xaml.cs @@ -101,7 +101,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar Button.ToolTip = tooltip; PowerPlug.Visibility = status.IsOnline ? Visibility.Visible : Visibility.Collapsed; Warning.Visibility = status.BatteryChargeStatus == BatteryChargeStatus.Critical ? Visibility.Visible : Visibility.Collapsed; - this.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, tooltip); + this.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, tooltip); } private void RenderCharge(double charge, BatteryChargeStatus status) diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/RaiseHandControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/RaiseHandControl.xaml.cs index 774cca6e..01aeb2ac 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/RaiseHandControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/Taskbar/RaiseHandControl.xaml.cs @@ -55,13 +55,35 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar RaisedIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Hand_Raised.xaml") }; Icon.Content = IconResourceLoader.Load(LoweredIcon); - NotificationButton.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); + var lastOpenedBySpacePress = false; + NotificationButton.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + NotificationButton.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); NotificationButton.PreviewMouseLeftButtonUp += NotificationButton_PreviewMouseLeftButtonUp; NotificationButton.PreviewMouseRightButtonUp += NotificationButton_PreviewMouseRightButtonUp; NotificationButton.ToolTip = text.Get(TextKey.Notification_ProctoringHandLowered); Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback); - Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); Popup.Opened += (o, args) => { Background = Brushes.LightGray; @@ -71,6 +93,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls.Taskbar { Background = originalBrush; NotificationButton.Background = originalBrush; + lastOpenedBySpacePress = false; }; } diff --git a/SafeExamBrowser.UserInterface.Desktop/Windows/BrowserWindow.xaml b/SafeExamBrowser.UserInterface.Desktop/Windows/BrowserWindow.xaml index cd4b266d..a7a7753b 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Windows/BrowserWindow.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Windows/BrowserWindow.xaml @@ -80,7 +80,7 @@ - diff --git a/SafeExamBrowser.UserInterface.Desktop/Windows/BrowserWindow.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Windows/BrowserWindow.xaml.cs index 1f8eead6..8cea8688 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Windows/BrowserWindow.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Windows/BrowserWindow.xaml.cs @@ -244,8 +244,8 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows Dispatcher.Invoke(() => { ZoomLevel.Text = $"{value}%"; - var zoomButtonHelpText = text.Get(TextKey.BrowserWindow_ZoomLevelReset).Replace("%%ZOOM%%", value.ToString("0")); - ZoomResetButton.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, zoomButtonHelpText); + var zoomButtonName = text.Get(TextKey.BrowserWindow_ZoomLevelReset).Replace("%%ZOOM%%", value.ToString("0")); + ZoomResetButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, zoomButtonName); }); } @@ -477,9 +477,8 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows HomeButton.Click += (o, args) => HomeNavigationRequested?.Invoke(); Loaded += BrowserWindow_Loaded; MenuButton.Click += MenuButton_Click; - MenuButton.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => MenuPopup.IsOpen = MenuPopup.IsMouseOver)); MenuPopup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback); - MenuPopup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => MenuPopup.IsOpen = MenuPopup.IsMouseOver)); + MenuPopup.LostFocus += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => MenuPopup.IsOpen = MenuPopup.IsKeyboardFocusWithin)); KeyDown += BrowserWindow_KeyDown; KeyUp += BrowserWindow_KeyUp; LocationChanged += (o, args) => { DownloadsPopup.IsOpen = false; MenuPopup.IsOpen = false; }; @@ -512,7 +511,8 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows var javascript = @" if (typeof __SEB_focusElement === 'undefined') { __SEB_focusElement = function (forward) { - if (!document.body) { return; } + if (!document.body) + return; var items = [].map .call(document.body.querySelectorAll(['input', 'select', 'a[href]', 'textarea', 'button', '[tabindex]']), function(el, i) { return { el, i } }) .filter(function(e) { return e.el.tabIndex >= 0 && !e.el.disabled && e.el.offsetParent; }) @@ -640,13 +640,13 @@ if (typeof __SEB_focusElement === 'undefined') { private void LoadText() { DeveloperConsoleText.Text = text.Get(TextKey.BrowserWindow_DeveloperConsoleMenuItem); - DeveloperConsoleButton.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, text.Get(TextKey.BrowserWindow_DeveloperConsoleMenuItem)); + DeveloperConsoleButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_DeveloperConsoleMenuItem)); FindCaseSensitiveCheckBox.Content = text.Get(TextKey.BrowserWindow_FindCaseSensitive); FindMenuText.Text = text.Get(TextKey.BrowserWindow_FindMenuItem); - FindMenuButton.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, text.Get(TextKey.BrowserWindow_FindMenuItem)); + FindMenuButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_FindMenuItem)); ZoomText.Text = text.Get(TextKey.BrowserWindow_ZoomMenuItem); - ZoomInButton.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, text.Get(TextKey.BrowserWindow_ZoomMenuPlus)); - ZoomOutButton.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, text.Get(TextKey.BrowserWindow_ZoomMenuMinus)); + ZoomInButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_ZoomMenuPlus)); + ZoomOutButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_ZoomMenuMinus)); ReloadButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_ReloadButton)); BackwardButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_BackwardButton)); ForwardButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_ForwardButton)); @@ -654,6 +654,10 @@ if (typeof __SEB_focusElement === 'undefined') { HomeButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_HomeButton)); MenuButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_MenuButton)); UrlTextBox.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_UrlTextBox)); + FindTextBox.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_SearchTextBox)); + FindPreviousButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_SearchPrevious)); + FindNextButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_SearchNext)); + FindbarCloseButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_CloseButton)); } } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/ApplicationButton.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/ApplicationButton.xaml.cs index aa80dde3..a821822b 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/ApplicationButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/ApplicationButton.xaml.cs @@ -35,7 +35,9 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter Icon.Content = IconResourceLoader.Load(window?.Icon ?? application.Icon); Text.Text = window?.Title ?? application.Name; Button.Click += (o, args) => Clicked?.Invoke(this, EventArgs.Empty); - Button.ToolTip = window?.Title ?? application.Tooltip; + var tooltip = window?.Title ?? application.Tooltip; + Button.ToolTip = tooltip; + System.Windows.Automation.AutomationProperties.SetName(Button, tooltip); if (window != null) { diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/AudioControl.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/AudioControl.xaml index b6c38225..948348d4 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/AudioControl.xaml +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/AudioControl.xaml @@ -21,7 +21,7 @@ diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/AudioControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/AudioControl.xaml.cs index a8e57a3e..5df57574 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/AudioControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/AudioControl.xaml.cs @@ -49,13 +49,39 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter audio.VolumeChanged += Audio_VolumeChanged; Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; - Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); + var lastOpenedBySpacePress = false; + Button.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); MuteButton.Click += MuteButton_Click; MutedIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_Muted.xaml") }; NoDeviceIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_Light_NoDevice.xaml") }; - Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); Popup.Opened += (o, args) => Grid.Background = Brushes.Gray; - Popup.Closed += (o, args) => Grid.Background = originalBrush; + Popup.Closed += (o, args) => + { + Grid.Background = originalBrush; + lastOpenedBySpacePress = false; + }; Volume.ValueChanged += Volume_ValueChanged; if (audio.HasOutputDevice) @@ -113,6 +139,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter this.muted = muted; Button.ToolTip = info; + System.Windows.Automation.AutomationProperties.SetName(Button, info); Text.Text = info; Volume.ValueChanged -= Volume_ValueChanged; Volume.Value = Math.Round(volume * 100); @@ -120,14 +147,18 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter if (muted) { + var tooltip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); + MuteButton.ToolTip = tooltip; + System.Windows.Automation.AutomationProperties.SetName(MuteButton, tooltip); ButtonIcon.Content = IconResourceLoader.Load(MutedIcon); - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); PopupIcon.Content = IconResourceLoader.Load(MutedIcon); } else { + var tooltip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); + MuteButton.ToolTip = tooltip; + System.Windows.Automation.AutomationProperties.SetName(MuteButton, tooltip); ButtonIcon.Content = LoadIcon(volume); - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); PopupIcon.Content = LoadIcon(volume); } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/KeyboardLayoutButton.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/KeyboardLayoutButton.xaml.cs index 7813146a..1b14edb7 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/KeyboardLayoutButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/KeyboardLayoutButton.xaml.cs @@ -43,6 +43,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter CultureCodeTextBlock.Text = layout.CultureCode; CultureNameTextBlock.Text = layout.CultureName; LayoutNameTextBlock.Text = layout.LayoutName; + System.Windows.Automation.AutomationProperties.SetName(Button, layout.CultureName); } } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/KeyboardLayoutControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/KeyboardLayoutControl.xaml.cs index eeed1afd..43912d1d 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/KeyboardLayoutControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/KeyboardLayoutControl.xaml.cs @@ -6,7 +6,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System; using System.Threading.Tasks; +using System.Windows.Automation; using System.Windows.Controls; using System.Windows.Media; using SafeExamBrowser.I18n.Contracts; @@ -49,10 +51,36 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter LayoutsStackPanel.Children[0].Focus(); })); }; - 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)); + var lastOpenedBySpacePress = false; + Button.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); Popup.Opened += (o, args) => Grid.Background = Brushes.Gray; - Popup.Closed += (o, args) => Grid.Background = originalBrush; + Popup.Closed += (o, args) => + { + Grid.Background = originalBrush; + lastOpenedBySpacePress = false; + }; } private void Keyboard_LayoutChanged(IKeyboardLayout layout) @@ -96,6 +124,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter Text.Text = layout.CultureName; Button.ToolTip = tooltip; + AutomationProperties.SetName(Button, tooltip); } private void Popup_KeyUp(object sender, System.Windows.Input.KeyEventArgs e) diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkButton.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkButton.xaml.cs index f464dccf..f8456e50 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkButton.xaml.cs @@ -34,5 +34,10 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter NetworkNameTextBlock.Text = network.Name; SignalStrengthTextBlock.Text = $"{network.SignalStrength}%"; } + + public void SetFocus() + { + Button.Focus(); + } } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkControl.xaml.cs index 4b50365a..9231578b 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/NetworkControl.xaml.cs @@ -45,10 +45,50 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter adapter.Changed += () => Dispatcher.InvokeAsync(Update); 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)); - Popup.Opened += (o, args) => Grid.Background = Brushes.Gray; - Popup.Closed += (o, args) => Grid.Background = originalBrush; + var lastOpenedBySpacePress = false; + Button.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); + Popup.Opened += (o, args) => + { + Grid.Background = Brushes.Gray; + Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() => + { + if (WirelessNetworksStackPanel.Children.Count > 0) + { + var btn = WirelessNetworksStackPanel.Children[0] as NetworkButton; + if (btn != null) + { + btn.SetFocus(); + } + } + })); + }; + Popup.Closed += (o, args) => + { + Grid.Background = originalBrush; + lastOpenedBySpacePress = false; + }; WirelessIcon.Child = GetWirelessIcon(0); Update(); @@ -121,7 +161,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter { Button.ToolTip = text; Text.Text = text; - Button.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, text); + Button.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text); } private UIElement GetWirelessIcon(int signalStrength) diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/PowerSupplyControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/PowerSupplyControl.xaml.cs index 4985f0bb..adedb3c8 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/PowerSupplyControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/PowerSupplyControl.xaml.cs @@ -87,7 +87,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter PowerPlug.Visibility = status.IsOnline ? Visibility.Visible : Visibility.Collapsed; Text.Text = tooltip; Warning.Visibility = status.BatteryChargeStatus == BatteryChargeStatus.Critical ? Visibility.Visible : Visibility.Collapsed; - this.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, tooltip); + this.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, tooltip); } private void RenderCharge(double charge, BatteryChargeStatus status) diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/RaiseHandControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/RaiseHandControl.xaml.cs index f7f22918..b07add7f 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/RaiseHandControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/ActionCenter/RaiseHandControl.xaml.cs @@ -55,15 +55,41 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter RaisedIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Hand_Raised.xaml") }; Icon.Content = IconResourceLoader.Load(LoweredIcon); - NotificationButton.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); + var lastOpenedBySpacePress = false; + NotificationButton.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + NotificationButton.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); NotificationButton.PreviewMouseLeftButtonUp += NotificationButton_PreviewMouseLeftButtonUp; NotificationButton.PreviewMouseRightButtonUp += NotificationButton_PreviewMouseRightButtonUp; NotificationButton.ToolTip = text.Get(TextKey.Notification_ProctoringHandLowered); Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback); - Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); Popup.Opened += (o, args) => Grid.Background = Brushes.Gray; - Popup.Closed += (o, args) => Grid.Background = originalBrush; + Popup.Closed += (o, args) => + { + Grid.Background = originalBrush; + lastOpenedBySpacePress = false; + }; Text.Text = text.Get(TextKey.Notification_ProctoringHandLowered); } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/ApplicationControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/ApplicationControl.xaml.cs index 195043af..aa85c490 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/ApplicationControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/ApplicationControl.xaml.cs @@ -44,6 +44,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar Button.MouseEnter += (o, args) => WindowPopup.IsOpen = WindowStackPanel.Children.Count > 0; Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => WindowPopup.IsOpen = WindowPopup.IsMouseOver || ActiveBar.IsMouseOver)); Button.ToolTip = application.Tooltip; + System.Windows.Automation.AutomationProperties.SetName(Button, application.Tooltip); WindowPopup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(WindowPopup_PlacementCallback); WindowPopup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => WindowPopup.IsOpen = IsMouseOver)); diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/AudioControl.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/AudioControl.xaml index a17d3fe5..4fd4f2a2 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/AudioControl.xaml +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/AudioControl.xaml @@ -22,7 +22,7 @@ diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/AudioControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/AudioControl.xaml.cs index 350f94d5..ec1b72a8 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/AudioControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/AudioControl.xaml.cs @@ -48,12 +48,34 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar audio.VolumeChanged += Audio_VolumeChanged; Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; - Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); + var lastOpenedBySpacePress = false; + Button.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); MuteButton.Click += MuteButton_Click; MutedIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_Muted.xaml") }; NoDeviceIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_NoDevice.xaml") }; Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback); - Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); Volume.ValueChanged += Volume_ValueChanged; Popup.Opened += (o, args) => @@ -67,6 +89,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar { Background = originalBrush; Button.Background = originalBrush; + lastOpenedBySpacePress = false; }; if (audio.HasOutputDevice) @@ -132,19 +155,24 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar this.muted = muted; Button.ToolTip = info; + System.Windows.Automation.AutomationProperties.SetName(Button, info); Volume.ValueChanged -= Volume_ValueChanged; Volume.Value = Math.Round(volume * 100); Volume.ValueChanged += Volume_ValueChanged; if (muted) { - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); + var tooltip = text.Get(TextKey.SystemControl_AudioDeviceUnmuteTooltip); + MuteButton.ToolTip = tooltip; + System.Windows.Automation.AutomationProperties.SetName(MuteButton, tooltip); PopupIcon.Content = IconResourceLoader.Load(MutedIcon); ButtonIcon.Content = IconResourceLoader.Load(MutedIcon); } else { - MuteButton.ToolTip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); + var tooltip = text.Get(TextKey.SystemControl_AudioDeviceMuteTooltip); + MuteButton.ToolTip = tooltip; + System.Windows.Automation.AutomationProperties.SetName(MuteButton, tooltip); PopupIcon.Content = LoadIcon(volume); ButtonIcon.Content = LoadIcon(volume); } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/Clock.xaml b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/Clock.xaml index 97aa83ba..0af201b4 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/Clock.xaml +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/Clock.xaml @@ -11,7 +11,7 @@ - - + + diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/KeyboardLayoutButton.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/KeyboardLayoutButton.xaml.cs index 89f7f336..a1d2812b 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/KeyboardLayoutButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/KeyboardLayoutButton.xaml.cs @@ -43,7 +43,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar CultureCodeTextBlock.Text = layout.CultureCode; CultureNameTextBlock.Text = layout.CultureName; LayoutNameTextBlock.Text = layout.LayoutName; - System.Windows.Automation.AutomationProperties.SetHelpText(Button, layout.LayoutName); + System.Windows.Automation.AutomationProperties.SetName(Button, layout.CultureName); } } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/KeyboardLayoutControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/KeyboardLayoutControl.xaml.cs index 091ce98d..5195ccf1 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/KeyboardLayoutControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/KeyboardLayoutControl.xaml.cs @@ -10,6 +10,7 @@ using System; using System.Linq; using System.Threading.Tasks; using System.Windows; +using System.Windows.Automation; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Media; @@ -53,9 +54,31 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar ((LayoutsStackPanel.Children[0] as ContentControl).Content as UIElement).Focus(); }))); }; - Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); + var lastOpenedBySpacePress = false; + Button.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback); - Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); Popup.Opened += (o, args) => { @@ -67,6 +90,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar { Background = originalBrush; Button.Background = originalBrush; + lastOpenedBySpacePress = false; }; } @@ -120,6 +144,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar LayoutCultureCode.Text = layout.CultureCode; Button.ToolTip = tooltip; + AutomationProperties.SetName(Button, tooltip); } private void Popup_KeyUp(object sender, System.Windows.Input.KeyEventArgs e) diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkButton.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkButton.xaml.cs index 76328c51..39f456e6 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkButton.xaml.cs @@ -34,5 +34,10 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar NetworkNameTextBlock.Text = network.Name; SignalStrengthTextBlock.Text = $"{network.SignalStrength}%"; } + + public void SetFocus() + { + Button.Focus(); + } } } diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkControl.xaml.cs index 0c065270..89360a6a 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/NetworkControl.xaml.cs @@ -46,21 +46,55 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar adapter.Changed += () => Dispatcher.InvokeAsync(Update); Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; - Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); + var lastOpenedBySpacePress = false; + Button.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback); - Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); WirelessIcon.Child = GetWirelessIcon(0); Popup.Opened += (o, args) => { Background = Brushes.LightGray; Button.Background = Brushes.LightGray; + Task.Delay(100).ContinueWith((task) => Dispatcher.Invoke(() => + { + if (WirelessNetworksStackPanel.Children.Count > 0) + { + var btn = WirelessNetworksStackPanel.Children[0] as NetworkButton; + if (btn != null) + { + btn.SetFocus(); + } + } + })); }; Popup.Closed += (o, args) => { Background = originalBrush; Button.Background = originalBrush; + lastOpenedBySpacePress = false; }; Update(); @@ -87,8 +121,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar if (network.Status == ConnectionStatus.Connected) { WirelessIcon.Child = GetWirelessIcon(network.SignalStrength); - Button.ToolTip = text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name); - Button.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, Button.ToolTip as string); + UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnected).Replace("%%NAME%%", network.Name)); } WirelessNetworksStackPanel.Children.Add(button); @@ -98,7 +131,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar { case ConnectionType.Wired: Button.IsEnabled = false; - Button.ToolTip = text.Get(TextKey.SystemControl_NetworkWiredConnected); + UpdateText(text.Get(TextKey.SystemControl_NetworkWiredConnected)); WiredIcon.Visibility = Visibility.Visible; WirelessIcon.Visibility = Visibility.Collapsed; break; @@ -109,7 +142,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar break; default: Button.IsEnabled = false; - Button.ToolTip = text.Get(TextKey.SystemControl_NetworkNotAvailable); + UpdateText(text.Get(TextKey.SystemControl_NetworkNotAvailable)); WiredIcon.Visibility = Visibility.Visible; WirelessIcon.Visibility = Visibility.Collapsed; break; @@ -118,19 +151,20 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar switch (adapter.Status) { case ConnectionStatus.Connected: + UpdateText(text.Get(TextKey.SystemControl_NetworkWiredConnected)); NetworkStatusIcon.Rotation = 0; NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Globe, Brushes.Green); NetworkStatusIcon.Spin = false; break; case ConnectionStatus.Connecting: - Button.ToolTip = text.Get(TextKey.SystemControl_NetworkWirelessConnecting); + UpdateText(text.Get(TextKey.SystemControl_NetworkWirelessConnecting)); NetworkStatusIcon.Rotation = 0; NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Cog, Brushes.DimGray); NetworkStatusIcon.Spin = true; NetworkStatusIcon.SpinDuration = 2; break; default: - Button.ToolTip = text.Get(TextKey.SystemControl_NetworkDisconnected); + UpdateText(text.Get(TextKey.SystemControl_NetworkDisconnected)); NetworkStatusIcon.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Ban, Brushes.DarkOrange); NetworkStatusIcon.Spin = false; WirelessIcon.Child = GetWirelessIcon(0); @@ -138,6 +172,12 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar } } + private void UpdateText(string text) + { + Button.ToolTip = text; + Button.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text); + } + private UIElement GetWirelessIcon(int signalStrength) { var icon = signalStrength > 66 ? "100" : (signalStrength > 33 ? "66" : (signalStrength > 0 ? "33" : "0")); diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/PowerSupplyControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/PowerSupplyControl.xaml.cs index a0eae5f1..61f9915a 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/PowerSupplyControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/PowerSupplyControl.xaml.cs @@ -101,7 +101,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar Button.ToolTip = tooltip; PowerPlug.Visibility = status.IsOnline ? Visibility.Visible : Visibility.Collapsed; Warning.Visibility = status.BatteryChargeStatus == BatteryChargeStatus.Critical ? Visibility.Visible : Visibility.Collapsed; - this.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, tooltip); + this.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, tooltip); } private void RenderCharge(double charge, BatteryChargeStatus status) diff --git a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/RaiseHandControl.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/RaiseHandControl.xaml.cs index 0c3c0690..68772cb3 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/RaiseHandControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Controls/Taskbar/RaiseHandControl.xaml.cs @@ -55,13 +55,35 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar RaisedIcon = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Hand_Raised.xaml") }; Icon.Content = IconResourceLoader.Load(LoweredIcon); - NotificationButton.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); + var lastOpenedBySpacePress = false; + NotificationButton.PreviewKeyDown += (o, args) => + { + if (args.Key == System.Windows.Input.Key.Space) // for some reason, the popup immediately closes again if opened by a Space Bar key event - as a mitigation, we record the space bar event and leave the popup open for at least 3 seconds + { + lastOpenedBySpacePress = true; + } + }; + NotificationButton.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = Popup.IsMouseOver; + })); NotificationButton.PreviewMouseLeftButtonUp += NotificationButton_PreviewMouseLeftButtonUp; NotificationButton.PreviewMouseRightButtonUp += NotificationButton_PreviewMouseRightButtonUp; NotificationButton.ToolTip = text.Get(TextKey.Notification_ProctoringHandLowered); Popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback); - Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => + { + if (Popup.IsOpen && lastOpenedBySpacePress) + { + return; + } + Popup.IsOpen = IsMouseOver; + })); Popup.Opened += (o, args) => { Background = Brushes.LightGray; @@ -72,6 +94,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls.Taskbar { Background = originalBrush; NotificationButton.Background = originalBrush; + lastOpenedBySpacePress = false; }; } diff --git a/SafeExamBrowser.UserInterface.Mobile/Windows/BrowserWindow.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/Windows/BrowserWindow.xaml.cs index 7e0f4e29..066317ff 100644 --- a/SafeExamBrowser.UserInterface.Mobile/Windows/BrowserWindow.xaml.cs +++ b/SafeExamBrowser.UserInterface.Mobile/Windows/BrowserWindow.xaml.cs @@ -244,8 +244,8 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows Dispatcher.Invoke(() => { ZoomLevel.Text = $"{value}%"; - var zoomButtonHelpText = text.Get(TextKey.BrowserWindow_ZoomLevelReset).Replace("%%ZOOM%%", value.ToString("0")); - ZoomResetButton.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, zoomButtonHelpText); + var zoomButtonName = text.Get(TextKey.BrowserWindow_ZoomLevelReset).Replace("%%ZOOM%%", value.ToString("0")); + ZoomResetButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, zoomButtonName); }); } @@ -473,9 +473,8 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows HomeButton.Click += (o, args) => HomeNavigationRequested?.Invoke(); Loaded += BrowserWindow_Loaded; MenuButton.Click += MenuButton_Click; - MenuButton.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => MenuPopup.IsOpen = MenuPopup.IsMouseOver)); MenuPopup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(Popup_PlacementCallback); - MenuPopup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => MenuPopup.IsOpen = MenuPopup.IsMouseOver)); + MenuPopup.LostFocus += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => MenuPopup.IsOpen = MenuPopup.IsKeyboardFocusWithin)); KeyDown += BrowserWindow_KeyDown; KeyUp += BrowserWindow_KeyUp; LocationChanged += (o, args) => { DownloadsPopup.IsOpen = false; MenuPopup.IsOpen = false; }; @@ -646,13 +645,13 @@ if (typeof __SEB_focusElement === 'undefined') { private void LoadText() { DeveloperConsoleText.Text = text.Get(TextKey.BrowserWindow_DeveloperConsoleMenuItem); - DeveloperConsoleButton.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, text.Get(TextKey.BrowserWindow_DeveloperConsoleMenuItem)); + DeveloperConsoleButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_DeveloperConsoleMenuItem)); FindCaseSensitiveCheckBox.Content = text.Get(TextKey.BrowserWindow_FindCaseSensitive); FindMenuText.Text = text.Get(TextKey.BrowserWindow_FindMenuItem); - FindMenuButton.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, text.Get(TextKey.BrowserWindow_FindMenuItem)); + FindMenuButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_FindMenuItem)); ZoomText.Text = text.Get(TextKey.BrowserWindow_ZoomMenuItem); - ZoomInButton.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, text.Get(TextKey.BrowserWindow_ZoomMenuPlus)); - ZoomOutButton.SetValue(System.Windows.Automation.AutomationProperties.HelpTextProperty, text.Get(TextKey.BrowserWindow_ZoomMenuMinus)); + ZoomInButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_ZoomMenuPlus)); + ZoomOutButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_ZoomMenuMinus)); ReloadButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_ReloadButton)); BackwardButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_BackwardButton)); ForwardButton.SetValue(System.Windows.Automation.AutomationProperties.NameProperty, text.Get(TextKey.BrowserWindow_ForwardButton));