From 90add546ba5f60d6a2c9c532522ca564dd2c5986 Mon Sep 17 00:00:00 2001 From: MohammadKarimi Date: Tue, 5 Nov 2024 01:03:42 +1100 Subject: [PATCH 1/6] Add new hook for hotkeys. --- .../PaletteStateOrchestratorViewModel.cs | 165 +++++++++--------- 1 file changed, 85 insertions(+), 80 deletions(-) diff --git a/src/Riter/ViewModel/PaletteStateOrchestratorViewModel.cs b/src/Riter/ViewModel/PaletteStateOrchestratorViewModel.cs index 353197d..700c536 100644 --- a/src/Riter/ViewModel/PaletteStateOrchestratorViewModel.cs +++ b/src/Riter/ViewModel/PaletteStateOrchestratorViewModel.cs @@ -5,6 +5,8 @@ namespace Riter.ViewModel; public class PaletteStateOrchestratorViewModel : BaseViewModel { + private readonly AppSettings _appSettings; + public PaletteStateOrchestratorViewModel( DrawingViewModel drawingViewModel, StrokeVisibilityViewModel strokeVisibilityViewModel, @@ -13,8 +15,10 @@ public PaletteStateOrchestratorViewModel( InkEditingModeViewModel inkEditingModeViewModel, HighlighterViewModel highlighterViewModel, SettingPanelViewModel settingPanelViewModel, - ButtonSelectedViewModel buttonSelectedViewModel) + ButtonSelectedViewModel buttonSelectedViewModel, + AppSettings appSettings) { + _appSettings = appSettings; DrawingViewModel = drawingViewModel; StrokeVisibilityViewModel = strokeVisibilityViewModel; StrokeHistoryViewModel = strokeHistoryViewModel; @@ -48,85 +52,86 @@ public PaletteStateOrchestratorViewModel( public void HandleHotkey(HotKey hotKey) { - switch (hotKey) - { - case HotKey.Drawing: - DrawingViewModel.StartDrawingCommand.Execute(null); - break; - case HotKey.Erasing: - DrawingViewModel.StartErasingCommand.Execute(null); - break; - case HotKey.Trash: - StrokeHistoryViewModel.ClearCommand.Execute(null); - break; - case HotKey.Highlighter: - DrawingViewModel.ToggleHighlighterCommand.Execute(null); - break; - case HotKey.Release: - DrawingViewModel.ReleaseCommand.Execute(null); - break; - case HotKey.HideAll: - StrokeVisibilityViewModel.HideAllCommand.Execute(null); - break; - case HotKey.Undo: - StrokeHistoryViewModel.UndoCommand.Execute(null); - break; - case HotKey.Redo: - StrokeHistoryViewModel.RedoCommand.Execute(null); - break; - case HotKey.SizeOfBrush1X: - BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X1); - break; - case HotKey.SizeOfBrush2X: - BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X2); - break; - case HotKey.SizeOfBrush3X: - BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X3); - break; - - case HotKey.Yellow: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Yellow); - break; - case HotKey.Purple: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Purple); - break; - case HotKey.Mint: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Mint); - break; - case HotKey.Coral: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Coral); - break; - case HotKey.Red: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Red); - break; - case HotKey.Cyan: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Cyan); - break; - case HotKey.White: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.White); - break; - case HotKey.Orange: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Orange); - break; - case HotKey.Gray: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Gray); - break; - case HotKey.Black: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Black); - break; - - case HotKey.TransparentBackground: - InkEditingModeViewModel.EnableTransparentCommand.Execute(null); - break; - case HotKey.BlackboardBackground: - InkEditingModeViewModel.EnableBlackboardCommand.Execute(null); - break; - case HotKey.WhiteboardBackground: - InkEditingModeViewModel.EnableWhiteboardCommand.Execute(null); - break; - default: - break; - } + // _appSettings.HotKeysConfig.FirstOrDefault() + //switch (hotKey) + //{ + // case HotKey.Drawing: + // DrawingViewModel.StartDrawingCommand.Execute(null); + // break; + // case HotKey.Erasing: + // DrawingViewModel.StartErasingCommand.Execute(null); + // break; + // case HotKey.Trash: + // StrokeHistoryViewModel.ClearCommand.Execute(null); + // break; + // case HotKey.Highlighter: + // DrawingViewModel.ToggleHighlighterCommand.Execute(null); + // break; + // case HotKey.Release: + // DrawingViewModel.ReleaseCommand.Execute(null); + // break; + // case HotKey.HideAll: + // StrokeVisibilityViewModel.HideAllCommand.Execute(null); + // break; + // case HotKey.Undo: + // StrokeHistoryViewModel.UndoCommand.Execute(null); + // break; + // case HotKey.Redo: + // StrokeHistoryViewModel.RedoCommand.Execute(null); + // break; + // case HotKey.SizeOfBrush1X: + // BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X1); + // break; + // case HotKey.SizeOfBrush2X: + // BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X2); + // break; + // case HotKey.SizeOfBrush3X: + // BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X3); + // break; + + // case HotKey.Yellow: + // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Yellow); + // break; + // case HotKey.Purple: + // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Purple); + // break; + // case HotKey.Mint: + // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Mint); + // break; + // case HotKey.Coral: + // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Coral); + // break; + // case HotKey.Red: + // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Red); + // break; + // case HotKey.Cyan: + // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Cyan); + // break; + // case HotKey.White: + // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.White); + // break; + // case HotKey.Orange: + // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Orange); + // break; + // case HotKey.Gray: + // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Gray); + // break; + // case HotKey.Black: + // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Black); + // break; + + // case HotKey.TransparentBackground: + // InkEditingModeViewModel.EnableTransparentCommand.Execute(null); + // break; + // case HotKey.BlackboardBackground: + // InkEditingModeViewModel.EnableBlackboardCommand.Execute(null); + // break; + // case HotKey.WhiteboardBackground: + // InkEditingModeViewModel.EnableWhiteboardCommand.Execute(null); + // break; + // default: + // break; + //} } private void OnBrushOrHighlightChanged(string propertyName) From 3d16a1c1b6680eada2ca56e007adb65102ca2882 Mon Sep 17 00:00:00 2001 From: MohammadKarimi Date: Tue, 5 Nov 2024 01:03:55 +1100 Subject: [PATCH 2/6] add new hotkey object to map --- src/Riter/Core/HotKey/GlobalHotkeyManager.cs | 216 +++++++++---------- src/Riter/Core/HotKey/HotKey.cs | 57 ++--- src/Riter/Core/HotKey/HotKeysConfig.cs | 4 +- src/Riter/Core/HotKey/HotkeyLoader.cs | 52 ++--- 4 files changed, 160 insertions(+), 169 deletions(-) diff --git a/src/Riter/Core/HotKey/GlobalHotkeyManager.cs b/src/Riter/Core/HotKey/GlobalHotkeyManager.cs index be56ed6..1f062eb 100644 --- a/src/Riter/Core/HotKey/GlobalHotkeyManager.cs +++ b/src/Riter/Core/HotKey/GlobalHotkeyManager.cs @@ -1,114 +1,102 @@ -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Windows.Interop; - -namespace Riter.Core; - -/// -/// Provides a mechanism for registering and managing multiple global hotkeys in a WPF application. -/// Allows triggering specific actions using keyboard shortcuts, even when the application is not in focus. -/// -public partial class GlobalHotKeyManager : IDisposable -{ - private readonly IntPtr _windowHandle; - private readonly HwndSource _source; - private readonly Dictionary> _hotkeyActions = []; - - private bool _isHookAdded; - - /// - /// Initializes a new instance of the class for the specified WPF window. - /// - /// The WPF window that the global hotkeys will be tied to. - public GlobalHotKeyManager(Window window) - { - _windowHandle = new WindowInteropHelper(window).Handle; - _source = HwndSource.FromHwnd(_windowHandle); - } - - public bool RegisterHotkey(HotKey id, uint modifiers, uint key, Action callback) - { - if (!_isHookAdded) - { - _source.AddHook(HwndHook); - _isHookAdded = true; - } - - var registered = RegisterHotKey(_windowHandle, (int)id, modifiers, key); - if (registered) - { - _hotkeyActions[id] = callback; - } - - return registered; - } - - - /// - /// Unregisters a hotkey by its unique identifier. - /// - /// The unique identifier of the hotkey to unregister. - public void UnregisterHotkey(HotKey id) - { - if (_hotkeyActions.ContainsKey(id)) - { - UnregisterHotKey(_windowHandle, (int)id); - _hotkeyActions.Remove(id); - } - } - - /// - /// Releases all resources used by the class. - /// Unregisters all registered hotkeys and removes the window hook. - /// - public void Dispose() - { - foreach (var id in _hotkeyActions.Keys) - { - UnregisterHotKey(_windowHandle, (int)id); - } - - _source.RemoveHook(HwndHook); - _hotkeyActions.Clear(); - } - - [LibraryImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - private static partial bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); - - [LibraryImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - private static partial bool UnregisterHotKey(IntPtr hWnd, int id); - - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); - - /// - /// Processes window messages for registered hotkeys. - /// Invokes the associated callback action when a hotkey is pressed. - /// - /// The handle to the window receiving the message. - /// The message identifier. - /// wParam Additional message information. - /// lParam Additional message information. - /// Indicates whether the message has been handled. - /// The return value is zero if the message is handled. - private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) - { - const int wM_HOTKEY = 0x0312; - - if (msg == wM_HOTKEY) - { - var id = (HotKey)wParam.ToInt32(); - - if (_hotkeyActions.TryGetValue(id, out var value)) - { - value?.Invoke(id); - handled = true; - } - } - - // Call the next hook in the chain, allowing other applications to receive the keystroke - return CallNextHookEx(IntPtr.Zero, msg, wParam, lParam); - } -} +//using System.Runtime.InteropServices; +//using System.Windows.Interop; + +//namespace Riter.Core; + +///// +///// Provides a mechanism for registering and managing multiple global hotkeys in a WPF application. +///// Allows triggering specific actions using keyboard shortcuts, even when the application is not in focus. +///// +//public partial class GlobalHotKeyManager : IDisposable +//{ +// private readonly IntPtr _windowHandle; +// private readonly HwndSource _source; +// private readonly Dictionary> _hotkeyActions = []; + +// private bool _isHookAdded; + +// /// +// /// Initializes a new instance of the class for the specified WPF window. +// /// +// /// The WPF window that the global hotkeys will be tied to. +// public GlobalHotKeyManager(Window window) +// { +// _windowHandle = new WindowInteropHelper(window).Handle; +// _source = HwndSource.FromHwnd(_windowHandle); +// } + +// public bool RegisterHotkey(HotKey id, uint modifiers, uint key, Action callback) +// { +// if (!_isHookAdded) +// { +// _source.AddHook(HwndHook); +// _isHookAdded = true; +// } + +// var registered = RegisterHotKey(_windowHandle, (int)id, modifiers, key); +// if (registered) +// { +// _hotkeyActions[id] = callback; +// } + +// return registered; +// } + + +// /// +// /// Unregisters a hotkey by its unique identifier. +// /// +// /// The unique identifier of the hotkey to unregister. +// public void UnregisterHotkey(HotKey id) +// { +// if (_hotkeyActions.ContainsKey(id)) +// { +// UnregisterHotKey(_windowHandle, (int)id); +// _hotkeyActions.Remove(id); +// } +// } + +// /// +// /// Releases all resources used by the class. +// /// Unregisters all registered hotkeys and removes the window hook. +// /// +// public void Dispose() +// { +// foreach (var id in _hotkeyActions.Keys) +// { +// UnregisterHotKey(_windowHandle, (int)id); +// } + +// _source.RemoveHook(HwndHook); +// _hotkeyActions.Clear(); +// } + +// [LibraryImport("user32.dll")] +// [return: MarshalAs(UnmanagedType.Bool)] +// private static partial bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); + +// [LibraryImport("user32.dll")] +// [return: MarshalAs(UnmanagedType.Bool)] +// private static partial bool UnregisterHotKey(IntPtr hWnd, int id); + +// [LibraryImport("user32.dll", SetLastError = true)] +// private static partial IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); + +// private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) +// { +// const int wM_HOTKEY = 0x0312; + +// if (msg == wM_HOTKEY) +// { +// var id = (HotKey)wParam.ToInt32(); + +// if (_hotkeyActions.TryGetValue(id, out var value)) +// { +// value?.Invoke(id); +// handled = true; +// } +// } + +// return CallNextHookEx(IntPtr.Zero, msg, wParam, lParam); +// } +//} diff --git a/src/Riter/Core/HotKey/HotKey.cs b/src/Riter/Core/HotKey/HotKey.cs index 1a261dd..123f9dd 100644 --- a/src/Riter/Core/HotKey/HotKey.cs +++ b/src/Riter/Core/HotKey/HotKey.cs @@ -1,29 +1,32 @@ namespace Riter.Core; -public enum HotKey -{ - Drawing = 9000, - Erasing = 9001, - HideAll = 9002, - Trash = 9003, - Undo = 9004, - Redo = 9005, - Highlighter = 9006, - Release = 9007, - SizeOfBrush1X = 9008, - SizeOfBrush2X = 9009, - SizeOfBrush3X = 9010, - TransparentBackground = 9011, - WhiteboardBackground = 9012, - BlackboardBackground = 9013, +//public enum HotKey +//{ +// Drawing = 9000, +// Erasing = 9001, +// HideAll = 9002, +// Trash = 9003, +// Undo = 9004, +// Redo = 9005, +// Highlighter = 9006, +// Release = 9007, +// SizeOfBrush1X = 9008, +// SizeOfBrush2X = 9009, +// SizeOfBrush3X = 9010, +// TransparentBackground = 9011, +// WhiteboardBackground = 9012, +// BlackboardBackground = 9013, - Yellow = 9014, - Purple = 9015, - Mint = 9016, - Coral = 9017, - Red = 9018, - Cyan = 9019, - White = 9020, - Orange = 9021, - Gray = 9022, - Black = 9023 -} +// Yellow = 9014, +// Purple = 9015, +// Mint = 9016, +// Coral = 9017, +// Red = 9018, +// Cyan = 9019, +// White = 9020, +// Orange = 9021, +// Gray = 9022, +// Black = 9023 +//} + + +public record struct HotKey(int Key, bool CtrlPressed, bool ShiftPressed); diff --git a/src/Riter/Core/HotKey/HotKeysConfig.cs b/src/Riter/Core/HotKey/HotKeysConfig.cs index 70be3a7..5ec46fb 100644 --- a/src/Riter/Core/HotKey/HotKeysConfig.cs +++ b/src/Riter/Core/HotKey/HotKeysConfig.cs @@ -9,7 +9,7 @@ public class Value public class HotKeysConfig { - public string Key { get; set; } + public string Key { get; init; } - public Value Value { get; set; } + public Value Value { get; init; } } diff --git a/src/Riter/Core/HotKey/HotkeyLoader.cs b/src/Riter/Core/HotKey/HotkeyLoader.cs index 909d5b4..89c7c72 100644 --- a/src/Riter/Core/HotKey/HotkeyLoader.cs +++ b/src/Riter/Core/HotKey/HotkeyLoader.cs @@ -2,34 +2,34 @@ namespace Riter.Core; -public class HotKeyLoader(AppSettings options) -{ - public const uint CTRL = 0x0002; - public const uint SHIFT = 0x0004; - public const uint ALT = 0x0001; +//public class HotKeyLoader(AppSettings options) +//{ +// public const uint CTRL = 0x0002; +// public const uint SHIFT = 0x0004; +// public const uint ALT = 0x0001; - public Dictionary callback)> Loads(PaletteStateOrchestratorViewModel viewModel) - { - Dictionary callback)> hotkeys = []; - foreach (var hotkey in options.HotKeysConfig) - { - var hotKey = System.Enum.Parse(hotkey.Key); - var modifier = GetModifierKey(hotkey.Value.Modifiers); - var key = GetKeyValue(hotkey.Value.Key); +// public Dictionary callback)> Loads(PaletteStateOrchestratorViewModel viewModel) +// { +// Dictionary callback)> hotkeys = []; +// foreach (var hotkey in options.HotKeysConfig) +// { +// var hotKey = System.Enum.Parse(hotkey.Key); +// var modifier = GetModifierKey(hotkey.Value.Modifiers); +// var key = GetKeyValue(hotkey.Value.Key); - hotkeys[hotKey] = (modifier, key, viewModel.HandleHotkey); - } +// hotkeys[hotKey] = (modifier, key, viewModel.HandleHotkey); +// } - return hotkeys; - } +// return hotkeys; +// } - private static uint GetModifierKey(string modifier) => modifier switch - { - "CTRL" => CTRL, - "SHIFT" => SHIFT, - "ALT" => ALT, - _ => 0 - }; +// private static uint GetModifierKey(string modifier) => modifier switch +// { +// "CTRL" => CTRL, +// "SHIFT" => SHIFT, +// "ALT" => ALT, +// _ => 0 +// }; - private static uint GetKeyValue(string key) => key.ToUpper()[0]; -} +// private static uint GetKeyValue(string key) => key.ToUpper()[0]; +//} From d7a4f8a66d1606bd2cd40fa7d03441737bb074fc Mon Sep 17 00:00:00 2001 From: MohammadKarimi Date: Tue, 5 Nov 2024 01:04:03 +1100 Subject: [PATCH 3/6] new listener for hotkeys. --- src/Riter/App.xaml.cs | 1 - src/Riter/Core/AppSettings.cs | 2 +- src/Riter/MainWindow.xaml.cs | 112 ++++++++++++++++++++++++++-------- src/Riter/Riter.csproj | 2 +- 4 files changed, 90 insertions(+), 27 deletions(-) diff --git a/src/Riter/App.xaml.cs b/src/Riter/App.xaml.cs index 919a781..adcf585 100644 --- a/src/Riter/App.xaml.cs +++ b/src/Riter/App.xaml.cs @@ -53,7 +53,6 @@ protected override void OnStartup(StartupEventArgs e) private static void ConfigureServices(ServiceCollection serviceCollection) { - serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); diff --git a/src/Riter/Core/AppSettings.cs b/src/Riter/Core/AppSettings.cs index 4a5a458..b8e090f 100644 --- a/src/Riter/Core/AppSettings.cs +++ b/src/Riter/Core/AppSettings.cs @@ -33,5 +33,5 @@ public class AppSettings /// public const string MyTelegram = "https://t.me/mhakarimi"; - public IEnumerable HotKeysConfig { get; set; } + public List HotKeysConfig { get; set; } } diff --git a/src/Riter/MainWindow.xaml.cs b/src/Riter/MainWindow.xaml.cs index 6ce0eb2..36277b5 100644 --- a/src/Riter/MainWindow.xaml.cs +++ b/src/Riter/MainWindow.xaml.cs @@ -1,7 +1,10 @@ -using System.Windows.Controls; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Windows.Controls; using System.Windows.Ink; using Riter.Core.Extensions; using Riter.Core.Interfaces; +using Riter.Core.UI; using Riter.ViewModel; namespace Riter; @@ -11,21 +14,41 @@ namespace Riter; /// public partial class MainWindow : Window { + private const int WHKEYBOARDLL = 13; + private const int WMKEYDOWN = 0x0100; + private const int WMKEYUP = 0x0101; + + private static readonly LowLevelKeyboardProc _proc = HookCallback; + private static IntPtr _hookID = IntPtr.Zero; + private static bool _ctrlPressed = false; + private static bool _shiftPressed = false; + private static PaletteStateOrchestratorViewModel _orchestratorViewModel; + private readonly IStrokeHistoryService _strokeHistoryService; - private readonly HotKeyLoader _hotKeyLoader; - private readonly PaletteStateOrchestratorViewModel _orchestratorViewModel; - private GlobalHotKeyManager _globalHotkeyManager; - - public MainWindow( - PaletteStateOrchestratorViewModel orchestratorViewModel, - HotKeyLoader hotKeyLoader, - IStrokeHistoryService strokeHistoryService) + + private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool UnhookWindowsHookEx(IntPtr hhk); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr GetModuleHandle(string lpModuleName); + + public MainWindow(PaletteStateOrchestratorViewModel orchestratorViewModel, + IStrokeHistoryService strokeHistoryService) { InitializeComponent(); DataContext = orchestratorViewModel; _orchestratorViewModel = orchestratorViewModel; _strokeHistoryService = strokeHistoryService; - _hotKeyLoader = hotKeyLoader; + // _hotKeyLoader = hotKeyLoader; _strokeHistoryService.SetMainElementToRedoAndUndo(MainInkCanvasControl.MainInkCanvas); MainInkCanvasControl.MainInkCanvas.Strokes.StrokesChanged += StrokesChanged; @@ -35,28 +58,69 @@ public MainWindow( Loaded += MainWindow_Loaded; } + protected override void OnClosed(EventArgs e) + { + base.OnClosed(e); + UnhookWindowsHookEx(_hookID); + } + /// protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); - _globalHotkeyManager = new GlobalHotKeyManager(this); - var hotkies = _hotKeyLoader.Loads(_orchestratorViewModel); + _hookID = SetHook(_proc); + } - foreach (var hotkey in hotkies) - { - _globalHotkeyManager.RegisterHotkey( - hotkey.Key, - hotkey.Value.modifiers, - hotkey.Value.key, - hotkey.Value.callback); - } + private static IntPtr SetHook(LowLevelKeyboardProc proc) + { + using var curProcess = Process.GetCurrentProcess(); + using var curModule = curProcess.MainModule; + return SetWindowsHookEx(WHKEYBOARDLL, proc, GetModuleHandle(curModule.ModuleName), 0); } - /// - protected override void OnClosed(EventArgs e) + private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { - _globalHotkeyManager.Dispose(); - base.OnClosed(e); + var isKey = true; + if (nCode >= 0 && (wParam == WMKEYDOWN || wParam == WMKEYUP)) + { + var vkCode = Marshal.ReadInt32(lParam); + + if (wParam is WMKEYDOWN) + { + if (vkCode == KeyInterop.VirtualKeyFromKey(Key.LeftCtrl) || vkCode == KeyInterop.VirtualKeyFromKey(Key.RightCtrl)) + { + _ctrlPressed = true; + isKey = false; + } + + if (vkCode == KeyInterop.VirtualKeyFromKey(Key.LeftShift) || vkCode == KeyInterop.VirtualKeyFromKey(Key.RightShift)) + { + _shiftPressed = true; + isKey = false; + } + + if (isKey) + { + _orchestratorViewModel.HandleHotkey(new HotKey(vkCode, _ctrlPressed, _shiftPressed)); + _ctrlPressed = false; + _shiftPressed = false; + } + } + else if (wParam == WMKEYUP) + { + if (vkCode == KeyInterop.VirtualKeyFromKey(Key.LeftCtrl) || vkCode == KeyInterop.VirtualKeyFromKey(Key.RightCtrl)) + { + _ctrlPressed = false; + } + + if (vkCode == KeyInterop.VirtualKeyFromKey(Key.LeftShift) || vkCode == KeyInterop.VirtualKeyFromKey(Key.RightShift)) + { + _shiftPressed = false; + } + } + } + + return CallNextHookEx(_hookID, nCode, wParam, lParam); } /// diff --git a/src/Riter/Riter.csproj b/src/Riter/Riter.csproj index ee092bb..6cf6e9f 100644 --- a/src/Riter/Riter.csproj +++ b/src/Riter/Riter.csproj @@ -6,7 +6,7 @@ disable enable true - 0.0.12 + 0.0.13 From 5b72c8d7300c5bea599f1bd31393e4f1684d3e0c Mon Sep 17 00:00:00 2001 From: MohammadKarimi Date: Tue, 5 Nov 2024 02:09:49 +1100 Subject: [PATCH 4/6] Complete hotkey listener and change th econfigs. --- src/Riter/Core/HotKey/GlobalHotkeyManager.cs | 102 ---------- src/Riter/Core/HotKey/HotKey.cs | 60 +++--- src/Riter/Core/HotKey/HotKeysConfig.cs | 12 +- src/Riter/Core/HotKey/HotkeyLoader.cs | 4 +- src/Riter/MainWindow.xaml.cs | 2 +- .../PaletteStateOrchestratorViewModel.cs | 180 ++++++++++-------- src/Riter/appsettings.json | 168 +++++----------- 7 files changed, 187 insertions(+), 341 deletions(-) delete mode 100644 src/Riter/Core/HotKey/GlobalHotkeyManager.cs diff --git a/src/Riter/Core/HotKey/GlobalHotkeyManager.cs b/src/Riter/Core/HotKey/GlobalHotkeyManager.cs deleted file mode 100644 index 1f062eb..0000000 --- a/src/Riter/Core/HotKey/GlobalHotkeyManager.cs +++ /dev/null @@ -1,102 +0,0 @@ -//using System.Runtime.InteropServices; -//using System.Windows.Interop; - -//namespace Riter.Core; - -///// -///// Provides a mechanism for registering and managing multiple global hotkeys in a WPF application. -///// Allows triggering specific actions using keyboard shortcuts, even when the application is not in focus. -///// -//public partial class GlobalHotKeyManager : IDisposable -//{ -// private readonly IntPtr _windowHandle; -// private readonly HwndSource _source; -// private readonly Dictionary> _hotkeyActions = []; - -// private bool _isHookAdded; - -// /// -// /// Initializes a new instance of the class for the specified WPF window. -// /// -// /// The WPF window that the global hotkeys will be tied to. -// public GlobalHotKeyManager(Window window) -// { -// _windowHandle = new WindowInteropHelper(window).Handle; -// _source = HwndSource.FromHwnd(_windowHandle); -// } - -// public bool RegisterHotkey(HotKey id, uint modifiers, uint key, Action callback) -// { -// if (!_isHookAdded) -// { -// _source.AddHook(HwndHook); -// _isHookAdded = true; -// } - -// var registered = RegisterHotKey(_windowHandle, (int)id, modifiers, key); -// if (registered) -// { -// _hotkeyActions[id] = callback; -// } - -// return registered; -// } - - -// /// -// /// Unregisters a hotkey by its unique identifier. -// /// -// /// The unique identifier of the hotkey to unregister. -// public void UnregisterHotkey(HotKey id) -// { -// if (_hotkeyActions.ContainsKey(id)) -// { -// UnregisterHotKey(_windowHandle, (int)id); -// _hotkeyActions.Remove(id); -// } -// } - -// /// -// /// Releases all resources used by the class. -// /// Unregisters all registered hotkeys and removes the window hook. -// /// -// public void Dispose() -// { -// foreach (var id in _hotkeyActions.Keys) -// { -// UnregisterHotKey(_windowHandle, (int)id); -// } - -// _source.RemoveHook(HwndHook); -// _hotkeyActions.Clear(); -// } - -// [LibraryImport("user32.dll")] -// [return: MarshalAs(UnmanagedType.Bool)] -// private static partial bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); - -// [LibraryImport("user32.dll")] -// [return: MarshalAs(UnmanagedType.Bool)] -// private static partial bool UnregisterHotKey(IntPtr hWnd, int id); - -// [LibraryImport("user32.dll", SetLastError = true)] -// private static partial IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); - -// private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) -// { -// const int wM_HOTKEY = 0x0312; - -// if (msg == wM_HOTKEY) -// { -// var id = (HotKey)wParam.ToInt32(); - -// if (_hotkeyActions.TryGetValue(id, out var value)) -// { -// value?.Invoke(id); -// handled = true; -// } -// } - -// return CallNextHookEx(IntPtr.Zero, msg, wParam, lParam); -// } -//} diff --git a/src/Riter/Core/HotKey/HotKey.cs b/src/Riter/Core/HotKey/HotKey.cs index 123f9dd..c784033 100644 --- a/src/Riter/Core/HotKey/HotKey.cs +++ b/src/Riter/Core/HotKey/HotKey.cs @@ -1,32 +1,34 @@ -namespace Riter.Core; -//public enum HotKey -//{ -// Drawing = 9000, -// Erasing = 9001, -// HideAll = 9002, -// Trash = 9003, -// Undo = 9004, -// Redo = 9005, -// Highlighter = 9006, -// Release = 9007, -// SizeOfBrush1X = 9008, -// SizeOfBrush2X = 9009, -// SizeOfBrush3X = 9010, -// TransparentBackground = 9011, -// WhiteboardBackground = 9012, -// BlackboardBackground = 9013, +using System.Runtime.InteropServices; +using System.Text; -// Yellow = 9014, -// Purple = 9015, -// Mint = 9016, -// Coral = 9017, -// Red = 9018, -// Cyan = 9019, -// White = 9020, -// Orange = 9021, -// Gray = 9022, -// Black = 9023 -//} +namespace Riter.Core; +public enum HotKey +{ + Drawing = 9000, + Erasing = 9001, + HideAll = 9002, + Trash = 9003, + Undo = 9004, + Redo = 9005, + Highlighter = 9006, + Release = 9007, + SizeOfBrush1X = 9008, + SizeOfBrush2X = 9009, + SizeOfBrush3X = 9010, + TransparentBackground = 9011, + WhiteboardBackground = 9012, + BlackboardBackground = 9013, + Yellow = 9014, + Purple = 9015, + Mint = 9016, + Coral = 9017, + Red = 9018, + Cyan = 9019, + White = 9020, + Orange = 9021, + Gray = 9022, + Black = 9023 +} -public record struct HotKey(int Key, bool CtrlPressed, bool ShiftPressed); +public record struct HotKeiesPressed(string Key, bool CtrlPressed, bool ShiftPressed); diff --git a/src/Riter/Core/HotKey/HotKeysConfig.cs b/src/Riter/Core/HotKey/HotKeysConfig.cs index 5ec46fb..f652f5a 100644 --- a/src/Riter/Core/HotKey/HotKeysConfig.cs +++ b/src/Riter/Core/HotKey/HotKeysConfig.cs @@ -1,15 +1,15 @@ namespace Riter.Core; -public class Value -{ - public string Modifiers { get; init; } +//public class Value +//{ +// public string Modifiers { get; init; } - public string Key { get; init; } -} +// public string Key { get; init; } +//} public class HotKeysConfig { public string Key { get; init; } - public Value Value { get; init; } + public string Value { get; init; } } diff --git a/src/Riter/Core/HotKey/HotkeyLoader.cs b/src/Riter/Core/HotKey/HotkeyLoader.cs index 89c7c72..d2f445a 100644 --- a/src/Riter/Core/HotKey/HotkeyLoader.cs +++ b/src/Riter/Core/HotKey/HotkeyLoader.cs @@ -1,6 +1,6 @@ -using Riter.ViewModel; +//using Riter.ViewModel; -namespace Riter.Core; +//namespace Riter.Core; //public class HotKeyLoader(AppSettings options) //{ diff --git a/src/Riter/MainWindow.xaml.cs b/src/Riter/MainWindow.xaml.cs index 36277b5..0813f3a 100644 --- a/src/Riter/MainWindow.xaml.cs +++ b/src/Riter/MainWindow.xaml.cs @@ -101,7 +101,7 @@ private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) if (isKey) { - _orchestratorViewModel.HandleHotkey(new HotKey(vkCode, _ctrlPressed, _shiftPressed)); + _orchestratorViewModel.HandleHotkey(new HotKeiesPressed(KeyInterop.KeyFromVirtualKey(vkCode).ToString(), _ctrlPressed, _shiftPressed)); _ctrlPressed = false; _shiftPressed = false; } diff --git a/src/Riter/ViewModel/PaletteStateOrchestratorViewModel.cs b/src/Riter/ViewModel/PaletteStateOrchestratorViewModel.cs index 700c536..2aabe3a 100644 --- a/src/Riter/ViewModel/PaletteStateOrchestratorViewModel.cs +++ b/src/Riter/ViewModel/PaletteStateOrchestratorViewModel.cs @@ -50,88 +50,106 @@ public PaletteStateOrchestratorViewModel( public DrawingAttributes InkDrawingAttributes => DrawingAttributesFactory.CreateDrawingAttributes(BrushSettingsViewModel.InkColor, BrushSettingsViewModel.SizeOfBrush, HighlighterViewModel.IsHighlighter); - public void HandleHotkey(HotKey hotKey) + public void HandleHotkey(HotKeiesPressed hotKeies) { - // _appSettings.HotKeysConfig.FirstOrDefault() - //switch (hotKey) - //{ - // case HotKey.Drawing: - // DrawingViewModel.StartDrawingCommand.Execute(null); - // break; - // case HotKey.Erasing: - // DrawingViewModel.StartErasingCommand.Execute(null); - // break; - // case HotKey.Trash: - // StrokeHistoryViewModel.ClearCommand.Execute(null); - // break; - // case HotKey.Highlighter: - // DrawingViewModel.ToggleHighlighterCommand.Execute(null); - // break; - // case HotKey.Release: - // DrawingViewModel.ReleaseCommand.Execute(null); - // break; - // case HotKey.HideAll: - // StrokeVisibilityViewModel.HideAllCommand.Execute(null); - // break; - // case HotKey.Undo: - // StrokeHistoryViewModel.UndoCommand.Execute(null); - // break; - // case HotKey.Redo: - // StrokeHistoryViewModel.RedoCommand.Execute(null); - // break; - // case HotKey.SizeOfBrush1X: - // BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X1); - // break; - // case HotKey.SizeOfBrush2X: - // BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X2); - // break; - // case HotKey.SizeOfBrush3X: - // BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X3); - // break; - - // case HotKey.Yellow: - // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Yellow); - // break; - // case HotKey.Purple: - // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Purple); - // break; - // case HotKey.Mint: - // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Mint); - // break; - // case HotKey.Coral: - // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Coral); - // break; - // case HotKey.Red: - // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Red); - // break; - // case HotKey.Cyan: - // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Cyan); - // break; - // case HotKey.White: - // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.White); - // break; - // case HotKey.Orange: - // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Orange); - // break; - // case HotKey.Gray: - // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Gray); - // break; - // case HotKey.Black: - // BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Black); - // break; - - // case HotKey.TransparentBackground: - // InkEditingModeViewModel.EnableTransparentCommand.Execute(null); - // break; - // case HotKey.BlackboardBackground: - // InkEditingModeViewModel.EnableBlackboardCommand.Execute(null); - // break; - // case HotKey.WhiteboardBackground: - // InkEditingModeViewModel.EnableWhiteboardCommand.Execute(null); - // break; - // default: - // break; - //} + var keiesMap = string.Empty; + var keyString = hotKeies.Key.ToString(); + if (hotKeies.CtrlPressed) + { + keiesMap += "CTRL + "; + } + + if (hotKeies.ShiftPressed) + { + keiesMap += "SHIFT + "; + } + + keiesMap += keyString.ToUpper(); + var hotkey = _appSettings.HotKeysConfig.FirstOrDefault(x => x.Key == keiesMap); + if (hotkey is null) + { + return; + } + + switch (Enum.Parse(hotkey.Value)) + { + case HotKey.Drawing: + DrawingViewModel.StartDrawingCommand.Execute(null); + break; + case HotKey.Erasing: + DrawingViewModel.StartErasingCommand.Execute(null); + break; + case HotKey.Trash: + StrokeHistoryViewModel.ClearCommand.Execute(null); + break; + case HotKey.Highlighter: + DrawingViewModel.ToggleHighlighterCommand.Execute(null); + break; + case HotKey.Release: + DrawingViewModel.ReleaseCommand.Execute(null); + break; + case HotKey.HideAll: + StrokeVisibilityViewModel.HideAllCommand.Execute(null); + break; + case HotKey.Undo: + StrokeHistoryViewModel.UndoCommand.Execute(null); + break; + case HotKey.Redo: + StrokeHistoryViewModel.RedoCommand.Execute(null); + break; + case HotKey.SizeOfBrush1X: + BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X1); + break; + case HotKey.SizeOfBrush2X: + BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X2); + break; + case HotKey.SizeOfBrush3X: + BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X3); + break; + + case HotKey.Yellow: + BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Yellow); + break; + case HotKey.Purple: + BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Purple); + break; + case HotKey.Mint: + BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Mint); + break; + case HotKey.Coral: + BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Coral); + break; + case HotKey.Red: + BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Red); + break; + case HotKey.Cyan: + BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Cyan); + break; + case HotKey.White: + BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.White); + break; + case HotKey.Orange: + BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Orange); + break; + case HotKey.Gray: + BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Gray); + break; + case HotKey.Black: + BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Black); + break; + + case HotKey.TransparentBackground: + InkEditingModeViewModel.EnableTransparentCommand.Execute(null); + break; + case HotKey.BlackboardBackground: + InkEditingModeViewModel.EnableBlackboardCommand.Execute(null); + break; + case HotKey.WhiteboardBackground: + InkEditingModeViewModel.EnableWhiteboardCommand.Execute(null); + break; + default: + break; + } } private void OnBrushOrHighlightChanged(string propertyName) diff --git a/src/Riter/appsettings.json b/src/Riter/appsettings.json index 175e4a3..59978d5 100644 --- a/src/Riter/appsettings.json +++ b/src/Riter/appsettings.json @@ -2,172 +2,100 @@ "AppSettings": { "HotkeysConfig": [ { - "Key": "Drawing", - "Value": { - "Modifiers": "", - "Key": "D" - } + "Value": "Drawing", + "Key": "D" }, { - "Key": "Erasing", - "Value": { - "Modifiers": "", - "Key": "E" - } + "Value": "Erasing", + "Key": "E" }, { - "Key": "HideAll", - "Value": { - "Modifiers": "CTRL", - "Key": "H" - } + "Value": "HideAll", + "Key": "CTRL + H" }, { - "Key": "Trash", - "Value": { - "Modifiers": "CTRL", - "Key": "T" - } + "Value": "Trash", + "Key": "CTRL + T" }, { - "Key": "Undo", - "Value": { - "Modifiers": "", - "Key": "Z" - } + "Value": "Undo", + "Key": "Z" }, { - "Key": "Redo", - "Value": { - "Modifiers": "", - "Key": "X" - } + "Value": "Redo", + "Key": "X" }, { - "Key": "Highlighter", - "Value": { - "Modifiers": "", - "Key": "H" - } + "Value": "Highlighter", + "Key": "H" }, { - "Key": "Release", - "Value": { - "Modifiers": "", - "Key": "R" - } + "Value": "Release", + "Key": "R" }, { - "Key": "SizeOfBrush1X", - "Value": { - "Modifiers": "CTRL", - "Key": "1" - } + "Value": "SizeOfBrush1X", + "Key": "CTRL + 1" }, { - "Key": "SizeOfBrush2X", - "Value": { - "Modifiers": "CTRL", - "Key": "2" - } + "Value": "SizeOfBrush2X", + "Key": "CTRL + 2" }, { - "Key": "SizeOfBrush3X", - "Value": { - "Modifiers": "CTRL", - "Key": "3" - } + "Value": "SizeOfBrush3X", + "Key": "CTRL + 3" }, { - "Key": "TransparentBackground", - "Value": { - "Modifiers": "SHIFT", - "Key": "T" - } + "Value": "TransparentBackground", + "Key": "SHIFT + T" }, { - "Key": "WhiteboardBackground", - "Value": { - "Modifiers": "SHIFT", - "Key": "W" - } + "Value": "WhiteboardBackground", + "Key": "SHIFT + W" }, { - "Key": "BlackboardBackground", - "Value": { - "Modifiers": "SHIFT", - "Key": "B" - } + "Value": "BlackboardBackground", + "Key": "SHIFT + B" }, { - "Key": "Yellow", - "Value": { - "Modifiers": "ALT", - "Key": "1" - } + "Value": "Yellow", + "Key": "SHIFT + 1" }, { - "Key": "Purple", - "Value": { - "Modifiers": "ALT", - "Key": "2" - } + "Value": "Purple", + "Key": "SHIFT + 2" }, { - "Key": "Mint", - "Value": { - "Modifiers": "ALT", - "Key": "3" - } + "Value": "Mint", + "Key": "SHIFT + 3" }, { - "Key": "Coral", - "Value": { - "Modifiers": "ALT", - "Key": "4" - } + "Value": "Coral", + "Key": "SHIFT + 4" }, { - "Key": "Red", - "Value": { - "Modifiers": "ALT", - "Key": "5" - } + "Value": "Red", + "Key": "SHIFT + 5" }, { - "Key": "Cyan", - "Value": { - "Modifiers": "ALT", - "Key": "6" - } + "Value": "Cyan", + "Key": "SHIFT + 6" }, { - "Key": "White", - "Value": { - "Modifiers": "ALT", - "Key": "7" - } + "Value": "White", + "Key": "SHIFT + 7" }, { - "Key": "Orange", - "Value": { - "Modifiers": "ALT", - "Key": "8" - } + "Value": "Orange", + "Key": "SHIFT + 8" }, { - "Key": "Gray", - "Value": { - "Modifiers": "ALT", - "Key": "9" - } + "Value": "Gray", + "Key": "SHIFT + 9" }, { - "Key": "Black", - "Value": { - "Modifiers": "ALT", - "Key": "0" - } + "Value": "Black", + "Key": "SHIFT + 0" } ] } From ab08fdf274959ff467b9a2931c5b29bf0b205104 Mon Sep 17 00:00:00 2001 From: MohammadKarimi Date: Tue, 5 Nov 2024 02:10:41 +1100 Subject: [PATCH 5/6] remove hotkeyloader class. --- src/Riter/Core/HotKey/HotKeysConfig.cs | 7 ------ src/Riter/Core/HotKey/HotkeyLoader.cs | 35 -------------------------- 2 files changed, 42 deletions(-) delete mode 100644 src/Riter/Core/HotKey/HotkeyLoader.cs diff --git a/src/Riter/Core/HotKey/HotKeysConfig.cs b/src/Riter/Core/HotKey/HotKeysConfig.cs index f652f5a..2705f80 100644 --- a/src/Riter/Core/HotKey/HotKeysConfig.cs +++ b/src/Riter/Core/HotKey/HotKeysConfig.cs @@ -1,12 +1,5 @@ namespace Riter.Core; -//public class Value -//{ -// public string Modifiers { get; init; } - -// public string Key { get; init; } -//} - public class HotKeysConfig { public string Key { get; init; } diff --git a/src/Riter/Core/HotKey/HotkeyLoader.cs b/src/Riter/Core/HotKey/HotkeyLoader.cs deleted file mode 100644 index d2f445a..0000000 --- a/src/Riter/Core/HotKey/HotkeyLoader.cs +++ /dev/null @@ -1,35 +0,0 @@ -//using Riter.ViewModel; - -//namespace Riter.Core; - -//public class HotKeyLoader(AppSettings options) -//{ -// public const uint CTRL = 0x0002; -// public const uint SHIFT = 0x0004; -// public const uint ALT = 0x0001; - -// public Dictionary callback)> Loads(PaletteStateOrchestratorViewModel viewModel) -// { -// Dictionary callback)> hotkeys = []; -// foreach (var hotkey in options.HotKeysConfig) -// { -// var hotKey = System.Enum.Parse(hotkey.Key); -// var modifier = GetModifierKey(hotkey.Value.Modifiers); -// var key = GetKeyValue(hotkey.Value.Key); - -// hotkeys[hotKey] = (modifier, key, viewModel.HandleHotkey); -// } - -// return hotkeys; -// } - -// private static uint GetModifierKey(string modifier) => modifier switch -// { -// "CTRL" => CTRL, -// "SHIFT" => SHIFT, -// "ALT" => ALT, -// _ => 0 -// }; - -// private static uint GetKeyValue(string key) => key.ToUpper()[0]; -//} From a80d8e28ec2e1ec05cea7a8f17c7874e8a9299bd Mon Sep 17 00:00:00 2001 From: MohammadKarimi Date: Tue, 5 Nov 2024 22:02:56 +1100 Subject: [PATCH 6/6] Complete Manage HotKeys. --- src/Riter/Core/HotKey/KeyConverter.cs | 48 ++++++ src/Riter/MainWindow.xaml.cs | 1 + .../PaletteStateOrchestratorViewModel.cs | 138 +++++++----------- src/Riter/appsettings.json | 26 ++-- 4 files changed, 113 insertions(+), 100 deletions(-) create mode 100644 src/Riter/Core/HotKey/KeyConverter.cs diff --git a/src/Riter/Core/HotKey/KeyConverter.cs b/src/Riter/Core/HotKey/KeyConverter.cs new file mode 100644 index 0000000..ea1c40d --- /dev/null +++ b/src/Riter/Core/HotKey/KeyConverter.cs @@ -0,0 +1,48 @@ +using System.Runtime.InteropServices; +using System.Text; + +namespace Riter.Core; + +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Input; + +public static class KeyConverter +{ + [DllImport("user32.dll")] + private static extern int ToUnicode( + uint wVirtKey, + uint wScanCode, + byte[] lpKeyState, + [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszBuff, + int cchBuff, + uint wFlags); + + [DllImport("user32.dll")] + private static extern bool GetKeyboardState(byte[] lpKeyState); + + [DllImport("user32.dll")] + private static extern uint MapVirtualKey(uint uCode, uint uMapType); + + public static string VkCodeToString(int vkCode) + { + var keyState = new byte[256]; + if (!GetKeyboardState(keyState)) + { + return string.Empty; + } + + // Ensure the shift key state is set if necessary + if ((vkCode >= 'A' && vkCode <= 'Z') || (vkCode >= '0' && vkCode <= '9')) + { + keyState[(int)Key.LeftShift] = 0x80; + } + + var scanCode = MapVirtualKey((uint)vkCode, 0); + var sb = new StringBuilder(5); + int result = ToUnicode((uint)vkCode, scanCode, keyState, sb, sb.Capacity, 0); + + return result > 0 ? sb.ToString() : string.Empty; + } +} diff --git a/src/Riter/MainWindow.xaml.cs b/src/Riter/MainWindow.xaml.cs index 0813f3a..6eb07ba 100644 --- a/src/Riter/MainWindow.xaml.cs +++ b/src/Riter/MainWindow.xaml.cs @@ -2,6 +2,7 @@ using System.Runtime.InteropServices; using System.Windows.Controls; using System.Windows.Ink; +using System.Windows.Input; using Riter.Core.Extensions; using Riter.Core.Interfaces; using Riter.Core.UI; diff --git a/src/Riter/ViewModel/PaletteStateOrchestratorViewModel.cs b/src/Riter/ViewModel/PaletteStateOrchestratorViewModel.cs index 2aabe3a..d147b3a 100644 --- a/src/Riter/ViewModel/PaletteStateOrchestratorViewModel.cs +++ b/src/Riter/ViewModel/PaletteStateOrchestratorViewModel.cs @@ -6,6 +6,7 @@ namespace Riter.ViewModel; public class PaletteStateOrchestratorViewModel : BaseViewModel { private readonly AppSettings _appSettings; + private readonly Dictionary _hotKeyCommandMap = []; public PaletteStateOrchestratorViewModel( DrawingViewModel drawingViewModel, @@ -28,6 +29,34 @@ public PaletteStateOrchestratorViewModel( SettingPanelViewModel = settingPanelViewModel; ButtonSelectedViewModel = buttonSelectedViewModel; + _hotKeyCommandMap = new() + { + { HotKey.Drawing, () => DrawingViewModel.StartDrawingCommand.Execute(null) }, + { HotKey.Erasing, () => DrawingViewModel.StartErasingCommand.Execute(null) }, + { HotKey.Trash, () => StrokeHistoryViewModel.ClearCommand.Execute(null) }, + { HotKey.Highlighter, () => DrawingViewModel.ToggleHighlighterCommand.Execute(null) }, + { HotKey.Release, () => DrawingViewModel.ReleaseCommand.Execute(null) }, + { HotKey.HideAll, () => StrokeVisibilityViewModel.HideAllCommand.Execute(null) }, + { HotKey.Undo, () => StrokeHistoryViewModel.UndoCommand.Execute(null) }, + { HotKey.Redo, () => StrokeHistoryViewModel.RedoCommand.Execute(null) }, + { HotKey.SizeOfBrush1X, () => BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X1) }, + { HotKey.SizeOfBrush2X, () => BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X2) }, + { HotKey.SizeOfBrush3X, () => BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X3) }, + { HotKey.Yellow, () => BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Yellow) }, + { HotKey.Purple, () => BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Purple) }, + { HotKey.Mint, () => BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Mint) }, + { HotKey.Coral, () => BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Coral) }, + { HotKey.Red, () => BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Red) }, + { HotKey.Cyan, () => BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Cyan) }, + { HotKey.White, () => BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.White) }, + { HotKey.Orange, () => BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Orange) }, + { HotKey.Gray, () => BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Gray) }, + { HotKey.Black, () => BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Black) }, + { HotKey.TransparentBackground, () => InkEditingModeViewModel.EnableTransparentCommand.Execute(null) }, + { HotKey.BlackboardBackground, () => InkEditingModeViewModel.EnableBlackboardCommand.Execute(null) }, + { HotKey.WhiteboardBackground, () => InkEditingModeViewModel.EnableWhiteboardCommand.Execute(null) }, + }; + BrushSettingsViewModel.PropertyChanged += (_, e) => OnBrushOrHighlightChanged(e.PropertyName); HighlighterViewModel.PropertyChanged += (_, e) => OnBrushOrHighlightChanged(e.PropertyName); } @@ -52,104 +81,39 @@ public PaletteStateOrchestratorViewModel( public void HandleHotkey(HotKeiesPressed hotKeies) { - var keiesMap = string.Empty; - var keyString = hotKeies.Key.ToString(); - if (hotKeies.CtrlPressed) + var keiesMap = BuildKeyCombination(hotKeies); + var hotkey = _appSettings.HotKeysConfig.FirstOrDefault(x => x.Key == keiesMap); + if (hotkey is null) { - keiesMap += "CTRL + "; + return; } - if (hotKeies.ShiftPressed) + if (!Enum.TryParse(hotkey.Value, out var hotKeyEnum)) { - keiesMap += "SHIFT + "; + return; } - keiesMap += keyString.ToUpper(); - var hotkey = _appSettings.HotKeysConfig.FirstOrDefault(x => x.Key == keiesMap); - if (hotkey is null) + if (_hotKeyCommandMap.TryGetValue(hotKeyEnum, out var command)) { - return; + command(); + } + } + + private static string BuildKeyCombination(HotKeiesPressed hotKeies) + { + var keiesMap = string.Empty; + if (hotKeies.CtrlPressed) + { + keiesMap += "CTRL + "; } - switch (Enum.Parse(hotkey.Value)) + if (hotKeies.ShiftPressed) { - case HotKey.Drawing: - DrawingViewModel.StartDrawingCommand.Execute(null); - break; - case HotKey.Erasing: - DrawingViewModel.StartErasingCommand.Execute(null); - break; - case HotKey.Trash: - StrokeHistoryViewModel.ClearCommand.Execute(null); - break; - case HotKey.Highlighter: - DrawingViewModel.ToggleHighlighterCommand.Execute(null); - break; - case HotKey.Release: - DrawingViewModel.ReleaseCommand.Execute(null); - break; - case HotKey.HideAll: - StrokeVisibilityViewModel.HideAllCommand.Execute(null); - break; - case HotKey.Undo: - StrokeHistoryViewModel.UndoCommand.Execute(null); - break; - case HotKey.Redo: - StrokeHistoryViewModel.RedoCommand.Execute(null); - break; - case HotKey.SizeOfBrush1X: - BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X1); - break; - case HotKey.SizeOfBrush2X: - BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X2); - break; - case HotKey.SizeOfBrush3X: - BrushSettingsViewModel.SetSizeOfBrushWithHotKeyCommand.Execute(BrushSize.X3); - break; - - case HotKey.Yellow: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Yellow); - break; - case HotKey.Purple: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Purple); - break; - case HotKey.Mint: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Mint); - break; - case HotKey.Coral: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Coral); - break; - case HotKey.Red: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Red); - break; - case HotKey.Cyan: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Cyan); - break; - case HotKey.White: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.White); - break; - case HotKey.Orange: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Orange); - break; - case HotKey.Gray: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Gray); - break; - case HotKey.Black: - BrushSettingsViewModel.SetInkColorWithHotKeyCommand.Execute(InkColor.Black); - break; - - case HotKey.TransparentBackground: - InkEditingModeViewModel.EnableTransparentCommand.Execute(null); - break; - case HotKey.BlackboardBackground: - InkEditingModeViewModel.EnableBlackboardCommand.Execute(null); - break; - case HotKey.WhiteboardBackground: - InkEditingModeViewModel.EnableWhiteboardCommand.Execute(null); - break; - default: - break; + keiesMap += "SHIFT + "; } + + keiesMap += hotKeies.Key.ToString().ToUpper(); + return keiesMap; } private void OnBrushOrHighlightChanged(string propertyName) diff --git a/src/Riter/appsettings.json b/src/Riter/appsettings.json index 59978d5..a752c17 100644 --- a/src/Riter/appsettings.json +++ b/src/Riter/appsettings.json @@ -35,15 +35,15 @@ }, { "Value": "SizeOfBrush1X", - "Key": "CTRL + 1" + "Key": "CTRL + D1" }, { "Value": "SizeOfBrush2X", - "Key": "CTRL + 2" + "Key": "CTRL + D2" }, { "Value": "SizeOfBrush3X", - "Key": "CTRL + 3" + "Key": "CTRL + D3" }, { "Value": "TransparentBackground", @@ -59,43 +59,43 @@ }, { "Value": "Yellow", - "Key": "SHIFT + 1" + "Key": "D1" }, { "Value": "Purple", - "Key": "SHIFT + 2" + "Key": "D2" }, { "Value": "Mint", - "Key": "SHIFT + 3" + "Key": "D3" }, { "Value": "Coral", - "Key": "SHIFT + 4" + "Key": "D4" }, { "Value": "Red", - "Key": "SHIFT + 5" + "Key": "D5" }, { "Value": "Cyan", - "Key": "SHIFT + 6" + "Key": "D6" }, { "Value": "White", - "Key": "SHIFT + 7" + "Key": "D7" }, { "Value": "Orange", - "Key": "SHIFT + 8" + "Key": "D8" }, { "Value": "Gray", - "Key": "SHIFT + 9" + "Key": "D9" }, { "Value": "Black", - "Key": "SHIFT + 0" + "Key": "D0" } ] }