2019-03-21 16:05:16 +01:00
/ *
2022-01-21 16:33:52 +01:00
* Copyright ( c ) 2022 ETH Zürich , Educational Development and Technology ( LET )
2019-03-21 16:05:16 +01:00
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/.
* /
2023-02-13 13:39:53 +01:00
using System ;
2019-03-21 16:05:16 +01:00
using System.Threading.Tasks ;
2022-09-22 11:28:33 +02:00
using System.Windows.Automation ;
2019-03-21 16:05:16 +01:00
using System.Windows.Controls ;
using System.Windows.Media ;
2019-08-30 15:59:51 +02:00
using SafeExamBrowser.I18n.Contracts ;
using SafeExamBrowser.SystemComponents.Contracts.Keyboard ;
2019-08-30 09:55:26 +02:00
using SafeExamBrowser.UserInterface.Contracts.Shell ;
2019-03-21 16:05:16 +01:00
2020-03-17 10:37:08 +01:00
namespace SafeExamBrowser.UserInterface.Mobile.Controls.ActionCenter
2019-03-21 16:05:16 +01:00
{
2020-03-17 10:37:08 +01:00
internal partial class KeyboardLayoutControl : UserControl , ISystemControl
2019-03-21 16:05:16 +01:00
{
2019-08-30 15:59:51 +02:00
private IKeyboard keyboard ;
private IText text ;
2019-03-21 16:05:16 +01:00
2020-03-17 10:37:08 +01:00
internal KeyboardLayoutControl ( IKeyboard keyboard , IText text )
2019-03-21 16:05:16 +01:00
{
2019-08-30 15:59:51 +02:00
this . keyboard = keyboard ;
this . text = text ;
2019-03-21 16:05:16 +01:00
InitializeComponent ( ) ;
InitializeKeyboardLayoutControl ( ) ;
}
2019-08-30 15:59:51 +02:00
public void Close ( )
2019-03-21 16:05:16 +01:00
{
2019-08-30 15:59:51 +02:00
Dispatcher . Invoke ( ( ) = > Popup . IsOpen = false ) ;
}
2019-03-21 16:05:16 +01:00
2019-08-30 15:59:51 +02:00
private void InitializeKeyboardLayoutControl ( )
{
var originalBrush = Grid . Background ;
2019-03-21 16:05:16 +01:00
2019-08-30 15:59:51 +02:00
InitializeLayouts ( ) ;
keyboard . LayoutChanged + = Keyboard_LayoutChanged ;
2022-05-18 10:51:58 +02:00
Button . Click + = ( o , args ) = >
{
Popup . IsOpen = ! Popup . IsOpen ;
this . Dispatcher . BeginInvoke ( ( System . Action ) ( ( ) = >
{
LayoutsStackPanel . Children [ 0 ] . Focus ( ) ;
} ) ) ;
} ;
2023-02-13 13:39:53 +01:00
var lastOpenedBySpacePress = DateTime . MinValue ;
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 = DateTime . Now ;
}
} ;
Button . MouseLeave + = ( o , args ) = > Task . Delay ( 250 ) . ContinueWith ( _ = > Dispatcher . Invoke ( ( ) = >
{
if ( Popup . IsOpen & & ( DateTime . Now - lastOpenedBySpacePress ) . TotalSeconds < 3 )
{
return ;
}
Popup . IsOpen = Popup . IsMouseOver ;
} ) ) ;
2019-08-30 15:59:51 +02:00
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 ;
2019-03-21 16:05:16 +01:00
}
2019-08-30 15:59:51 +02:00
private void Keyboard_LayoutChanged ( IKeyboardLayout layout )
2019-03-21 16:05:16 +01:00
{
2019-08-30 15:59:51 +02:00
Dispatcher . InvokeAsync ( ( ) = > SetCurrent ( layout ) ) ;
2019-03-21 16:05:16 +01:00
}
2019-08-30 15:59:51 +02:00
private void InitializeLayouts ( )
2019-03-21 16:05:16 +01:00
{
2019-08-30 15:59:51 +02:00
foreach ( var layout in keyboard . GetLayouts ( ) )
2019-03-21 16:05:16 +01:00
{
2020-03-17 10:37:08 +01:00
var button = new KeyboardLayoutButton ( layout ) ;
2019-08-30 15:59:51 +02:00
button . LayoutSelected + = ( o , args ) = > ActivateLayout ( layout ) ;
LayoutsStackPanel . Children . Add ( button ) ;
if ( layout . IsCurrent )
2019-03-21 16:05:16 +01:00
{
2019-08-30 15:59:51 +02:00
SetCurrent ( layout ) ;
2019-03-21 16:05:16 +01:00
}
2019-08-30 15:59:51 +02:00
}
2019-03-21 16:05:16 +01:00
}
2019-08-30 15:59:51 +02:00
private void ActivateLayout ( IKeyboardLayout layout )
2019-03-21 16:05:16 +01:00
{
2019-08-30 15:59:51 +02:00
Popup . IsOpen = false ;
keyboard . ActivateLayout ( layout . Id ) ;
2019-03-21 16:05:16 +01:00
}
2019-08-30 15:59:51 +02:00
private void SetCurrent ( IKeyboardLayout layout )
2019-03-21 16:05:16 +01:00
{
2022-04-26 16:45:53 +02:00
var tooltip = text . Get ( TextKey . SystemControl_KeyboardLayoutTooltip ) . Replace ( "%%LAYOUT%%" , layout . CultureName ) ;
2019-03-21 16:05:16 +01:00
2019-08-30 15:59:51 +02:00
foreach ( var child in LayoutsStackPanel . Children )
{
2020-03-17 10:37:08 +01:00
if ( child is KeyboardLayoutButton layoutButton )
2019-08-30 15:59:51 +02:00
{
layoutButton . IsCurrent = layout . Id = = layoutButton . LayoutId ;
}
}
2019-03-21 16:05:16 +01:00
2022-04-26 16:45:53 +02:00
Text . Text = layout . CultureName ;
2019-08-30 15:59:51 +02:00
Button . ToolTip = tooltip ;
2022-10-07 14:38:31 +02:00
AutomationProperties . SetName ( Button , tooltip ) ;
2019-03-21 16:05:16 +01:00
}
2022-05-18 10:51:58 +02:00
private void Popup_KeyUp ( object sender , System . Windows . Input . KeyEventArgs e )
{
if ( e . Key = = System . Windows . Input . Key . Enter | | e . Key = = System . Windows . Input . Key . Escape )
{
Popup . IsOpen = false ;
Button . Focus ( ) ;
}
}
2019-03-21 16:05:16 +01:00
}
}