mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-07 17:42:45 +08:00
[Keyboard Manager] Add JSON support for App Specific shortcuts (#4840)
* Enable app specific shortcut remapping * Fixed lowercase function call * Add test file * Moved GetForegroundProcess to II and added tests * Fixed runtime error while testing due to heap allocation across dll boundary * Renamed function * Changed shortcutBuffer type * Linked App specific UI to backend * Added shortcut validation logic on TextBox LostFocus handler * Moved Validate function and changed default text * Changed to case insensitive warning check * Changed to case insensitive warning check at OnClickAccept * Fixed alignment and spacing issues * Added app-specific JSON support in backend * Updated landing page * Make listview horizontally scrollable * Added tests * Consider all case variants of All Apps in textbox to be global shortcuts
This commit is contained in:
parent
653ae777d5
commit
bb2049411b
@ -0,0 +1,32 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Lib
|
||||
{
|
||||
public class AppSpecificKeysDataModel : KeysDataModel
|
||||
{
|
||||
[JsonPropertyName("targetApp")]
|
||||
public string TargetApp { get; set; }
|
||||
|
||||
public new List<string> GetOriginalKeys()
|
||||
{
|
||||
return base.GetOriginalKeys();
|
||||
}
|
||||
|
||||
public new List<string> GetNewRemapKeys()
|
||||
{
|
||||
return base.GetNewRemapKeys();
|
||||
}
|
||||
|
||||
public bool Compare(AppSpecificKeysDataModel arg)
|
||||
{
|
||||
return OriginalKeys.Equals(arg.OriginalKeys) && NewRemapKeys.Equals(arg.NewRemapKeys) && TargetApp.Equals(arg.TargetApp);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,10 +2,10 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Lib
|
||||
{
|
||||
|
@ -17,4 +17,4 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
|
||||
InProcessRemapKeys = new List<KeysDataModel>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,13 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
|
||||
[JsonPropertyName("global")]
|
||||
public List<KeysDataModel> GlobalRemapShortcuts { get; set; }
|
||||
|
||||
[JsonPropertyName("appSpecific")]
|
||||
public List<AppSpecificKeysDataModel> AppSpecificRemapShortcuts { get; set; }
|
||||
|
||||
public ShortcutsKeyDataModel()
|
||||
{
|
||||
GlobalRemapShortcuts = new List<KeysDataModel>();
|
||||
AppSpecificRemapShortcuts = new List<AppSpecificKeysDataModel>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
PowerToyName,
|
||||
settings.Properties.ActiveConfiguration.Value + JsonFileType,
|
||||
OnConfigFileUpdate);
|
||||
|
||||
}
|
||||
|
||||
public bool Enabled
|
||||
@ -113,17 +112,22 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public List<KeysDataModel> RemapShortcuts
|
||||
public static List<AppSpecificKeysDataModel> CombineShortcutLists(List<KeysDataModel> globalShortcutList, List<AppSpecificKeysDataModel> appSpecificShortcutList)
|
||||
{
|
||||
return globalShortcutList.ConvertAll(x => new AppSpecificKeysDataModel { OriginalKeys = x.OriginalKeys, NewRemapKeys = x.NewRemapKeys, TargetApp = "All Apps" }).Concat(appSpecificShortcutList).ToList();
|
||||
}
|
||||
|
||||
public List<AppSpecificKeysDataModel> RemapShortcuts
|
||||
{
|
||||
get
|
||||
{
|
||||
if (profile != null)
|
||||
{
|
||||
return profile.RemapShortcuts.GlobalRemapShortcuts;
|
||||
return CombineShortcutLists(profile.RemapShortcuts.GlobalRemapShortcuts, profile.RemapShortcuts.AppSpecificRemapShortcuts);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new List<KeysDataModel>();
|
||||
return new List<AppSpecificKeysDataModel>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,6 +81,95 @@
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Name="ShortcutKeysListViewTemplate" x:DataType="Lib:AppSpecificKeysDataModel">
|
||||
<StackPanel
|
||||
Orientation="Horizontal"
|
||||
Height="56">
|
||||
<ItemsControl
|
||||
ItemsSource="{x:Bind GetOriginalKeys()}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border
|
||||
Background="{ThemeResource SystemBaseLowColor}"
|
||||
CornerRadius="4"
|
||||
Padding="14,0,14,0"
|
||||
Margin="5,0,5,0"
|
||||
Height="36"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Left">
|
||||
<TextBlock
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center"
|
||||
TextAlignment="Center"
|
||||
FontSize="12"
|
||||
Text="{Binding}" />
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<FontIcon Glyph=""
|
||||
Grid.Column="1"
|
||||
FontSize="14"
|
||||
VerticalAlignment="Center"
|
||||
Margin="5,0,5,0"/>
|
||||
<ItemsControl
|
||||
ItemsSource="{x:Bind GetNewRemapKeys()}"
|
||||
Grid.Column="2">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border
|
||||
Background="{ThemeResource SystemAccentColor}"
|
||||
CornerRadius="4"
|
||||
Padding="14,0,14,0"
|
||||
Margin="5,0,5,0"
|
||||
Height="36"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Left">
|
||||
<TextBlock
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center"
|
||||
TextAlignment="Center"
|
||||
Foreground="White"
|
||||
FontSize="12"
|
||||
Text="{Binding}" />
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<FontIcon Glyph=""
|
||||
Grid.Column="3"
|
||||
FontSize="14"
|
||||
VerticalAlignment="Center"
|
||||
Margin="5,0,5,0"/>
|
||||
<Border
|
||||
Background="{ThemeResource SystemAccentColor}"
|
||||
Grid.Column="4"
|
||||
CornerRadius="4"
|
||||
Padding="14,0,14,0"
|
||||
Margin="5,0,5,0"
|
||||
Height="36"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Left">
|
||||
<TextBlock
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center"
|
||||
TextAlignment="Center"
|
||||
Foreground="White"
|
||||
FontSize="12"
|
||||
Text="{x:Bind TargetApp}" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</Page.Resources>
|
||||
|
||||
<Grid ColumnSpacing="{StaticResource DefaultColumnSpacing}" RowSpacing="{StaticResource DefaultRowSpacing}">
|
||||
@ -192,7 +281,7 @@
|
||||
<ListView x:Name="RemapShortcutsList"
|
||||
extensions:ListViewExtensions.AlternateColor="{ThemeResource SystemControlBackgroundListLowBrush}"
|
||||
ItemsSource="{x:Bind Path=ViewModel.RemapShortcuts, Mode=OneWay}"
|
||||
ItemTemplate="{StaticResource KeysListViewTemplate}"
|
||||
ItemTemplate="{StaticResource ShortcutKeysListViewTemplate}"
|
||||
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4"
|
||||
@ -203,6 +292,9 @@
|
||||
SelectionMode="None"
|
||||
IsSwipeEnabled="False"
|
||||
Visibility="{x:Bind Path=ViewModel.RemapShortcuts, Mode=OneWay, Converter={StaticResource visibleIfNotEmptyConverter}}"
|
||||
ScrollViewer.HorizontalScrollMode="Enabled"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Visible"
|
||||
ScrollViewer.IsHorizontalRailEnabled="True"
|
||||
/>
|
||||
|
||||
<!--<AppBarButton x:Uid="KeyboardManager_RemapShortcutsButton"
|
||||
|
@ -169,6 +169,7 @@
|
||||
<Compile Include="UnitTestApp.xaml.cs">
|
||||
<DependentUpon>UnitTestApp.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ViewModelTests\KeyboardManager.cs" />
|
||||
<Compile Include="ViewModelTests\PowerRename.cs" />
|
||||
<Compile Include="ViewModelTests\PowerPreview.cs" />
|
||||
<Compile Include="ViewModelTests\ShortcutGuide.cs" />
|
||||
|
@ -0,0 +1,132 @@
|
||||
using Microsoft.PowerToys.Settings.UI.Lib;
|
||||
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||
using Microsoft.PowerToys.Settings.UI.Views;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Windows.System;
|
||||
|
||||
namespace ViewModelTests
|
||||
{
|
||||
[TestClass]
|
||||
public class KeyboardManager
|
||||
{
|
||||
public const string Module = "Keyboard Manager";
|
||||
|
||||
[TestInitialize]
|
||||
public void Setup()
|
||||
{ }
|
||||
|
||||
[TestCleanup]
|
||||
public void CleanUp()
|
||||
{ }
|
||||
|
||||
[TestMethod]
|
||||
public void CombineShortcutLists_ShouldReturnEmptyList_WhenBothArgumentsAreEmptyLists()
|
||||
{
|
||||
// arrange
|
||||
var firstList = new List<KeysDataModel>();
|
||||
var secondList = new List<AppSpecificKeysDataModel>();
|
||||
|
||||
// act
|
||||
var result = KeyboardManagerViewModel.CombineShortcutLists(firstList, secondList);
|
||||
|
||||
// Assert
|
||||
var expectedResult = new List<AppSpecificKeysDataModel>();
|
||||
|
||||
Assert.AreEqual(expectedResult.Count(), result.Count());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CombineShortcutLists_ShouldReturnListWithOneAllAppsEntry_WhenFirstArgumentHasOneEntryAndSecondArgumentIsEmpty()
|
||||
{
|
||||
// arrange
|
||||
var firstList = new List<KeysDataModel>();
|
||||
var entry = new KeysDataModel();
|
||||
entry.OriginalKeys = VirtualKey.Control + ";" + VirtualKey.A;
|
||||
entry.NewRemapKeys = VirtualKey.Control + ";" + VirtualKey.V;
|
||||
firstList.Add(entry);
|
||||
var secondList = new List<AppSpecificKeysDataModel>();
|
||||
|
||||
// act
|
||||
var result = KeyboardManagerViewModel.CombineShortcutLists(firstList, secondList);
|
||||
|
||||
// Assert
|
||||
var expectedResult = new List<AppSpecificKeysDataModel>();
|
||||
var expectedEntry = new AppSpecificKeysDataModel();
|
||||
expectedEntry.OriginalKeys = entry.OriginalKeys;
|
||||
expectedEntry.NewRemapKeys = entry.NewRemapKeys;
|
||||
expectedEntry.TargetApp = "All Apps";
|
||||
expectedResult.Add(expectedEntry);
|
||||
var x = expectedResult[0].Equals(result[0]);
|
||||
Assert.AreEqual(expectedResult.Count(), result.Count());
|
||||
Assert.IsTrue(expectedResult[0].Compare(result[0]));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CombineShortcutLists_ShouldReturnListWithOneAppSpecificEntry_WhenFirstArgumentIsEmptyAndSecondArgumentHasOneEntry()
|
||||
{
|
||||
// arrange
|
||||
var firstList = new List<KeysDataModel>();
|
||||
var secondList = new List<AppSpecificKeysDataModel>();
|
||||
var entry = new AppSpecificKeysDataModel();
|
||||
entry.OriginalKeys = VirtualKey.Control + ";" + VirtualKey.A;
|
||||
entry.NewRemapKeys = VirtualKey.Control + ";" + VirtualKey.V;
|
||||
entry.TargetApp = "msedge";
|
||||
secondList.Add(entry);
|
||||
|
||||
// act
|
||||
var result = KeyboardManagerViewModel.CombineShortcutLists(firstList, secondList);
|
||||
|
||||
// Assert
|
||||
var expectedResult = new List<AppSpecificKeysDataModel>();
|
||||
var expectedEntry = new AppSpecificKeysDataModel();
|
||||
expectedEntry.OriginalKeys = entry.OriginalKeys;
|
||||
expectedEntry.NewRemapKeys = entry.NewRemapKeys;
|
||||
expectedEntry.TargetApp = entry.TargetApp;
|
||||
expectedResult.Add(expectedEntry);
|
||||
|
||||
Assert.AreEqual(expectedResult.Count(), result.Count());
|
||||
Assert.IsTrue(expectedResult[0].Compare(result[0]));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CombineShortcutLists_ShouldReturnListWithOneAllAppsEntryAndOneAppSpecificEntry_WhenFirstArgumentHasOneEntryAndSecondArgumentHasOneEntry()
|
||||
{
|
||||
// arrange
|
||||
var firstList = new List<KeysDataModel>();
|
||||
var firstListEntry = new KeysDataModel();
|
||||
firstListEntry.OriginalKeys = VirtualKey.Control + ";" + VirtualKey.A;
|
||||
firstListEntry.NewRemapKeys = VirtualKey.Control + ";" + VirtualKey.V;
|
||||
firstList.Add(firstListEntry);
|
||||
var secondList = new List<AppSpecificKeysDataModel>();
|
||||
var secondListEntry = new AppSpecificKeysDataModel();
|
||||
secondListEntry.OriginalKeys = VirtualKey.Control + ";" + VirtualKey.B;
|
||||
secondListEntry.NewRemapKeys = VirtualKey.Control + ";" + VirtualKey.W;
|
||||
secondListEntry.TargetApp = "msedge";
|
||||
secondList.Add(secondListEntry);
|
||||
|
||||
// act
|
||||
var result = KeyboardManagerViewModel.CombineShortcutLists(firstList, secondList);
|
||||
|
||||
// Assert
|
||||
var expectedResult = new List<AppSpecificKeysDataModel>();
|
||||
var expectedFirstEntry = new AppSpecificKeysDataModel();
|
||||
expectedFirstEntry.OriginalKeys = firstListEntry.OriginalKeys;
|
||||
expectedFirstEntry.NewRemapKeys = firstListEntry.NewRemapKeys;
|
||||
expectedFirstEntry.TargetApp = "All Apps";
|
||||
expectedResult.Add(expectedFirstEntry);
|
||||
var expectedSecondEntry = new AppSpecificKeysDataModel();
|
||||
expectedSecondEntry.OriginalKeys = secondListEntry.OriginalKeys;
|
||||
expectedSecondEntry.NewRemapKeys = secondListEntry.NewRemapKeys;
|
||||
expectedSecondEntry.TargetApp = secondListEntry.TargetApp;
|
||||
expectedResult.Add(expectedSecondEntry);
|
||||
|
||||
Assert.AreEqual(expectedResult.Count(), result.Count());
|
||||
Assert.IsTrue(expectedResult[0].Compare(result[0]));
|
||||
Assert.IsTrue(expectedResult[1].Compare(result[1]));
|
||||
}
|
||||
}
|
||||
}
|
@ -22,12 +22,18 @@ namespace KeyboardManagerConstants
|
||||
// Name of the property use to store global shortcut remaps array.
|
||||
inline const std::wstring GlobalRemapShortcutsSettingName = L"global";
|
||||
|
||||
// Name of the property use to store app specific shortcut remaps array.
|
||||
inline const std::wstring AppSpecificRemapShortcutsSettingName = L"appSpecific";
|
||||
|
||||
// Name of the property use to store original keys.
|
||||
inline const std::wstring OriginalKeysSettingName = L"originalKeys";
|
||||
|
||||
// Name of the property use to store new remap keys.
|
||||
inline const std::wstring NewRemapKeysSettingName = L"newRemapKeys";
|
||||
|
||||
// Name of the property use to store the target application.
|
||||
inline const std::wstring TargetAppSettingName = L"targetApp";
|
||||
|
||||
// Name of the default configuration.
|
||||
inline const std::wstring DefaultConfiguration = L"default";
|
||||
|
||||
|
@ -444,6 +444,7 @@ bool KeyboardManagerState::SaveConfigToFile()
|
||||
json::JsonObject remapShortcuts;
|
||||
json::JsonObject remapKeys;
|
||||
json::JsonArray inProcessRemapKeysArray;
|
||||
json::JsonArray appSpecificRemapShortcutsArray;
|
||||
json::JsonArray globalRemapShortcutsArray;
|
||||
std::unique_lock<std::mutex> lockSingleKeyReMap(singleKeyReMap_mutex);
|
||||
for (const auto& it : singleKeyReMap)
|
||||
@ -466,8 +467,26 @@ bool KeyboardManagerState::SaveConfigToFile()
|
||||
globalRemapShortcutsArray.Append(keys);
|
||||
}
|
||||
lockOsLevelShortcutReMap.unlock();
|
||||
|
||||
std::unique_lock<std::mutex> lockAppSpecificShortcutReMap(appSpecificShortcutReMap_mutex);
|
||||
for (const auto& itApp : appSpecificShortcutReMap)
|
||||
{
|
||||
// Iterate over apps
|
||||
for (const auto& itKeys : itApp.second)
|
||||
{
|
||||
json::JsonObject keys;
|
||||
keys.SetNamedValue(KeyboardManagerConstants::OriginalKeysSettingName, json::value(itKeys.first.ToHstringVK()));
|
||||
keys.SetNamedValue(KeyboardManagerConstants::NewRemapKeysSettingName, json::value(itKeys.second.targetShortcut.ToHstringVK()));
|
||||
keys.SetNamedValue(KeyboardManagerConstants::TargetAppSettingName, json::value(itApp.first));
|
||||
|
||||
appSpecificRemapShortcutsArray.Append(keys);
|
||||
}
|
||||
|
||||
}
|
||||
lockAppSpecificShortcutReMap.unlock();
|
||||
|
||||
remapShortcuts.SetNamedValue(KeyboardManagerConstants::GlobalRemapShortcutsSettingName, globalRemapShortcutsArray);
|
||||
remapShortcuts.SetNamedValue(KeyboardManagerConstants::AppSpecificRemapShortcutsSettingName, appSpecificRemapShortcutsArray);
|
||||
remapKeys.SetNamedValue(KeyboardManagerConstants::InProcessRemapKeysSettingName, inProcessRemapKeysArray);
|
||||
configJson.SetNamedValue(KeyboardManagerConstants::RemapKeysSettingName, remapKeys);
|
||||
configJson.SetNamedValue(KeyboardManagerConstants::RemapShortcutsSettingName, remapShortcuts);
|
||||
|
@ -89,48 +89,100 @@ public:
|
||||
if (configFile)
|
||||
{
|
||||
auto jsonData = *configFile;
|
||||
auto remapKeysData = jsonData.GetNamedObject(KeyboardManagerConstants::RemapKeysSettingName);
|
||||
auto remapShortcutsData = jsonData.GetNamedObject(KeyboardManagerConstants::RemapShortcutsSettingName);
|
||||
keyboardManagerState.ClearSingleKeyRemaps();
|
||||
|
||||
if (remapKeysData)
|
||||
// Load single key remaps
|
||||
try
|
||||
{
|
||||
auto inProcessRemapKeys = remapKeysData.GetNamedArray(KeyboardManagerConstants::InProcessRemapKeysSettingName);
|
||||
for (const auto& it : inProcessRemapKeys)
|
||||
auto remapKeysData = jsonData.GetNamedObject(KeyboardManagerConstants::RemapKeysSettingName);
|
||||
keyboardManagerState.ClearSingleKeyRemaps();
|
||||
|
||||
if (remapKeysData)
|
||||
{
|
||||
try
|
||||
auto inProcessRemapKeys = remapKeysData.GetNamedArray(KeyboardManagerConstants::InProcessRemapKeysSettingName);
|
||||
for (const auto& it : inProcessRemapKeys)
|
||||
{
|
||||
auto originalKey = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
||||
auto newRemapKey = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName);
|
||||
keyboardManagerState.AddSingleKeyRemap(std::stoul(originalKey.c_str()), std::stoul(newRemapKey.c_str()));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Improper Key Data JSON. Try the next remap.
|
||||
try
|
||||
{
|
||||
auto originalKey = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
||||
auto newRemapKey = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName);
|
||||
keyboardManagerState.AddSingleKeyRemap(std::stoul(originalKey.c_str()), std::stoul(newRemapKey.c_str()));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Improper Key Data JSON. Try the next remap.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
keyboardManagerState.ClearOSLevelShortcuts();
|
||||
if (remapShortcutsData)
|
||||
catch (...)
|
||||
{
|
||||
auto globalRemapShortcuts = remapShortcutsData.GetNamedArray(KeyboardManagerConstants::GlobalRemapShortcutsSettingName);
|
||||
for (const auto& it : globalRemapShortcuts)
|
||||
// Improper JSON format for single key remaps. Skip to next remap type
|
||||
}
|
||||
|
||||
// Load shortcut remaps
|
||||
try
|
||||
{
|
||||
auto remapShortcutsData = jsonData.GetNamedObject(KeyboardManagerConstants::RemapShortcutsSettingName);
|
||||
keyboardManagerState.ClearOSLevelShortcuts();
|
||||
keyboardManagerState.ClearAppSpecificShortcuts();
|
||||
if (remapShortcutsData)
|
||||
{
|
||||
// Load os level shortcut remaps
|
||||
try
|
||||
{
|
||||
auto originalKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
||||
auto newRemapKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName);
|
||||
Shortcut originalSC(originalKeys.c_str());
|
||||
Shortcut newRemapSC(newRemapKeys.c_str());
|
||||
keyboardManagerState.AddOSLevelShortcut(originalSC, newRemapSC);
|
||||
auto globalRemapShortcuts = remapShortcutsData.GetNamedArray(KeyboardManagerConstants::GlobalRemapShortcutsSettingName);
|
||||
for (const auto& it : globalRemapShortcuts)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto originalKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
||||
auto newRemapKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName);
|
||||
Shortcut originalSC(originalKeys.c_str());
|
||||
Shortcut newRemapSC(newRemapKeys.c_str());
|
||||
keyboardManagerState.AddOSLevelShortcut(originalSC, newRemapSC);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Improper Key Data JSON. Try the next shortcut.
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Improper Key Data JSON. Try the next shortcut.
|
||||
// Improper JSON format for os level shortcut remaps. Skip to next remap type
|
||||
}
|
||||
|
||||
// Load app specific shortcut remaps
|
||||
try
|
||||
{
|
||||
auto appSpecificRemapShortcuts = remapShortcutsData.GetNamedArray(KeyboardManagerConstants::AppSpecificRemapShortcutsSettingName);
|
||||
for (const auto& it : appSpecificRemapShortcuts)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto originalKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::OriginalKeysSettingName);
|
||||
auto newRemapKeys = it.GetObjectW().GetNamedString(KeyboardManagerConstants::NewRemapKeysSettingName);
|
||||
auto targetApp = it.GetObjectW().GetNamedString(KeyboardManagerConstants::TargetAppSettingName);
|
||||
Shortcut originalSC(originalKeys.c_str());
|
||||
Shortcut newRemapSC(newRemapKeys.c_str());
|
||||
keyboardManagerState.AddAppSpecificShortcut(targetApp.c_str(), originalSC, newRemapSC);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Improper Key Data JSON. Try the next shortcut.
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Improper JSON format for os level shortcut remaps. Skip to next remap type
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Improper JSON format for shortcut remaps. Skip to next remap type
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -254,6 +254,12 @@ std::pair<KeyboardManagerHelper::ErrorType, int> KeyDropDownControl::ValidateSho
|
||||
std::wstring appName = targetApp.Text().c_str();
|
||||
// Convert app name to lower case
|
||||
std::transform(appName.begin(), appName.end(), appName.begin(), towlower);
|
||||
std::wstring lowercaseDefAppName = KeyboardManagerConstants::DefaultAppName;
|
||||
std::transform(lowercaseDefAppName.begin(), lowercaseDefAppName.end(), lowercaseDefAppName.begin(), towlower);
|
||||
if (appName == lowercaseDefAppName)
|
||||
{
|
||||
appName = L"";
|
||||
}
|
||||
|
||||
// Check if the value being set is the same as the other column
|
||||
if (shortcutRemapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)] == tempShortcut && shortcutRemapBuffer[rowIndex].first[std::abs(int(colIndex) - 1)].IsValidShortcut() && tempShortcut.IsValidShortcut())
|
||||
@ -323,7 +329,18 @@ void KeyDropDownControl::SetSelectionHandler(Grid& table, StackPanel& shortcutCo
|
||||
|
||||
// Reset the buffer based on the new selected drop down items
|
||||
shortcutRemapBuffer[validationResult.second].first[colIndex].SetKeyCodes(GetKeysFromStackPanel(parent));
|
||||
shortcutRemapBuffer[validationResult.second].second = targetApp.Text().c_str();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@ -66,7 +66,18 @@ void ShortcutControl::AddNewShortcutControlRow(Grid& parent, std::vector<std::ve
|
||||
// Reset the buffer based on the selected drop down items
|
||||
shortcutRemapBuffer[rowIndex].first[0].SetKeyCodes(KeyDropDownControl::GetKeysFromStackPanel(keyboardRemapControlObjects[rowIndex][0]->shortcutDropDownStackPanel));
|
||||
shortcutRemapBuffer[rowIndex].first[1].SetKeyCodes(KeyDropDownControl::GetKeysFromStackPanel(keyboardRemapControlObjects[rowIndex][1]->shortcutDropDownStackPanel));
|
||||
shortcutRemapBuffer[rowIndex].second = targetAppTextBox.Text().c_str();
|
||||
std::wstring newText = targetAppTextBox.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[rowIndex].second = L"";
|
||||
}
|
||||
else
|
||||
{
|
||||
shortcutRemapBuffer[rowIndex].second = targetAppTextBox.Text().c_str();
|
||||
}
|
||||
});
|
||||
|
||||
parent.SetColumn(targetAppTextBox, KeyboardManagerConstants::ShortcutTableTargetAppColIndex);
|
||||
|
Loading…
Reference in New Issue
Block a user