From be796fd899a59a264ff5d9cbb437f07685cb2779 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Thu, 2 Jan 2025 20:08:41 +1100 Subject: [PATCH] use string for WPFControl & HotkeyModel with left right key accuracy --- .../Hotkey/GlobalHotkey.cs | 38 +++- .../Hotkey/HotkeyModel.cs | 196 +++++++++++------- Flow.Launcher.Plugin/ActionContext.cs | 8 + Flow.Launcher/HotkeyControl.xaml.cs | 4 +- Flow.Launcher/HotkeyControlDialog.xaml.cs | 31 +-- 5 files changed, 173 insertions(+), 104 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs index b2a140755..1d1eee6ea 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs @@ -37,25 +37,53 @@ namespace Flow.Launcher.Infrastructure.Hotkey public static SpecialKeyState CheckModifiers() { SpecialKeyState state = new SpecialKeyState(); - if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_SHIFT) & 0x8000) != 0) + if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_LSHIFT) & 0x8000) != 0) { //SHIFT is pressed + state.LeftShiftPressed = true; state.ShiftPressed = true; } - if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_CONTROL) & 0x8000) != 0) + if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_RSHIFT) & 0x8000) != 0) + { + //SHIFT is pressed + state.RightShiftPressed = true; + state.ShiftPressed = true; + } + + if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_LCONTROL) & 0x8000) != 0) { //CONTROL is pressed + state.LeftCtrlPressed = true; state.CtrlPressed = true; } - if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_MENU) & 0x8000) != 0) + if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_RCONTROL) & 0x8000) != 0) + { + //CONTROL is pressed + state.RightCtrlPressed = true; + state.CtrlPressed = true; + } + if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_LMENU) & 0x8000) != 0) { //ALT is pressed + state.LeftAltPressed = true; state.AltPressed = true; } - if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_LWIN) & 0x8000) != 0 || - (PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_RWIN) & 0x8000) != 0) + if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_RMENU) & 0x8000) != 0) + { + //ALT is pressed + state.RightAltPressed = true; + state.AltPressed = true; + } + if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_LWIN) & 0x8000) != 0) { //WIN is pressed + state.LWinPressed = true; + state.WinPressed = true; + } + if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_RWIN) & 0x8000) != 0) + { + //WIN is pressed + state.RWinPressed = true; state.WinPressed = true; } diff --git a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs index 82b53d951..b2f6ee719 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs @@ -9,10 +9,14 @@ namespace Flow.Launcher.Infrastructure.Hotkey { public record struct HotkeyModel { - public bool Alt { get; set; } - public bool Shift { get; set; } - public bool Win { get; set; } - public bool Ctrl { get; set; } + public bool LeftAlt { get; set; } + public bool LeftShift { get; set; } + public bool LWin { get; set; } + public bool LeftCtrl { get; set; } + public bool RightAlt { get; set; } + public bool RightShift { get; set; } + public bool RWin { get; set; } + public bool RightCtrl { get; set; } public string HotkeyRaw { get; set; } = string.Empty; public string PreviousHotkey { get; set; } = string.Empty; @@ -29,22 +33,22 @@ namespace Flow.Launcher.Infrastructure.Hotkey get { ModifierKeys modifierKeys = ModifierKeys.None; - if (Alt) + if (LeftAlt || RightAlt) { modifierKeys |= ModifierKeys.Alt; } - if (Shift) + if (LeftShift || RightShift) { modifierKeys |= ModifierKeys.Shift; } - if (Win) + if (LWin || RWin) { modifierKeys |= ModifierKeys.Windows; } - if (Ctrl) + if (LeftCtrl || RightCtrl) { modifierKeys |= ModifierKeys.Control; } @@ -58,17 +62,21 @@ namespace Flow.Launcher.Infrastructure.Hotkey { Clear(); Parse(hotkeyString); - HotkeyRaw = ToChefKeysString(); + HotkeyRaw = FromWPFKeysToString(); } internal void SetHotkeyFromWPFControl(SpecialKeyState specialKeyState, Key key) { - Alt = specialKeyState.AltPressed; - Shift = specialKeyState.ShiftPressed; - Win = specialKeyState.WinPressed; - Ctrl = specialKeyState.CtrlPressed; + LeftAlt = specialKeyState.LeftAltPressed; + LeftShift = specialKeyState.LeftShiftPressed; + LWin = specialKeyState.LWinPressed; + LeftCtrl = specialKeyState.LeftCtrlPressed; + RightAlt = specialKeyState.RightAltPressed; + RightShift = specialKeyState.RightShiftPressed; + RWin = specialKeyState.RWinPressed; + RightCtrl = specialKeyState.RightCtrlPressed; CharKey = key; - HotkeyRaw = ToChefKeysString(); + HotkeyRaw = FromWPFKeysToString(); PreviousHotkey = string.Empty; } @@ -77,31 +85,25 @@ namespace Flow.Launcher.Infrastructure.Hotkey SetHotkeyFromString(hotkey); } - //public HotkeyModel(bool alt, bool shift, bool win, bool ctrl, Key key) - //{ - // Alt = alt; - // Shift = shift; - // Win = win; - // Ctrl = ctrl; - // CharKey = key; - //} - // Use for ChefKeys only internal void AddString(string key) { HotkeyRaw = string.IsNullOrEmpty(HotkeyRaw) ? key : HotkeyRaw + "+" + key; + Parse(HotkeyRaw); } - internal string GetLastKeySet() => !string.IsNullOrEmpty(HotkeyRaw) ? HotkeyRaw.Split('+').Last() : string.Empty; - - internal bool MaxKeysReached() => DisplayKeysRaw().Count() == 4; + internal string GetLastKeySet() => !string.IsNullOrEmpty(HotkeyRaw) ? HotkeyRaw.Split('+').Last() : string.Empty; internal void Clear() { - Alt = false; - Shift = false; - Win = false; - Ctrl = false; + LeftAlt = false; + LeftShift = false; + LWin = false; + LeftCtrl = false; + RightAlt = false; + RightShift = false; + RWin = false; + RightCtrl = false; HotkeyRaw = string.Empty; PreviousHotkey = string.Empty; CharKey = Key.None; @@ -114,36 +116,52 @@ namespace Flow.Launcher.Infrastructure.Hotkey return; } - List keys = hotkeyString.Replace(" ", "").Split('+').ToList(); - if (keys.Contains("Alt") || keys.Contains("LeftAlt") || keys.Contains("RightAlt")) + List keys = hotkeyString.Split('+', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList(); + if (keys.Contains("Alt") || keys.Contains("LeftAlt")) { - Alt = true; + LeftAlt = true; keys.Remove("Alt"); keys.Remove("LeftAlt"); + } + if (keys.Contains("RightAlt")) + { + RightAlt = true; keys.Remove("RightAlt"); } - if (keys.Contains("Shift") || keys.Contains("LeftShift") || keys.Contains("RightShift")) + if (keys.Contains("Shift") || keys.Contains("LeftShift")) { - Shift = true; + LeftShift = true; keys.Remove("Shift"); keys.Remove("LeftShift"); + } + if (keys.Contains("RightShift")) + { + RightShift = true; keys.Remove("RightShift"); } - if (keys.Contains("Win") || keys.Contains("LWin") || keys.Contains("RWin")) + if (keys.Contains("Win") || keys.Contains("LWin")) { - Win = true; + LWin = true; keys.Remove("Win"); keys.Remove("LWin"); + } + if (keys.Contains("RWin")) + { + RWin = true; keys.Remove("RWin"); } - if (keys.Contains("Ctrl") || keys.Contains("LeftCtrl")|| keys.Contains("RightCtrl")) + if (keys.Contains("Ctrl") || keys.Contains("LeftCtrl")) { - Ctrl = true; + LeftCtrl = true; keys.Remove("Ctrl"); keys.Remove("LeftCtrl"); + } + if (keys.Contains("RightCtrl")) + { + RightCtrl = true; keys.Remove("RightCtrl"); } @@ -169,62 +187,90 @@ namespace Flow.Launcher.Infrastructure.Hotkey } } - public string ToChefKeysString() + public readonly string ToWPFHotkeyString() { - var key = string.Join("+", EnumerateDisplayKeys(true)); - - return key; + var hotkey = string.Empty; + + foreach (var key in HotkeyRaw.Split('+')) + { + if (!string.IsNullOrEmpty(hotkey)) + hotkey += " + "; + + switch (key) + { + case "LeftCtrl" or "RightCtrl": + hotkey += "Ctrl"; + break; + case "LeftAlt" or "RightAlt": + hotkey += "Alt"; + break; + case "LeftShift" or "RightShift": + hotkey += "Shift"; + break; + case "LWin" or "RWin": + hotkey += "Win"; + break; + + default: + hotkey += key; + break; + } + } + + return hotkey; } - public IEnumerable DisplayKeysRaw() => !string.IsNullOrEmpty(HotkeyRaw) ? HotkeyRaw.Split('+') : Array.Empty(); + public IEnumerable EnumerateDisplayKeys() => !string.IsNullOrEmpty(HotkeyRaw) ? HotkeyRaw.Split('+') : Array.Empty(); - public IEnumerable EnumerateDisplayKeys(bool forChefKeys = false) + //For WPF hotkey control + public string FromWPFKeysToString() => string.Join("+", EnumerateWPFKeys()); + + public IEnumerable EnumerateWPFKeys() { - if (Ctrl && CharKey is not (Key.LeftCtrl or Key.RightCtrl)) + if (LeftCtrl && CharKey is not Key.LeftCtrl) { - yield return GetKeyString("Ctrl", forChefKeys); + yield return "LeftCtrl"; } - if (Alt && CharKey is not (Key.LeftAlt or Key.RightAlt)) + if (LeftAlt && CharKey is not Key.LeftAlt) { - yield return GetKeyString("Alt", forChefKeys); + yield return "LeftAlt"; } - if (Shift && CharKey is not (Key.LeftShift or Key.RightShift)) + if (LeftShift && CharKey is not Key.LeftShift) { - yield return GetKeyString("Shift", forChefKeys); + yield return "LeftShift"; } - if (Win && CharKey is not (Key.LWin or Key.RWin)) + if (LWin && CharKey is not Key.LWin) { - yield return GetKeyString("Win", forChefKeys); + yield return "LWin"; + } + if (RightCtrl && CharKey is not Key.RightCtrl) + { + yield return "RightCtrl"; + } + + if (RightAlt && CharKey is not Key.RightAlt) + { + yield return "RightAlt"; + } + + if (RightShift && CharKey is not Key.RightShift) + { + yield return "RightShift"; + } + + if (RWin && CharKey is not Key.RWin) + { + yield return "RWin"; } if (CharKey != Key.None) { yield return specialSymbolDictionary.TryGetValue(CharKey, out var value) ? value - : GetKeyString(CharKey.ToString(), forChefKeys); - } - } - - private string GetKeyString(string key, bool convertToChefKeysString) - { - if (!convertToChefKeysString) - return key; - - switch (key) - { - case "Alt": - return "LeftAlt"; - case "Ctrl": - return "LeftCtrl"; - case "Shift": - return "LeftShift"; - case "Win": - return "LWin"; - default: - return key; + : CharKey.ToString(); } } @@ -235,6 +281,8 @@ namespace Flow.Launcher.Infrastructure.Hotkey /// public bool ValidateForWpf(bool validateKeyGestrue = false) { + Parse(HotkeyRaw); + switch (CharKey) { case Key.LeftAlt: diff --git a/Flow.Launcher.Plugin/ActionContext.cs b/Flow.Launcher.Plugin/ActionContext.cs index e31c8e31d..a38907a9d 100644 --- a/Flow.Launcher.Plugin/ActionContext.cs +++ b/Flow.Launcher.Plugin/ActionContext.cs @@ -38,6 +38,14 @@ namespace Flow.Launcher.Plugin /// True if the Windows key is pressed. /// public bool WinPressed { get; set; } + public bool LeftShiftPressed { get; set; } + public bool RightShiftPressed { get; set; } + public bool LeftCtrlPressed { get; set; } + public bool RightCtrlPressed { get; set; } + public bool LeftAltPressed { get; set; } + public bool RightAltPressed { get; set; } + public bool LWinPressed { get; set; } + public bool RWinPressed { get; set; } /// /// Get this object represented as a flag combination. diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs index 9f1c8761e..cff597955 100644 --- a/Flow.Launcher/HotkeyControl.xaml.cs +++ b/Flow.Launcher/HotkeyControl.xaml.cs @@ -182,7 +182,7 @@ namespace Flow.Launcher if (!hotkeyAvailable) return; - Hotkey = keyModel.HotkeyRaw; + Hotkey = keyModel.ToWPFHotkeyString(); SetKeysToDisplay(CurrentHotkey); // If exists then will be unregistered, if doesn't no errors will be thrown. @@ -193,7 +193,7 @@ namespace Flow.Launcher } else { - Hotkey = keyModel.HotkeyRaw; + Hotkey = keyModel.ToWPFHotkeyString(); ChangeHotkey?.Execute(keyModel); } } diff --git a/Flow.Launcher/HotkeyControlDialog.xaml.cs b/Flow.Launcher/HotkeyControlDialog.xaml.cs index d5146fcf5..e4a2d8cad 100644 --- a/Flow.Launcher/HotkeyControlDialog.xaml.cs +++ b/Flow.Launcher/HotkeyControlDialog.xaml.cs @@ -144,17 +144,10 @@ public partial class HotkeyControlDialog : ContentDialog if (HotkeyToUpdate.GetLastKeySet() == key.ToString()) return; - if (!isWPFHotkeyControl) - { - if (HotkeyToUpdate.MaxKeysReached()) - return; + if (MaxKeysLimitReached()) + return; - HotkeyToUpdate.AddString(key.ToString()); - } - else - { - HotkeyToUpdate.SetHotkeyFromWPFControl(GlobalHotkey.CheckModifiers(), key); - } + HotkeyToUpdate.AddString(key.ToString()); } private void SetKeysToDisplay(HotkeyModel? hotkey) @@ -170,19 +163,9 @@ public partial class HotkeyControlDialog : ContentDialog IEnumerable enumerateMethod; - if (!isWPFHotkeyControl) + foreach (var key in hotkey.Value.EnumerateDisplayKeys()!) { - foreach (var key in hotkey.Value.DisplayKeysRaw()!) - { - KeysToDisplay.Add(key); - } - } - else - { - foreach (var key in hotkey.Value.EnumerateDisplayKeys()!) - { - KeysToDisplay.Add(key); - } + KeysToDisplay.Add(key); } if (tbMsg == null) @@ -190,7 +173,7 @@ public partial class HotkeyControlDialog : ContentDialog if (_hotkeySettings.RegisteredHotkeys .FirstOrDefault(v => v.Hotkey == hotkey - || v.Hotkey.ToChefKeysString() == hotkey.Value.HotkeyRaw) + || v.Hotkey.FromWPFKeysToString() == hotkey.Value.HotkeyRaw) is { } registeredHotkeyData) { var description = string.Format( @@ -253,6 +236,8 @@ public partial class HotkeyControlDialog : ContentDialog private static bool CheckWPFHotkeyAvailability(HotkeyModel hotkey, bool validateKeyGesture) => hotkey.ValidateForWpf(validateKeyGesture) && HotKeyMapper.CheckHotkeyAvailability(hotkey.HotkeyRaw); + private bool MaxKeysLimitReached() => isWPFHotkeyControl ? KeysToDisplay.Count == 2 : KeysToDisplay.Count == 4; + private void Overwrite(object sender, RoutedEventArgs e) { _overwriteOtherHotkey?.Invoke();