From 0ac2f0132170a6a65ca315591c8261f703595a84 Mon Sep 17 00:00:00 2001 From: tux Date: Sat, 5 Jul 2025 19:38:16 +0530 Subject: [PATCH] fix: keybindings trigger --- ui/windows/MainWindow.axaml.cs | 87 ++++++++---------- utils/KeyBindings.cs | 161 +++++++++++++++++++++++++++++++++ 2 files changed, 200 insertions(+), 48 deletions(-) create mode 100644 utils/KeyBindings.cs diff --git a/ui/windows/MainWindow.axaml.cs b/ui/windows/MainWindow.axaml.cs index ba42260..5fde0d1 100644 --- a/ui/windows/MainWindow.axaml.cs +++ b/ui/windows/MainWindow.axaml.cs @@ -7,8 +7,8 @@ using Avalonia.Media; using Avalonia.Threading; using highminded.ui.controls; using highminded.utils; -using SharpHook; using SharpHook.Data; +using KeyBinding = highminded.utils.KeyBinding; namespace highminded.ui.windows; @@ -32,7 +32,7 @@ public partial class MainWindow : Window private readonly SettingsUserControl _settingsUserControl = new SettingsUserControl(); // Hotkey - private readonly TaskPoolGlobalHook _hook = new TaskPoolGlobalHook(); + private readonly PreciseKeyBindings _keyBindings = new PreciseKeyBindings(); public MainWindow() { @@ -42,9 +42,7 @@ public partial class MainWindow : Window UControl.Content = _chatUserControl; ChatBtnActive(); HideOverlay(); - // Global Hotkey - _hook.KeyPressed += OnKeyPressed; - _hook.RunAsync(); + RegisterKeyBindings(); } private void OnPointerPressed(object? sender, PointerPressedEventArgs e) @@ -141,50 +139,21 @@ public partial class MainWindow : Window Hide(); } - private void OnKeyPressed(object? sender, KeyboardHookEventArgs e) + private void RegisterKeyBindings() { - bool hasCtrl = (e.RawEvent.Mask & EventMask.Ctrl) != EventMask.None; - bool hasAlt = (e.RawEvent.Mask & EventMask.Alt) != EventMask.None; - bool hasShift = (e.RawEvent.Mask & EventMask.Shift) != EventMask.None; - bool hasH = e.Data.KeyCode == KeyCode.VcH; - bool hasBackslash = e.Data.KeyCode == KeyCode.VcBackslash; - bool hasA = e.Data.KeyCode == KeyCode.VcA; - bool hasS = e.Data.KeyCode == KeyCode.VcS; - bool hasQ = e.Data.KeyCode == KeyCode.VcQ; + _keyBindings.AddKeyBinding( + new KeyBinding(KeyCode.VcH, ModifierKey.Control, ModifierKey.Alt, ModifierKey.Shift), + () => Dispatcher.UIThread.Post(ShowOverlay) + ); - if (hasCtrl && hasShift && hasAlt && hasH) - { - ShowOverlay(); - } + _keyBindings.AddKeyBinding( + new KeyBinding(KeyCode.VcQ, ModifierKey.Alt, ModifierKey.Shift), + () => Dispatcher.UIThread.Post(() => Environment.Exit(0)) + ); - if (hasAlt && hasShift && hasS) - { - Dispatcher.UIThread.Post(() => { _chatUserControl.SendScreenshot(); }); - } - - if (hasAlt && hasShift && hasA) - { - Dispatcher.UIThread.Post(() => - { - if (!InMemoryDb.Obj.MainViewModel.IsRecording) - { - _chatUserControl.StartRecord(); - } - else - { - _chatUserControl.StopRecord(); - } - }); - } - - if (hasAlt && hasShift && hasQ) - { - Dispatcher.UIThread.Post(() => { Environment.Exit(0); }); - } - - if (hasAlt && hasShift && hasBackslash) - { - Dispatcher.UIThread.Post(() => + _keyBindings.AddKeyBinding( + new KeyBinding(KeyCode.VcBackslash, ModifierKey.Alt, ModifierKey.Shift), + () => Dispatcher.UIThread.Post(() => { if (WindowState == WindowState.Minimized || !IsVisible) { @@ -197,7 +166,29 @@ public partial class MainWindow : Window { Hide(); } - }); - } + }) + ); + + _keyBindings.AddKeyBinding( + new KeyBinding(KeyCode.VcA, ModifierKey.Alt, ModifierKey.Shift), + () => Dispatcher.UIThread.Post(() => + { + if (!InMemoryDb.Obj.MainViewModel.IsRecording) + { + _chatUserControl.StartRecord(); + } + else + { + _chatUserControl.StopRecord(); + } + }) + ); + + _keyBindings.AddKeyBinding( + new KeyBinding(KeyCode.VcS, ModifierKey.Alt, ModifierKey.Shift), + () => Dispatcher.UIThread.Post(() => _chatUserControl.SendScreenshot()) + ); + + _keyBindings.Start(); } } \ No newline at end of file diff --git a/utils/KeyBindings.cs b/utils/KeyBindings.cs new file mode 100644 index 0000000..1591c88 --- /dev/null +++ b/utils/KeyBindings.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections.Generic; +using SharpHook; +using SharpHook.Data; + +namespace highminded.utils; + +public enum ModifierKey +{ + Control, + Shift, + Alt, + Meta +} + +public class PreciseKeyBindings +{ + private readonly IGlobalHook _hook; + private readonly Dictionary _keyBindings; + private readonly HashSet _pressedKeys; + + public PreciseKeyBindings() + { + _hook = new TaskPoolGlobalHook(); + _keyBindings = new Dictionary(); + _pressedKeys = new HashSet(); + + // Subscribe to key events + _hook.KeyPressed += OnKeyPressed; + _hook.KeyReleased += OnKeyReleased; + } + + public void AddKeyBinding(KeyBinding binding, Action action) + { + _keyBindings[binding] = action; + } + + public void Start() + { + _hook.RunAsync(); + } + + public void Stop() + { + _hook.Dispose(); + } + + private void OnKeyPressed(object? sender, KeyboardHookEventArgs e) + { + _pressedKeys.Add(e.Data.KeyCode); + + // Check if any key binding matches the current pressed keys + foreach (var kvp in _keyBindings) + { + if (IsExactMatch(kvp.Key)) + { + kvp.Value.Invoke(); + break; // Only trigger the first match + } + } + } + + private void OnKeyReleased(object? sender, KeyboardHookEventArgs e) + { + _pressedKeys.Remove(e.Data.KeyCode); + } + + private bool IsExactMatch(KeyBinding binding) + { + // Get currently pressed modifiers + var pressedModifiers = GetPressedModifiers(); + + // Check if the main key is pressed + if (!_pressedKeys.Contains(binding.Key)) + return false; + + // Check if modifiers match exactly + if (pressedModifiers.Count != binding.Modifiers.Count) + return false; + + foreach (var modifier in binding.Modifiers) + { + if (!pressedModifiers.Contains(modifier)) + return false; + } + + return true; + } + + private HashSet GetPressedModifiers() + { + var modifiers = new HashSet(); + + // Check for Control + if (_pressedKeys.Contains(KeyCode.VcLeftControl) || _pressedKeys.Contains(KeyCode.VcRightControl)) + modifiers.Add(ModifierKey.Control); + + // Check for Shift + if (_pressedKeys.Contains(KeyCode.VcLeftShift) || _pressedKeys.Contains(KeyCode.VcRightShift)) + modifiers.Add(ModifierKey.Shift); + + // Check for Alt + if (_pressedKeys.Contains(KeyCode.VcLeftAlt) || _pressedKeys.Contains(KeyCode.VcRightAlt)) + modifiers.Add(ModifierKey.Alt); + + // Check for Meta/Windows key + if (_pressedKeys.Contains(KeyCode.VcLeftMeta) || _pressedKeys.Contains(KeyCode.VcRightMeta)) + modifiers.Add(ModifierKey.Meta); + + return modifiers; + } +} + +public class KeyBinding : IEquatable +{ + public KeyCode Key { get; } + public HashSet Modifiers { get; } + + public KeyBinding(KeyCode key, params ModifierKey[] modifiers) + { + Key = key; + Modifiers = new HashSet(modifiers); + } + + public override bool Equals(object? obj) + { + return Equals(obj as KeyBinding); + } + + public bool Equals(KeyBinding? other) + { + if (other == null) return false; + if (Key != other.Key) return false; + if (Modifiers.Count != other.Modifiers.Count) return false; + + foreach (var modifier in Modifiers) + { + if (!other.Modifiers.Contains(modifier)) + return false; + } + + return true; + } + + public override int GetHashCode() + { + int hash = Key.GetHashCode(); + foreach (var modifier in Modifiers) + { + hash ^= modifier.GetHashCode(); + } + + return hash; + } + + public override string ToString() + { + var modStr = string.Join(" + ", Modifiers); + return string.IsNullOrEmpty(modStr) ? Key.ToString() : $"{modStr} + {Key}"; + } +} \ No newline at end of file