2020-04-18 16:12:26 -07:00
# include "pch.h"
# include "KeyDropDownControl.h"
2020-04-20 21:01:21 -07:00
# include "keyboardmanager/common/Helpers.h"
2020-07-13 11:49:09 -07:00
# include <keyboardmanager/common/KeyboardManagerState.h>
2020-08-13 16:32:15 -07:00
# include "BufferValidationHelpers.h"
2020-10-02 15:36:36 +03:00
# include <common\shared_constants.h>
# include <common\keyboard_layout_impl.h>
2020-10-19 12:27:47 +03:00
# include <modules\keyboardmanager\common\Helpers.h>
2020-04-18 16:12:26 -07:00
// Initialized to null
KeyboardManagerState * KeyDropDownControl : : keyboardManagerState = nullptr ;
2020-10-19 12:27:47 +03:00
// Get selected value of dropdown or -1 if nothing is selected
DWORD KeyDropDownControl : : GetSelectedValue ( ComboBox comboBox )
2020-10-02 15:36:36 +03:00
{
2020-10-19 12:27:47 +03:00
auto dataContext = comboBox . SelectedValue ( ) ;
if ( ! dataContext )
return - 1 ;
2020-10-02 15:36:36 +03:00
2020-10-19 12:27:47 +03:00
auto value = winrt : : unbox_value < hstring > ( dataContext ) ;
return stoi ( std : : wstring ( value ) ) ;
}
void KeyDropDownControl : : SetSelectedValue ( std : : wstring value )
{
this - > dropDown . as < ComboBox > ( ) . SelectedValue ( winrt : : box_value ( value ) ) ;
2020-10-02 15:36:36 +03:00
}
// Get keys name list depending if Disable is in dropdown
2020-10-19 12:27:47 +03:00
std : : vector < std : : pair < DWORD , std : : wstring > > KeyDropDownControl : : GetKeyList ( bool isShortcut , bool renderDisable )
2020-10-02 15:36:36 +03:00
{
auto list = keyboardManagerState - > keyboardMap . GetKeyNameList ( isShortcut ) ;
if ( renderDisable )
{
2020-10-19 12:27:47 +03:00
list . insert ( list . begin ( ) , { CommonSharedConstants : : VK_DISABLED , keyboardManagerState - > keyboardMap . GetKeyName ( CommonSharedConstants : : VK_DISABLED ) } ) ;
2020-10-02 15:36:36 +03:00
}
return list ;
}
2020-04-18 16:12:26 -07:00
// Function to set properties apart from the SelectionChanged event handler
2020-10-02 15:36:36 +03:00
void KeyDropDownControl : : SetDefaultProperties ( bool isShortcut , bool renderDisable )
2020-04-18 16:12:26 -07:00
{
2020-07-13 11:49:09 -07:00
dropDown = ComboBox ( ) ;
warningFlyout = Flyout ( ) ;
warningMessage = TextBlock ( ) ;
2020-05-08 17:34:24 -07:00
if ( ! isShortcut )
{
2020-07-13 11:49:09 -07:00
dropDown . as < ComboBox > ( ) . Width ( KeyboardManagerConstants : : RemapTableDropDownWidth ) ;
2020-05-08 17:34:24 -07:00
}
else
{
2020-07-13 11:49:09 -07:00
dropDown . as < ComboBox > ( ) . Width ( KeyboardManagerConstants : : ShortcutTableDropDownWidth ) ;
2020-05-08 17:34:24 -07:00
}
2020-07-13 11:49:09 -07:00
dropDown . as < ComboBox > ( ) . MaxDropDownHeight ( KeyboardManagerConstants : : TableDropDownHeight ) ;
2020-04-18 16:12:26 -07:00
// Initialise layout attribute
previousLayout = GetKeyboardLayout ( 0 ) ;
2020-10-19 12:27:47 +03:00
dropDown . as < ComboBox > ( ) . SelectedValuePath ( L " DataContext " ) ;
dropDown . as < ComboBox > ( ) . ItemsSource ( KeyboardManagerHelper : : ToBoxValue ( GetKeyList ( isShortcut , renderDisable ) ) ) ;
2020-04-18 16:12:26 -07:00
// drop down open handler - to reload the items with the latest layout
2020-07-13 11:49:09 -07:00
dropDown . as < ComboBox > ( ) . DropDownOpened ( [ & , isShortcut ] ( winrt : : Windows : : Foundation : : IInspectable const & sender , auto args ) {
2020-04-18 16:12:26 -07:00
ComboBox currentDropDown = sender . as < ComboBox > ( ) ;
2020-10-02 15:36:36 +03:00
CheckAndUpdateKeyboardLayout ( currentDropDown , isShortcut , renderDisable ) ;
2020-04-18 16:12:26 -07:00
} ) ;
2020-05-11 10:10:36 -07:00
// Attach flyout to the drop down
2020-07-13 11:49:09 -07:00
warningFlyout . as < Flyout > ( ) . Content ( warningMessage . as < TextBlock > ( ) ) ;
dropDown . as < ComboBox > ( ) . ContextFlyout ( ) . SetAttachedFlyout ( ( FrameworkElement ) dropDown . as < ComboBox > ( ) , warningFlyout . as < Flyout > ( ) ) ;
2020-09-18 17:12:37 -07:00
// To set the accessible name of the combo-box (by default index 1)
SetAccessibleNameForComboBox ( dropDown . as < ComboBox > ( ) , 1 ) ;
}
// Function to set accessible name for combobox
void KeyDropDownControl : : SetAccessibleNameForComboBox ( ComboBox dropDown , int index )
{
// Display name with drop down index (where this indexing will start from 1) - Used by narrator
dropDown . SetValue ( Automation : : AutomationProperties : : NameProperty ( ) , box_value ( GET_RESOURCE_STRING ( IDS_KEY_DROPDOWN_COMBOBOX ) + L " " + std : : to_wstring ( index ) ) ) ;
2020-04-18 16:12:26 -07:00
}
// Function to check if the layout has changed and accordingly update the drop down list
2020-10-02 15:36:36 +03:00
void KeyDropDownControl : : CheckAndUpdateKeyboardLayout ( ComboBox currentDropDown , bool isShortcut , bool renderDisable )
2020-04-18 16:12:26 -07:00
{
// Get keyboard layout for current thread
HKL layout = GetKeyboardLayout ( 0 ) ;
// Check if the layout has changed
if ( previousLayout ! = layout )
{
2020-10-19 12:27:47 +03:00
currentDropDown . ItemsSource ( KeyboardManagerHelper : : ToBoxValue ( GetKeyList ( isShortcut , renderDisable ) ) ) ;
2020-04-18 16:12:26 -07:00
previousLayout = layout ;
}
}
2020-04-23 09:14:16 -07:00
// Function to set selection handler for single key remap drop down. Needs to be called after the constructor since the singleKeyControl StackPanel is null if called in the constructor
2020-08-13 16:32:15 -07:00
void KeyDropDownControl : : SetSelectionHandler ( Grid & table , StackPanel singleKeyControl , int colIndex , RemapBuffer & singleKeyRemapBuffer )
2020-04-23 09:14:16 -07:00
{
2020-04-26 15:09:40 -07:00
// drop down selection handler
2020-05-11 10:10:36 -07:00
auto onSelectionChange = [ & , table , singleKeyControl , colIndex ] ( winrt : : Windows : : Foundation : : IInspectable const & sender ) {
2020-04-23 09:14:16 -07:00
ComboBox currentDropDown = sender . as < ComboBox > ( ) ;
2020-10-19 12:27:47 +03:00
int selectedKeyCode = GetSelectedValue ( currentDropDown ) ;
2020-04-23 09:14:16 -07:00
// Get row index of the single key control
uint32_t controlIndex ;
bool indexFound = table . Children ( ) . IndexOf ( singleKeyControl , controlIndex ) ;
if ( indexFound )
{
2020-09-18 17:12:37 -07:00
// GetRow will give the row index including the table header
int rowIndex = table . GetRow ( singleKeyControl ) - 1 ;
2020-04-26 15:09:40 -07:00
2020-08-13 16:32:15 -07:00
// Validate current remap selection
2020-10-19 12:27:47 +03:00
KeyboardManagerHelper : : ErrorType errorType = BufferValidationHelpers : : ValidateAndUpdateKeyBufferElement ( rowIndex , colIndex , selectedKeyCode , singleKeyRemapBuffer ) ;
2020-04-26 15:09:40 -07:00
2020-08-13 16:32:15 -07:00
// If there is an error set the warning flyout
2020-04-26 15:09:40 -07:00
if ( errorType ! = KeyboardManagerHelper : : ErrorType : : NoError )
{
SetDropDownError ( currentDropDown , KeyboardManagerHelper : : GetErrorMessage ( errorType ) ) ;
}
2020-05-11 10:10:36 -07:00
}
} ;
2020-04-26 15:09:40 -07:00
2020-05-11 10:10:36 -07:00
// Rather than on every selection change (which gets triggered on searching as well) we set the handler only when the drop down is closed
2020-07-13 11:49:09 -07:00
dropDown . as < ComboBox > ( ) . DropDownClosed ( [ onSelectionChange ] ( winrt : : Windows : : Foundation : : IInspectable const & sender , auto const & args ) {
2020-05-11 10:10:36 -07:00
onSelectionChange ( sender ) ;
} ) ;
// We check if the selection changed was triggered while the drop down was closed. This is required to handle Type key, initial loading of remaps and if the user just types in the combo box without opening it
2020-07-13 11:49:09 -07:00
dropDown . as < ComboBox > ( ) . SelectionChanged ( [ onSelectionChange ] ( winrt : : Windows : : Foundation : : IInspectable const & sender , SelectionChangedEventArgs const & args ) {
2020-05-11 10:10:36 -07:00
ComboBox currentDropDown = sender . as < ComboBox > ( ) ;
if ( ! currentDropDown . IsDropDownOpen ( ) )
{
onSelectionChange ( sender ) ;
2020-04-23 09:14:16 -07:00
}
} ) ;
}
2020-08-13 16:32:15 -07:00
std : : pair < KeyboardManagerHelper : : ErrorType , int > KeyDropDownControl : : ValidateShortcutSelection ( Grid table , StackPanel shortcutControl , StackPanel parent , int colIndex , RemapBuffer & shortcutRemapBuffer , std : : vector < std : : unique_ptr < KeyDropDownControl > > & keyDropDownControlObjects , TextBox targetApp , bool isHybridControl , bool isSingleKeyWindow )
2020-04-23 09:14:16 -07:00
{
2020-07-13 11:49:09 -07:00
ComboBox currentDropDown = dropDown . as < ComboBox > ( ) ;
2020-06-10 08:25:41 -07:00
uint32_t dropDownIndex = - 1 ;
bool dropDownFound = parent . Children ( ) . IndexOf ( currentDropDown , dropDownIndex ) ;
// Get row index of the single key control
uint32_t controlIndex ;
bool controlIindexFound = table . Children ( ) . IndexOf ( shortcutControl , controlIndex ) ;
int rowIndex = - 1 ;
2020-08-13 16:32:15 -07:00
std : : pair < KeyboardManagerHelper : : ErrorType , BufferValidationHelpers : : DropDownAction > validationResult = std : : make_pair ( KeyboardManagerHelper : : ErrorType : : NoError , BufferValidationHelpers : : DropDownAction : : NoAction ) ;
2020-04-23 09:14:16 -07:00
2020-06-10 08:25:41 -07:00
if ( controlIindexFound )
{
2020-09-18 17:12:37 -07:00
// GetRow will give the row index including the table header
rowIndex = table . GetRow ( shortcutControl ) - 1 ;
2020-07-08 16:24:30 -07:00
2020-10-19 12:27:47 +03:00
std : : vector < int32_t > selectedCodes = GetSelectedCodesFromStackPanel ( parent ) ;
2020-07-23 16:43:49 -07:00
2020-08-13 16:32:15 -07:00
std : : wstring appName ;
if ( targetApp ! = nullptr )
{
appName = targetApp . Text ( ) . c_str ( ) ;
}
2020-04-26 15:09:40 -07:00
2020-08-13 16:32:15 -07:00
// Validate shortcut element
2020-10-19 12:27:47 +03:00
validationResult = BufferValidationHelpers : : ValidateShortcutBufferElement ( rowIndex , colIndex , dropDownIndex , selectedCodes , appName , isHybridControl , shortcutRemapBuffer , dropDownFound ) ;
2020-04-26 15:09:40 -07:00
2020-08-13 16:32:15 -07:00
// Add or clear unused drop downs
if ( validationResult . second = = BufferValidationHelpers : : DropDownAction : : AddDropDown )
{
AddDropDown ( table , shortcutControl , parent , colIndex , shortcutRemapBuffer , keyDropDownControlObjects , targetApp , isHybridControl , isSingleKeyWindow ) ;
}
else if ( validationResult . second = = BufferValidationHelpers : : DropDownAction : : ClearUnusedDropDowns )
{
2020-09-18 17:12:37 -07:00
// remove all the drop downs after the current index (accessible names do not have to be updated since drop downs at the end of the list are getting removed)
2020-08-13 16:32:15 -07:00
int elementsToBeRemoved = parent . Children ( ) . Size ( ) - dropDownIndex - 1 ;
for ( int i = 0 ; i < elementsToBeRemoved ; i + + )
2020-04-26 15:09:40 -07:00
{
2020-08-13 16:32:15 -07:00
parent . Children ( ) . RemoveAtEnd ( ) ;
keyDropDownControlObjects . erase ( keyDropDownControlObjects . end ( ) - 1 ) ;
2020-04-26 15:09:40 -07:00
}
2020-08-13 16:32:15 -07:00
parent . UpdateLayout ( ) ;
2020-06-10 08:25:41 -07:00
}
2020-04-26 15:09:40 -07:00
2020-09-22 13:54:53 -07:00
// If ignore key to shortcut warning flag is true and it is a hybrid control in SingleKeyRemapControl, then skip MapToSameKey error
if ( isHybridControl & & isSingleKeyWindow & & ignoreKeyToShortcutWarning & & ( validationResult . first = = KeyboardManagerHelper : : ErrorType : : MapToSameKey ) )
{
validationResult . first = KeyboardManagerHelper : : ErrorType : : NoError ;
}
// If the remapping is invalid display an error message
2020-08-13 16:32:15 -07:00
if ( validationResult . first ! = KeyboardManagerHelper : : ErrorType : : NoError )
2020-06-10 08:25:41 -07:00
{
2020-08-13 16:32:15 -07:00
SetDropDownError ( currentDropDown , KeyboardManagerHelper : : GetErrorMessage ( validationResult . first ) ) ;
2020-06-10 08:25:41 -07:00
}
// Handle None case if there are no other errors
2020-08-13 16:32:15 -07:00
else if ( validationResult . second = = BufferValidationHelpers : : DropDownAction : : DeleteDropDown )
2020-06-10 08:25:41 -07:00
{
2020-09-18 17:12:37 -07:00
// Update accessible names for drop downs appearing after the deleted one
for ( uint32_t i = dropDownIndex + 1 ; i < keyDropDownControlObjects . size ( ) ; i + + )
{
// Update accessible name (row index will become i-1 for this element, so the display name would be i (display name indexing from 1)
SetAccessibleNameForComboBox ( keyDropDownControlObjects [ i ] - > GetComboBox ( ) , i ) ;
}
2020-06-10 08:25:41 -07:00
parent . Children ( ) . RemoveAt ( dropDownIndex ) ;
// delete drop down control object from the vector so that it can be destructed
keyDropDownControlObjects . erase ( keyDropDownControlObjects . begin ( ) + dropDownIndex ) ;
parent . UpdateLayout ( ) ;
}
}
2020-09-22 13:54:53 -07:00
// Reset ignoreKeyToShortcutWarning
if ( ignoreKeyToShortcutWarning )
{
ignoreKeyToShortcutWarning = false ;
}
2020-08-13 16:32:15 -07:00
return std : : make_pair ( validationResult . first , rowIndex ) ;
2020-06-10 08:25:41 -07:00
}
// Function to set selection handler for shortcut drop down. Needs to be called after the constructor since the shortcutControl StackPanel is null if called in the constructor
2020-08-13 16:32:15 -07:00
void KeyDropDownControl : : SetSelectionHandler ( Grid & table , StackPanel shortcutControl , StackPanel parent , int colIndex , RemapBuffer & shortcutRemapBuffer , std : : vector < std : : unique_ptr < KeyDropDownControl > > & keyDropDownControlObjects , TextBox & targetApp , bool isHybridControl , bool isSingleKeyWindow )
2020-06-10 08:25:41 -07:00
{
2020-07-23 16:43:49 -07:00
auto onSelectionChange = [ & , table , shortcutControl , colIndex , parent , targetApp , isHybridControl , isSingleKeyWindow ] ( winrt : : Windows : : Foundation : : IInspectable const & sender ) {
std : : pair < KeyboardManagerHelper : : ErrorType , int > validationResult = ValidateShortcutSelection ( table , shortcutControl , parent , colIndex , shortcutRemapBuffer , keyDropDownControlObjects , targetApp , isHybridControl , isSingleKeyWindow ) ;
2020-06-10 08:25:41 -07:00
// Check if the drop down row index was identified from the return value of validateSelection
if ( validationResult . second ! = - 1 )
{
// If an error occurred
if ( validationResult . first ! = KeyboardManagerHelper : : ErrorType : : NoError )
2020-04-26 15:09:40 -07:00
{
2020-07-08 16:24:30 -07:00
// Validate all the drop downs
2020-07-23 16:43:49 -07:00
ValidateShortcutFromDropDownList ( table , shortcutControl , parent , colIndex , shortcutRemapBuffer , keyDropDownControlObjects , targetApp , isHybridControl , isSingleKeyWindow ) ;
2020-04-26 15:09:40 -07:00
}
2020-06-10 08:25:41 -07:00
2020-08-13 16:32:15 -07:00
// Reset the buffer based on the new selected drop down items. Use static key code list since the KeyDropDownControl object might be deleted
2020-10-19 12:27:47 +03:00
std : : vector < int32_t > selectedKeyCodes = GetSelectedCodesFromStackPanel ( parent ) ;
2020-07-23 16:43:49 -07:00
if ( ! isHybridControl )
2020-07-10 17:07:28 -07:00
{
2020-07-23 16:43:49 -07:00
std : : get < Shortcut > ( shortcutRemapBuffer [ validationResult . second ] . first [ colIndex ] ) . SetKeyCodes ( selectedKeyCodes ) ;
2020-07-10 17:07:28 -07:00
}
else
{
2020-07-23 16:43:49 -07:00
// If exactly one key is selected consider it to be a key remap
2020-10-19 12:27:47 +03:00
if ( GetNumberOfSelectedKeys ( selectedKeyCodes ) = = 1 )
2020-07-23 16:43:49 -07:00
{
shortcutRemapBuffer [ validationResult . second ] . first [ colIndex ] = selectedKeyCodes [ 0 ] ;
}
else
{
Shortcut tempShortcut ;
tempShortcut . SetKeyCodes ( selectedKeyCodes ) ;
// Assign instead of setting the value in the buffer since the previous value may not be a Shortcut
shortcutRemapBuffer [ validationResult . second ] . first [ colIndex ] = tempShortcut ;
}
}
if ( targetApp ! = nullptr )
{
std : : wstring newText = targetApp . Text ( ) . c_str ( ) ;
std : : wstring lowercaseDefAppName = KeyboardManagerConstants : : DefaultAppName ;
std : : transform ( newText . begin ( ) , newText . end ( ) , newText . begin ( ) , towlower ) ;
std : : transform ( lowercaseDefAppName . begin ( ) , lowercaseDefAppName . end ( ) , lowercaseDefAppName . begin ( ) , towlower ) ;
if ( newText = = lowercaseDefAppName )
{
shortcutRemapBuffer [ validationResult . second ] . second = L " " ;
}
else
{
shortcutRemapBuffer [ validationResult . second ] . second = targetApp . Text ( ) . c_str ( ) ;
}
2020-07-10 17:07:28 -07:00
}
2020-04-23 09:14:16 -07:00
}
// If the user searches for a key the selection handler gets invoked however if they click away it reverts back to the previous state. This can result in dangling references to added drop downs which were then reset.
// We handle this by removing the drop down if it no longer a child of the parent
for ( long long i = keyDropDownControlObjects . size ( ) - 1 ; i > = 0 ; i - - )
{
uint32_t index ;
bool found = parent . Children ( ) . IndexOf ( keyDropDownControlObjects [ i ] - > GetComboBox ( ) , index ) ;
if ( ! found )
{
keyDropDownControlObjects . erase ( keyDropDownControlObjects . begin ( ) + i ) ;
}
}
2020-05-11 10:10:36 -07:00
} ;
// Rather than on every selection change (which gets triggered on searching as well) we set the handler only when the drop down is closed
2020-07-13 11:49:09 -07:00
dropDown . as < ComboBox > ( ) . DropDownClosed ( [ onSelectionChange ] ( winrt : : Windows : : Foundation : : IInspectable const & sender , auto const & args ) {
2020-05-11 10:10:36 -07:00
onSelectionChange ( sender ) ;
} ) ;
// We check if the selection changed was triggered while the drop down was closed. This is required to handle Type key, initial loading of remaps and if the user just types in the combo box without opening it
2020-07-13 11:49:09 -07:00
dropDown . as < ComboBox > ( ) . SelectionChanged ( [ onSelectionChange ] ( winrt : : Windows : : Foundation : : IInspectable const & sender , SelectionChangedEventArgs const & args ) {
2020-05-11 10:10:36 -07:00
ComboBox currentDropDown = sender . as < ComboBox > ( ) ;
if ( ! currentDropDown . IsDropDownOpen ( ) )
{
onSelectionChange ( sender ) ;
}
2020-04-23 09:14:16 -07:00
} ) ;
}
2020-04-18 16:12:26 -07:00
// Function to return the combo box element of the drop down
ComboBox KeyDropDownControl : : GetComboBox ( )
{
2020-07-13 11:49:09 -07:00
return dropDown . as < ComboBox > ( ) ;
2020-04-18 16:12:26 -07:00
}
// Function to add a drop down to the shortcut stack panel
2020-09-22 13:54:53 -07:00
void KeyDropDownControl : : AddDropDown ( Grid table , StackPanel shortcutControl , StackPanel parent , const int colIndex , RemapBuffer & shortcutRemapBuffer , std : : vector < std : : unique_ptr < KeyDropDownControl > > & keyDropDownControlObjects , TextBox targetApp , bool isHybridControl , bool isSingleKeyWindow , bool ignoreWarning )
2020-04-18 16:12:26 -07:00
{
2020-10-06 17:17:20 +02:00
keyDropDownControlObjects . emplace_back ( std : : make_unique < KeyDropDownControl > ( true , ignoreWarning , colIndex = = 1 ) ) ;
2020-04-18 16:12:26 -07:00
parent . Children ( ) . Append ( keyDropDownControlObjects [ keyDropDownControlObjects . size ( ) - 1 ] - > GetComboBox ( ) ) ;
2020-07-23 16:43:49 -07:00
keyDropDownControlObjects [ keyDropDownControlObjects . size ( ) - 1 ] - > SetSelectionHandler ( table , shortcutControl , parent , colIndex , shortcutRemapBuffer , keyDropDownControlObjects , targetApp , isHybridControl , isSingleKeyWindow ) ;
2020-04-18 16:12:26 -07:00
parent . UpdateLayout ( ) ;
2020-09-18 17:12:37 -07:00
// Update accessible name
SetAccessibleNameForComboBox ( keyDropDownControlObjects [ keyDropDownControlObjects . size ( ) - 1 ] - > GetComboBox ( ) , ( int ) keyDropDownControlObjects . size ( ) ) ;
2020-04-18 16:12:26 -07:00
}
// Function to get the list of key codes from the shortcut combo box stack panel
2020-10-19 12:27:47 +03:00
std : : vector < int32_t > KeyDropDownControl : : GetSelectedCodesFromStackPanel ( StackPanel parent )
2020-04-18 16:12:26 -07:00
{
2020-10-19 12:27:47 +03:00
std : : vector < int32_t > selectedKeyCodes ;
2020-06-10 08:25:41 -07:00
2020-08-13 16:32:15 -07:00
// Get selected indices for each drop down
for ( int i = 0 ; i < ( int ) parent . Children ( ) . Size ( ) ; i + + )
2020-04-18 16:12:26 -07:00
{
2020-08-13 16:32:15 -07:00
ComboBox ItDropDown = parent . Children ( ) . GetAt ( i ) . as < ComboBox > ( ) ;
2020-10-19 12:27:47 +03:00
selectedKeyCodes . push_back ( GetSelectedValue ( ItDropDown ) ) ;
2020-04-18 16:12:26 -07:00
}
2020-10-19 12:27:47 +03:00
return selectedKeyCodes ;
2020-04-18 16:12:26 -07:00
}
2020-07-08 16:24:30 -07:00
// Function for validating the selection of shortcuts for all the associated drop downs
2020-08-13 16:32:15 -07:00
void KeyDropDownControl : : ValidateShortcutFromDropDownList ( Grid table , StackPanel shortcutControl , StackPanel parent , int colIndex , RemapBuffer & shortcutRemapBuffer , std : : vector < std : : unique_ptr < KeyDropDownControl > > & keyDropDownControlObjects , TextBox targetApp , bool isHybridControl , bool isSingleKeyWindow )
2020-07-08 16:24:30 -07:00
{
// Iterate over all drop downs from left to right in that row/col and validate if there is an error in any of the drop downs. After this the state should be error-free (if it is a valid shortcut)
for ( int i = 0 ; i < keyDropDownControlObjects . size ( ) ; i + + )
{
// Check for errors only if the current selection is a valid shortcut
2020-10-19 12:27:47 +03:00
std : : vector < int32_t > selectedKeyCodes = GetSelectedCodesFromStackPanel ( parent ) ;
2020-10-08 11:28:24 -07:00
KeyShortcutUnion currentShortcut ;
2020-10-19 12:27:47 +03:00
if ( GetNumberOfSelectedKeys ( selectedKeyCodes ) = = 1 & & isHybridControl )
2020-07-23 16:43:49 -07:00
{
currentShortcut = selectedKeyCodes [ 0 ] ;
}
else
{
Shortcut temp ;
temp . SetKeyCodes ( selectedKeyCodes ) ;
currentShortcut = temp ;
}
2020-07-08 16:24:30 -07:00
2020-07-23 16:43:49 -07:00
// If the key/shortcut is valid and that drop down is not empty
2020-10-19 12:27:47 +03:00
if ( ( ( currentShortcut . index ( ) = = 0 & & std : : get < DWORD > ( currentShortcut ) ! = NULL ) | | ( currentShortcut . index ( ) = = 1 & & std : : get < Shortcut > ( currentShortcut ) . IsValidShortcut ( ) ) ) & & GetSelectedValue ( keyDropDownControlObjects [ i ] - > GetComboBox ( ) ) ! = - 1 )
2020-07-08 16:24:30 -07:00
{
2020-07-23 16:43:49 -07:00
keyDropDownControlObjects [ i ] - > ValidateShortcutSelection ( table , shortcutControl , parent , colIndex , shortcutRemapBuffer , keyDropDownControlObjects , targetApp , isHybridControl , isSingleKeyWindow ) ;
2020-07-08 16:24:30 -07:00
}
}
}
2020-04-26 15:09:40 -07:00
// Function to set the warning message
void KeyDropDownControl : : SetDropDownError ( ComboBox currentDropDown , hstring message )
2020-04-18 16:12:26 -07:00
{
2020-04-26 15:09:40 -07:00
currentDropDown . SelectedIndex ( - 1 ) ;
2020-07-13 11:49:09 -07:00
warningMessage . as < TextBlock > ( ) . Text ( message ) ;
currentDropDown . ContextFlyout ( ) . ShowAttachedFlyout ( ( FrameworkElement ) dropDown . as < ComboBox > ( ) ) ;
2020-04-18 16:12:26 -07:00
}
2020-07-23 16:43:49 -07:00
// Function to add a shortcut to the UI control as combo boxes
2020-08-13 16:32:15 -07:00
void KeyDropDownControl : : AddShortcutToControl ( Shortcut shortcut , Grid table , StackPanel parent , KeyboardManagerState & keyboardManagerState , const int colIndex , std : : vector < std : : unique_ptr < KeyDropDownControl > > & keyDropDownControlObjects , RemapBuffer & remapBuffer , StackPanel controlLayout , TextBox targetApp , bool isHybridControl , bool isSingleKeyWindow )
2020-07-23 16:43:49 -07:00
{
// Delete the existing drop down menus
parent . Children ( ) . Clear ( ) ;
// Remove references to the old drop down objects to destroy them
keyDropDownControlObjects . clear ( ) ;
std : : vector < DWORD > shortcutKeyCodes = shortcut . GetKeyCodes ( ) ;
if ( shortcutKeyCodes . size ( ) ! = 0 )
{
2020-09-22 13:54:53 -07:00
bool ignoreWarning = false ;
// If more than one key is to be added, ignore a shortcut to key warning on partially entering the remapping
if ( shortcutKeyCodes . size ( ) > 1 )
{
ignoreWarning = true ;
}
KeyDropDownControl : : AddDropDown ( table , controlLayout , parent , colIndex , remapBuffer , keyDropDownControlObjects , targetApp , isHybridControl , isSingleKeyWindow , ignoreWarning ) ;
2020-07-23 16:43:49 -07:00
for ( int i = 0 ; i < shortcutKeyCodes . size ( ) ; i + + )
{
2020-10-19 12:27:47 +03:00
// New drop down gets added automatically when the SelectedValue(key code) is set
2020-07-23 16:43:49 -07:00
if ( i < ( int ) parent . Children ( ) . Size ( ) )
{
ComboBox currentDropDown = parent . Children ( ) . GetAt ( i ) . as < ComboBox > ( ) ;
2020-10-19 12:27:47 +03:00
currentDropDown . SelectedValue ( winrt : : box_value ( std : : to_wstring ( shortcutKeyCodes [ i ] ) ) ) ;
2020-07-23 16:43:49 -07:00
}
}
}
parent . UpdateLayout ( ) ;
}
2020-10-19 12:27:47 +03:00
// Get number of selected keys. Do not count -1 and 0 values as they stand for Not selected and None
int KeyDropDownControl : : GetNumberOfSelectedKeys ( std : : vector < int32_t > keyCodes )
{
return ( int ) std : : count_if ( keyCodes . begin ( ) , keyCodes . end ( ) , [ ] ( int32_t a ) { return a ! = - 1 & & a ! = 0 ; } ) ;
}