mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-24 04:00:02 +01:00
[FHL] Save Remapping Config and Data (#37787)
* load URL remapping * Save Remapping Config and Data * update mock data for testing * fix app mapping * update xaml
This commit is contained in:
@@ -495,6 +495,20 @@ bool GetShortcutRemapByType(void* config, int operationType, int index, Shortcut
|
||||
return mappingConfig->AddSingleKeyToTextRemap(static_cast<DWORD>(originalKey), text);
|
||||
}
|
||||
|
||||
bool AddSingleKeyToShortcutRemap(void* config, int originalKey, const wchar_t* targetKeys)
|
||||
{
|
||||
auto mappingConfig = static_cast<MappingConfiguration*>(config);
|
||||
|
||||
if (!targetKeys)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Shortcut targetShortcut(targetKeys);
|
||||
|
||||
return mappingConfig->AddSingleKeyRemap(static_cast<DWORD>(originalKey), targetShortcut);
|
||||
}
|
||||
|
||||
bool AddShortcutRemap(void* config,
|
||||
const wchar_t* originalKeys,
|
||||
const wchar_t* targetKeys,
|
||||
@@ -527,6 +541,18 @@ bool GetShortcutRemapByType(void* config, int operationType, int index, Shortcut
|
||||
std::wstring name = layoutMap.GetKeyName(static_cast<DWORD>(keyCode));
|
||||
wcsncpy_s(keyName, maxCount, name.c_str(), _TRUNCATE);
|
||||
}
|
||||
|
||||
int GetKeyCodeFromName(const wchar_t* keyName)
|
||||
{
|
||||
if (keyName == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
LayoutMap layoutMap;
|
||||
std::wstring name(keyName);
|
||||
return static_cast<int>(layoutMap.GetKeyFromName(name));
|
||||
}
|
||||
}
|
||||
|
||||
// Test function to call the remapping helper function
|
||||
|
||||
@@ -56,12 +56,16 @@ extern "C"
|
||||
|
||||
__declspec(dllexport) bool AddSingleKeyRemap(void* config, int originalKey, int targetKey);
|
||||
__declspec(dllexport) bool AddSingleKeyToTextRemap(void* config, int originalKey, const wchar_t* text);
|
||||
__declspec(dllexport) bool AddSingleKeyToShortcutRemap(void* config,
|
||||
int originalKey,
|
||||
const wchar_t* targetKeys);
|
||||
__declspec(dllexport) bool AddShortcutRemap(void* config,
|
||||
const wchar_t* originalKeys,
|
||||
const wchar_t* targetKeys,
|
||||
const wchar_t* targetApp);
|
||||
|
||||
__declspec(dllexport) void GetKeyDisplayName(int keyCode, wchar_t* keyName, int maxCount);
|
||||
__declspec(dllexport) int GetKeyCodeFromName(const wchar_t* keyName);
|
||||
__declspec(dllexport) void FreeString(wchar_t* str);
|
||||
}
|
||||
extern "C" __declspec(dllexport) bool CheckIfRemappingsAreValid();
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace KeyboardManagerEditorUI.Helpers
|
||||
|
||||
public bool IsAllApps { get; set; } = true;
|
||||
|
||||
public string AppName { get; set; } = "All apps";
|
||||
public string AppName { get; set; } = "All Apps";
|
||||
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,13 @@ namespace KeyboardManagerEditorUI.Interop
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool AddSingleKeyRemap(IntPtr config, int originalKey, int targetKey);
|
||||
|
||||
[DllImport(DllName)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool AddSingleKeyToShortcutRemap(
|
||||
IntPtr config,
|
||||
int originalKey,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string targetKeys);
|
||||
|
||||
[DllImport(DllName)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool AddShortcutRemap(
|
||||
@@ -76,6 +83,10 @@ namespace KeyboardManagerEditorUI.Interop
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string targetKeys,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string targetApp);
|
||||
|
||||
[DllImport(DllName)]
|
||||
internal static extern int GetKeyCodeFromName(
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string keyName);
|
||||
|
||||
[DllImport(DllName)]
|
||||
internal static extern void FreeString(IntPtr str);
|
||||
|
||||
|
||||
@@ -129,8 +129,30 @@ namespace KeyboardManagerEditorUI.Interop
|
||||
return KeyboardManagerInterop.AddSingleKeyRemap(_configHandle, originalKey, targetKey);
|
||||
}
|
||||
|
||||
public bool AddSingleKeyMapping(int originalKey, string targetKeys)
|
||||
{
|
||||
if (string.IsNullOrEmpty(targetKeys))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!targetKeys.Contains(';') && int.TryParse(targetKeys, out int targetKey))
|
||||
{
|
||||
return KeyboardManagerInterop.AddSingleKeyRemap(_configHandle, originalKey, targetKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
return KeyboardManagerInterop.AddSingleKeyToShortcutRemap(_configHandle, originalKey, targetKeys);
|
||||
}
|
||||
}
|
||||
|
||||
public bool AddShortcutMapping(string originalKeys, string targetKeys, string targetApp = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(originalKeys) || string.IsNullOrEmpty(targetKeys))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return KeyboardManagerInterop.AddShortcutRemap(_configHandle, originalKeys, targetKeys, targetApp);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,9 +55,6 @@
|
||||
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Assets\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Styles\CommonStyle.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -119,8 +119,7 @@
|
||||
Grid.Column="1"
|
||||
Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<Image Width="16" Source="ms-appx:///Assets/Images/FluentIconsKeyboardManager.png" />
|
||||
<TextBlock VerticalAlignment="Center" Text="Keyboardmanager.exe" />
|
||||
<TextBlock VerticalAlignment="Center" Text="WindowsTerminal.exe" />
|
||||
<FontIcon
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
@@ -173,8 +172,8 @@
|
||||
Style="{StaticResource CustomShortcutToggleButtonStyle}">
|
||||
<ToggleButton.Content>
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<styles:KeyVisual Content="Win" VisualType="SmallOutline" />
|
||||
<styles:KeyVisual Content="U" VisualType="SmallOutline" />
|
||||
<styles:KeyVisual Content="Win (Left)" VisualType="SmallOutline" />
|
||||
<styles:KeyVisual Content="T" VisualType="SmallOutline" />
|
||||
</StackPanel>
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
@@ -193,7 +192,7 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBox Header="Application" Text="Keyboardmanager.exe" />
|
||||
<TextBox Header="Application" Text="WindowsTerminal.exe" />
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
Height="32"
|
||||
@@ -203,11 +202,11 @@
|
||||
<TextBox
|
||||
Grid.Row="1"
|
||||
Header="Arguments"
|
||||
Text="-config json" />
|
||||
Text="-config" />
|
||||
<TextBox
|
||||
Grid.Row="2"
|
||||
Header="Start in directory"
|
||||
Text="C:\Users\Dev\PowerToys\bin" />
|
||||
Text="C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.21.10351.0_x64__8wekyb3d8bbwe" />
|
||||
<Button
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace KeyboardManagerEditorUI.Pages
|
||||
this.InitializeComponent();
|
||||
|
||||
Shortcuts = new ObservableCollection<URLShortcut>();
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Win", "U", }, URL = "https://www.bing.com" });
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Win (Left)", "T", }, URL = "https://www.bing.com" });
|
||||
}
|
||||
|
||||
private async void NewShortcutBtn_Click(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -12,6 +14,7 @@ using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using System.Text;
|
||||
using KeyboardManagerEditorUI.Helpers;
|
||||
using KeyboardManagerEditorUI.Interop;
|
||||
using ManagedCommon;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
@@ -123,7 +126,7 @@ namespace KeyboardManagerEditorUI.Pages
|
||||
OriginalKeys = originalKeyNames,
|
||||
RemappedKeys = targetKeyNames,
|
||||
IsAllApps = string.IsNullOrEmpty(mapping.TargetApp),
|
||||
AppName = mapping.TargetApp ?? string.Empty,
|
||||
AppName = string.IsNullOrEmpty(mapping.TargetApp) ? "All Apps" : mapping.TargetApp,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -158,7 +161,19 @@ namespace KeyboardManagerEditorUI.Pages
|
||||
|
||||
private async void NewShortcutBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ShortcutControl.SetOriginalKeys(new List<string>());
|
||||
ShortcutControl.SetRemappedKeys(new List<string>());
|
||||
ShortcutControl.SetApp(false, string.Empty);
|
||||
|
||||
KeyDialog.PrimaryButtonClick += KeyDialog_PrimaryButtonClick;
|
||||
await KeyDialog.ShowAsync();
|
||||
KeyDialog.PrimaryButtonClick -= KeyDialog_PrimaryButtonClick;
|
||||
}
|
||||
|
||||
private void KeyDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
||||
{
|
||||
SaveCurrentMapping();
|
||||
LoadMappings();
|
||||
}
|
||||
|
||||
private async void ListView_ItemClick(object sender, ItemClickEventArgs e)
|
||||
@@ -171,5 +186,75 @@ namespace KeyboardManagerEditorUI.Pages
|
||||
await KeyDialog.ShowAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetKeyCode(string keyName)
|
||||
{
|
||||
return KeyboardManagerInterop.GetKeyCodeFromName(keyName);
|
||||
}
|
||||
|
||||
private void SaveCurrentMapping()
|
||||
{
|
||||
if (_mappingService == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
List<string> originalKeys = ShortcutControl.GetOriginalKeys();
|
||||
List<string> remappedKeys = ShortcutControl.GetRemappedKeys();
|
||||
bool isAppSpecific = ShortcutControl.GetIsAppSpecific();
|
||||
string appName = ShortcutControl.GetAppName();
|
||||
|
||||
// mock data
|
||||
// originalKeys = ["A", "Ctrl"];
|
||||
// remappedKeys = ["B"];
|
||||
if (originalKeys == null || originalKeys.Count == 0 || remappedKeys == null || remappedKeys.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (originalKeys.Count == 1)
|
||||
{
|
||||
int originalKey = GetKeyCode(originalKeys[0]);
|
||||
if (originalKey != 0)
|
||||
{
|
||||
if (remappedKeys.Count == 1)
|
||||
{
|
||||
int targetKey = GetKeyCode(remappedKeys[0]);
|
||||
if (targetKey != 0)
|
||||
{
|
||||
_mappingService.AddSingleKeyMapping(originalKey, targetKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string targetKeys = string.Join(";", remappedKeys.Select(k => GetKeyCode(k).ToString(CultureInfo.InvariantCulture)));
|
||||
_mappingService.AddSingleKeyMapping(originalKey, targetKeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string originalKeysString = string.Join(";", originalKeys.Select(k => GetKeyCode(k).ToString(CultureInfo.InvariantCulture)));
|
||||
string targetKeysString = string.Join(";", remappedKeys.Select(k => GetKeyCode(k).ToString(CultureInfo.InvariantCulture)));
|
||||
|
||||
if (isAppSpecific && !string.IsNullOrEmpty(appName))
|
||||
{
|
||||
_mappingService.AddShortcutMapping(originalKeysString, targetKeysString, appName);
|
||||
}
|
||||
else
|
||||
{
|
||||
_mappingService.AddShortcutMapping(originalKeysString, targetKeysString);
|
||||
}
|
||||
}
|
||||
|
||||
_mappingService.SaveSettings();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Error saving shortcut mapping: " + ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +33,8 @@ namespace KeyboardManagerEditorUI.Pages
|
||||
this.InitializeComponent();
|
||||
|
||||
Shortcuts = new ObservableCollection<URLShortcut>();
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Shift", "Win", "M" }, URL = "Hello" });
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Win", "P", }, URL = "Nice!" });
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Shift", "Win", "M" }, URL = "I like it" });
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Win", "U", }, URL = "Yes" });
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Ctrl", "P" }, URL = "OK" });
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Alt (Left)", "H" }, URL = "Hello" });
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Win (Left)", "P", }, URL = "PowerToys" });
|
||||
}
|
||||
|
||||
private async void NewShortcutBtn_Click(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -156,16 +156,15 @@
|
||||
Style="{StaticResource CustomShortcutToggleButtonStyle}">
|
||||
<ToggleButton.Content>
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<styles:KeyVisual Content="Shift" VisualType="SmallOutline" />
|
||||
<styles:KeyVisual Content="Win" VisualType="SmallOutline" />
|
||||
<styles:KeyVisual Content="M" VisualType="SmallOutline" />
|
||||
<styles:KeyVisual Content="Win (Left)" VisualType="SmallOutline" />
|
||||
<styles:KeyVisual Content="B" VisualType="SmallOutline" />
|
||||
</StackPanel>
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
<TextBox
|
||||
Margin="0,24,0,0"
|
||||
Header="URL to open"
|
||||
Text="https://www.microsoft.com" />
|
||||
Text="https://www.bing.com" />
|
||||
</StackPanel>
|
||||
</ContentDialog>
|
||||
</Grid>
|
||||
|
||||
@@ -7,8 +7,11 @@ using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using System.Text;
|
||||
using KeyboardManagerEditorUI.Helpers;
|
||||
using KeyboardManagerEditorUI.Interop;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
@@ -24,21 +27,60 @@ namespace KeyboardManagerEditorUI.Pages
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class URLs : Page
|
||||
public sealed partial class URLs : Page, IDisposable
|
||||
{
|
||||
private KeyboardMappingService? _mappingService;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public ObservableCollection<URLShortcut> Shortcuts { get; set; }
|
||||
|
||||
[DllImport("PowerToys.KeyboardManagerEditorLibraryWrapper.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
private static extern void GetKeyDisplayName(int keyCode, [Out] StringBuilder keyName, int maxLength);
|
||||
|
||||
public URLs()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
Shortcuts = new ObservableCollection<URLShortcut>();
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Shift", "Win", "M" }, URL = "https://www.microsoft.com" });
|
||||
|
||||
_mappingService = new KeyboardMappingService();
|
||||
|
||||
foreach (var mapping in _mappingService.GetShortcutMappingsByType(ShortcutOperationType.OpenUri))
|
||||
{
|
||||
string[] originalKeyCodes = mapping.OriginalKeys.Split(';');
|
||||
var originalKeyNames = new List<string>();
|
||||
foreach (var keyCode in originalKeyCodes)
|
||||
{
|
||||
if (int.TryParse(keyCode, out int code))
|
||||
{
|
||||
originalKeyNames.Add(GetKeyDisplayName(code));
|
||||
}
|
||||
}
|
||||
|
||||
var shortcut = new URLShortcut
|
||||
{
|
||||
Shortcut = originalKeyNames,
|
||||
URL = mapping.UriToOpen,
|
||||
};
|
||||
Shortcuts.Add(shortcut);
|
||||
}
|
||||
|
||||
/*
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Shift", "Win", "M" }, URL = "https://www.microsoft.com" });
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Win", "P", }, URL = "https://www.bing.com" });
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Shift", "Win", "M" }, URL = "https://www.windows.com" });
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Win", "U", }, URL = "https://www.bing.com" });
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Ctrl", "P" }, URL = "https://www.surface.com" });
|
||||
Shortcuts.Add(new URLShortcut() { Shortcut = new List<string>() { "Alt", "Ctrl", "Shift" }, URL = "https://www.bing.com" });
|
||||
*/
|
||||
}
|
||||
|
||||
public static string GetKeyDisplayName(int keyCode)
|
||||
{
|
||||
var keyName = new StringBuilder(64);
|
||||
GetKeyDisplayName(keyCode, keyName, keyName.Capacity);
|
||||
return keyName.ToString();
|
||||
}
|
||||
|
||||
private async void NewShortcutBtn_Click(object sender, RoutedEventArgs e)
|
||||
@@ -50,5 +92,26 @@ namespace KeyboardManagerEditorUI.Pages
|
||||
{
|
||||
await KeyDialog.ShowAsync();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// Dispose managed resources
|
||||
_mappingService?.Dispose();
|
||||
_mappingService = null;
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,26 @@ namespace KeyboardManagerEditorUI.Styles
|
||||
RemappedKeys.ItemsSource = keys;
|
||||
}
|
||||
|
||||
public List<string> GetOriginalKeys()
|
||||
{
|
||||
return OriginalKeys.ItemsSource as List<string> ?? new List<string>();
|
||||
}
|
||||
|
||||
public List<string> GetRemappedKeys()
|
||||
{
|
||||
return RemappedKeys.ItemsSource as List<string> ?? new List<string>();
|
||||
}
|
||||
|
||||
public bool GetIsAppSpecific()
|
||||
{
|
||||
return AllAppsCheckBox.IsChecked ?? false;
|
||||
}
|
||||
|
||||
public string GetAppName()
|
||||
{
|
||||
return AppNameTextBox.Text ?? string.Empty;
|
||||
}
|
||||
|
||||
private void OriginalToggleBtn_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
RemappedToggleBtn.IsChecked = false;
|
||||
|
||||
Reference in New Issue
Block a user