mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 01:36:31 +02:00
## Running the Project **Option 1: Test via runner** 1. Check out branch `niels9001/kbm-ux-consolidation` 2. Build PowerToys project 3. Manually build `Modules/KeyboardManagerEditorUI` project separately 4. Run `runner` project 5. Ensure experimental features are enabled in general settings (should be on by default) 6. Launch keyboard manager via settings app **Option 2: Test via installer** 1. Install PowerToys via installer on azure pipeline 1. Launch keyboard manager ## Validation For each page (Text, Remappings, Programs, URLs): * Create shortcuts with variable options and ensure they run as expected * Delete shortcuts and ensure they no longer execute * Try to create invalid shortcuts to check for proper validation * Ensure created shortcuts appear in Power Toys Settings Keyboard manager page * Try toggling shortcuts * Try deleting shortcuts while toggled off ### UI * Any feedback on UI design appreciated as well <img width="1071" height="671" alt="image" src="https://github.com/user-attachments/assets/d2e81de0-6d92-4189-9a33-32e94cce74f7" /> <img width="2142" height="1341" alt="image" src="https://github.com/user-attachments/assets/0e4e5685-fdf1-4dfd-ba52-a2e5bc9a66db" /> Closes: #15870 Closes: #31902 Closes: #45302 Closes: #36227 Closes: #16093 Closes: #13409 Closes: #9919 Closes: #9482 Closes: #8798 Closes: #7054 Closes: #2733 Closes: #2027 Closes: #30167 --------- Co-authored-by: Hao Liu <liuhao3418@gmail.com> Co-authored-by: chenmy77 <162882040+chenmy77@users.noreply.github.com> Co-authored-by: Niels Laute <niels.laute@live.nl> Co-authored-by: Jay <65828559+Jay-o-Way@users.noreply.github.com> Co-authored-by: Jaylyn Barbee <51131738+Jaylyn-Barbee@users.noreply.github.com> Co-authored-by: Dustin L. Howett <duhowett@microsoft.com>
297 lines
11 KiB
C#
297 lines
11 KiB
C#
// 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;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using ManagedCommon;
|
|
|
|
namespace KeyboardManagerEditorUI.Interop
|
|
{
|
|
public class KeyboardMappingService : IDisposable
|
|
{
|
|
private IntPtr _configHandle;
|
|
private bool _disposed;
|
|
|
|
public KeyboardMappingService()
|
|
{
|
|
_configHandle = KeyboardManagerInterop.CreateMappingConfiguration();
|
|
if (_configHandle == IntPtr.Zero)
|
|
{
|
|
Logger.LogError("Failed to create mapping configuration");
|
|
throw new InvalidOperationException("Failed to create mapping configuration");
|
|
}
|
|
|
|
KeyboardManagerInterop.LoadMappingSettings(_configHandle);
|
|
}
|
|
|
|
public List<KeyMapping> GetSingleKeyMappings()
|
|
{
|
|
var result = new List<KeyMapping>();
|
|
int count = KeyboardManagerInterop.GetSingleKeyRemapCount(_configHandle);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var mapping = default(SingleKeyMapping);
|
|
if (KeyboardManagerInterop.GetSingleKeyRemap(_configHandle, i, ref mapping))
|
|
{
|
|
result.Add(new KeyMapping
|
|
{
|
|
OriginalKey = mapping.OriginalKey,
|
|
TargetKey = KeyboardManagerInterop.GetStringAndFree(mapping.TargetKey),
|
|
IsShortcut = mapping.IsShortcut,
|
|
});
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public List<ShortcutKeyMapping> GetShortcutMappings()
|
|
{
|
|
var result = new List<ShortcutKeyMapping>();
|
|
int count = KeyboardManagerInterop.GetShortcutRemapCount(_configHandle);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var mapping = default(ShortcutMapping);
|
|
if (KeyboardManagerInterop.GetShortcutRemap(_configHandle, i, ref mapping))
|
|
{
|
|
result.Add(new ShortcutKeyMapping
|
|
{
|
|
OriginalKeys = KeyboardManagerInterop.GetStringAndFree(mapping.OriginalKeys),
|
|
TargetKeys = KeyboardManagerInterop.GetStringAndFree(mapping.TargetKeys),
|
|
TargetApp = KeyboardManagerInterop.GetStringAndFree(mapping.TargetApp),
|
|
OperationType = (ShortcutOperationType)mapping.OperationType,
|
|
TargetText = KeyboardManagerInterop.GetStringAndFree(mapping.TargetText),
|
|
ProgramPath = KeyboardManagerInterop.GetStringAndFree(mapping.ProgramPath),
|
|
ProgramArgs = KeyboardManagerInterop.GetStringAndFree(mapping.ProgramArgs),
|
|
UriToOpen = KeyboardManagerInterop.GetStringAndFree(mapping.UriToOpen),
|
|
});
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public List<ShortcutKeyMapping> GetShortcutMappingsByType(ShortcutOperationType operationType)
|
|
{
|
|
var result = new List<ShortcutKeyMapping>();
|
|
int count = KeyboardManagerInterop.GetShortcutRemapCountByType(_configHandle, (int)operationType);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var mapping = default(ShortcutMapping);
|
|
if (KeyboardManagerInterop.GetShortcutRemapByType(_configHandle, (int)operationType, i, ref mapping))
|
|
{
|
|
result.Add(new ShortcutKeyMapping
|
|
{
|
|
OriginalKeys = KeyboardManagerInterop.GetStringAndFree(mapping.OriginalKeys),
|
|
TargetKeys = KeyboardManagerInterop.GetStringAndFree(mapping.TargetKeys),
|
|
TargetApp = KeyboardManagerInterop.GetStringAndFree(mapping.TargetApp),
|
|
OperationType = (ShortcutOperationType)mapping.OperationType,
|
|
TargetText = KeyboardManagerInterop.GetStringAndFree(mapping.TargetText),
|
|
ProgramPath = KeyboardManagerInterop.GetStringAndFree(mapping.ProgramPath),
|
|
ProgramArgs = KeyboardManagerInterop.GetStringAndFree(mapping.ProgramArgs),
|
|
UriToOpen = KeyboardManagerInterop.GetStringAndFree(mapping.UriToOpen),
|
|
});
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public List<KeyToTextMapping> GetKeyToTextMappings()
|
|
{
|
|
var result = new List<KeyToTextMapping>();
|
|
int count = KeyboardManagerInterop.GetSingleKeyToTextRemapCount(_configHandle);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var mapping = default(KeyboardTextMapping);
|
|
if (KeyboardManagerInterop.GetSingleKeyToTextRemap(_configHandle, i, ref mapping))
|
|
{
|
|
result.Add(new KeyToTextMapping
|
|
{
|
|
OriginalKey = mapping.OriginalKey,
|
|
TargetText = KeyboardManagerInterop.GetStringAndFree(mapping.TargetText),
|
|
});
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public string GetKeyDisplayName(int keyCode)
|
|
{
|
|
var keyName = new StringBuilder(64);
|
|
KeyboardManagerInterop.GetKeyDisplayName(keyCode, keyName, keyName.Capacity);
|
|
return keyName.ToString();
|
|
}
|
|
|
|
public int GetKeyCodeFromName(string keyName)
|
|
{
|
|
if (string.IsNullOrEmpty(keyName))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int keyCode = KeyboardManagerInterop.GetKeyCodeFromName(keyName);
|
|
Logger.LogInfo($"Key code for key name {keyName}: {keyCode}");
|
|
return keyCode;
|
|
}
|
|
|
|
public bool AddSingleKeyMapping(int originalKey, int targetKey)
|
|
{
|
|
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 AddSingleKeyToTextMapping(int originalKey, string targetText)
|
|
{
|
|
if (string.IsNullOrEmpty(targetText))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return KeyboardManagerInterop.AddSingleKeyToTextRemap(_configHandle, originalKey, targetText);
|
|
}
|
|
|
|
public bool AddShortcutMapping(string originalKeys, string targetKeys, string targetApp = "", ShortcutOperationType operationType = ShortcutOperationType.RemapShortcut)
|
|
{
|
|
if (string.IsNullOrEmpty(originalKeys) || string.IsNullOrEmpty(targetKeys))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return KeyboardManagerInterop.AddShortcutRemap(_configHandle, originalKeys, targetKeys, targetApp, (int)operationType);
|
|
}
|
|
|
|
public bool AddShortcutMapping(ShortcutKeyMapping shortcutKeyMapping)
|
|
{
|
|
if (string.IsNullOrEmpty(shortcutKeyMapping.OriginalKeys) || string.IsNullOrEmpty(shortcutKeyMapping.TargetKeys))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (shortcutKeyMapping.OperationType == ShortcutOperationType.RunProgram && string.IsNullOrEmpty(shortcutKeyMapping.ProgramPath))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (shortcutKeyMapping.OperationType == ShortcutOperationType.OpenUri && string.IsNullOrEmpty(shortcutKeyMapping.UriToOpen))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (shortcutKeyMapping.OperationType == ShortcutOperationType.RunProgram)
|
|
{
|
|
return KeyboardManagerInterop.AddShortcutRemap(
|
|
_configHandle,
|
|
shortcutKeyMapping.OriginalKeys,
|
|
shortcutKeyMapping.TargetKeys,
|
|
shortcutKeyMapping.TargetApp,
|
|
(int)shortcutKeyMapping.OperationType,
|
|
shortcutKeyMapping.ProgramPath,
|
|
string.IsNullOrEmpty(shortcutKeyMapping.ProgramArgs) ? null : shortcutKeyMapping.ProgramArgs,
|
|
string.IsNullOrEmpty(shortcutKeyMapping.StartInDirectory) ? null : shortcutKeyMapping.StartInDirectory,
|
|
(int)shortcutKeyMapping.Elevation,
|
|
(int)shortcutKeyMapping.IfRunningAction,
|
|
(int)shortcutKeyMapping.Visibility);
|
|
}
|
|
else if (shortcutKeyMapping.OperationType == ShortcutOperationType.OpenUri)
|
|
{
|
|
return KeyboardManagerInterop.AddShortcutRemap(
|
|
_configHandle,
|
|
shortcutKeyMapping.OriginalKeys,
|
|
shortcutKeyMapping.TargetKeys,
|
|
shortcutKeyMapping.TargetApp,
|
|
(int)shortcutKeyMapping.OperationType,
|
|
shortcutKeyMapping.UriToOpen);
|
|
}
|
|
|
|
return KeyboardManagerInterop.AddShortcutRemap(
|
|
_configHandle,
|
|
shortcutKeyMapping.OriginalKeys,
|
|
shortcutKeyMapping.TargetKeys,
|
|
shortcutKeyMapping.TargetApp,
|
|
(int)shortcutKeyMapping.OperationType);
|
|
}
|
|
|
|
public bool SaveSettings()
|
|
{
|
|
return KeyboardManagerInterop.SaveMappingSettings(_configHandle);
|
|
}
|
|
|
|
public bool DeleteSingleKeyMapping(int originalKey)
|
|
{
|
|
return KeyboardManagerInterop.DeleteSingleKeyRemap(_configHandle, originalKey);
|
|
}
|
|
|
|
public bool DeleteSingleKeyToTextMapping(int originalKey)
|
|
{
|
|
if (originalKey == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return KeyboardManagerInterop.DeleteSingleKeyToTextRemap(_configHandle, originalKey);
|
|
}
|
|
|
|
public bool DeleteShortcutMapping(string originalKeys, string targetApp = "")
|
|
{
|
|
if (string.IsNullOrEmpty(originalKeys))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return KeyboardManagerInterop.DeleteShortcutRemap(_configHandle, originalKeys, targetApp ?? string.Empty);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (!_disposed)
|
|
{
|
|
if (_configHandle != IntPtr.Zero)
|
|
{
|
|
KeyboardManagerInterop.DestroyMappingConfiguration(_configHandle);
|
|
_configHandle = IntPtr.Zero;
|
|
}
|
|
|
|
_disposed = true;
|
|
}
|
|
}
|
|
|
|
~KeyboardMappingService()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
}
|
|
}
|