// 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 GetSingleKeyMappings() { var result = new List(); 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 GetShortcutMappings() { var result = new List(); 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 GetShortcutMappingsByType(ShortcutOperationType operationType) { var result = new List(); 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 GetKeyToTextMappings() { var result = new List(); 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); } } }