diff --git a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs index a091856969b..30a77f79969 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs @@ -12,9 +12,9 @@ namespace Flow.Launcher.Infrastructure.Hotkey public unsafe class GlobalHotkey : IDisposable { private static readonly IntPtr hookId; - - - + + + public delegate bool KeyboardCallback(KeyEvent keyEvent, int vkCode, SpecialKeyState state); internal static Func hookedKeyboardCallback; @@ -27,12 +27,15 @@ public unsafe class GlobalHotkey : IDisposable static GlobalHotkey() { // Set the hook - hookId = InterceptKeys.SetHook(& LowLevelKeyboardProc); + hookId = InterceptKeys.SetHook(&LowLevelKeyboardProc); } public static SpecialKeyState CheckModifiers() { SpecialKeyState state = new SpecialKeyState(); + + + if ((InterceptKeys.GetKeyState(VK_SHIFT) & 0x8000) != 0) { //SHIFT is pressed diff --git a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs index 5bd97714c15..0a7737fb719 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/HotkeyModel.cs @@ -31,15 +31,15 @@ public ModifierKeys ModifierKeys } if (Shift) { - modifierKeys = modifierKeys | ModifierKeys.Shift; + modifierKeys |= ModifierKeys.Shift; } if (Win) { - modifierKeys = modifierKeys | ModifierKeys.Windows; + modifierKeys |= ModifierKeys.Windows; } if (Ctrl) { - modifierKeys = modifierKeys | ModifierKeys.Control; + modifierKeys |= ModifierKeys.Control; } return modifierKeys; } diff --git a/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs b/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs index d33bac34cea..737394bae4f 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs @@ -34,5 +34,8 @@ public static IntPtr SetHook(delegate* unmanaged p [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] public static extern short GetKeyState(int keyCode); + + [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + public static extern short GetAsyncKeyState(int keyCode); } } \ No newline at end of file diff --git a/Flow.Launcher/HotkeyControl.xaml b/Flow.Launcher/HotkeyControl.xaml index 9b5f671d8f5..5bc6cbbc8dc 100644 --- a/Flow.Launcher/HotkeyControl.xaml +++ b/Flow.Launcher/HotkeyControl.xaml @@ -49,7 +49,6 @@ Margin="0,0,18,0" VerticalContentAlignment="Center" input:InputMethod.IsInputMethodEnabled="False" - PreviewKeyDown="TbHotkey_OnPreviewKeyDown" TabIndex="100" LostFocus="tbHotkey_LostFocus"/> diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs index bc437d8628b..86c54293d7a 100644 --- a/Flow.Launcher/HotkeyControl.xaml.cs +++ b/Flow.Launcher/HotkeyControl.xaml.cs @@ -9,6 +9,8 @@ using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Plugin; using System.Threading; +using Flow.Launcher.Core.Plugin; +using Flow.Launcher.Infrastructure.Logger; namespace Flow.Launcher { @@ -25,41 +27,97 @@ public partial class HotkeyControl : UserControl protected virtual void OnHotkeyChanged() => HotkeyChanged?.Invoke(this, EventArgs.Empty); + private Func callback { get; set; } + public HotkeyControl() { InitializeComponent(); tbMsgTextOriginal = tbMsg.Text; tbMsgForegroundColorOriginal = tbMsg.Foreground; + + callback = TbHotkey_OnPreviewKeyDown; + + GotFocus += (_, _) => + { + PluginManager.API.RegisterGlobalKeyboardCallback(callback); + }; + LostFocus += (_, _) => + { + PluginManager.API.RemoveGlobalKeyboardCallback(callback); + state.AltPressed = false; + state.CtrlPressed = false; + state.ShiftPressed = false; + state.WinPressed = false; + }; } private CancellationTokenSource hotkeyUpdateSource; - private void TbHotkey_OnPreviewKeyDown(object sender, KeyEventArgs e) + private SpecialKeyState state = new(); + + private bool TbHotkey_OnPreviewKeyDown(int keyevent, int vkcode, SpecialKeyState dummy) { + var key = KeyInterop.KeyFromVirtualKey(vkcode); + + if ((KeyEvent)keyevent is not (KeyEvent.WM_KEYDOWN or KeyEvent.WM_SYSKEYDOWN)) + { + switch (key) + { + case Key.LeftAlt or Key.RightAlt: + state.AltPressed = false; + break; + case Key.LeftCtrl or Key.RightCtrl: + state.CtrlPressed = false; + break; + case Key.LeftShift or Key.RightShift: + state.ShiftPressed = false; + break; + case Key.LWin or Key.LWin: + state.WinPressed = false; + break; + default: + break; + } + return true; + } + + switch (key) + { + case Key.LeftAlt or Key.RightAlt: + state.AltPressed = true; + break; + case Key.LeftCtrl or Key.RightCtrl: + state.CtrlPressed = true; + break; + case Key.LeftShift or Key.RightShift: + state.ShiftPressed = true; + break; + case Key.LWin or Key.LWin: + state.WinPressed = true; + break; + } + + hotkeyUpdateSource?.Cancel(); hotkeyUpdateSource?.Dispose(); hotkeyUpdateSource = new(); var token = hotkeyUpdateSource.Token; - e.Handled = true; - //when alt is pressed, the real key should be e.SystemKey - Key key = e.Key == Key.System ? e.SystemKey : e.Key; - - SpecialKeyState specialKeyState = GlobalHotkey.CheckModifiers(); var hotkeyModel = new HotkeyModel( - specialKeyState.AltPressed, - specialKeyState.ShiftPressed, - specialKeyState.WinPressed, - specialKeyState.CtrlPressed, + state.AltPressed, + state.ShiftPressed, + state.WinPressed, + state.CtrlPressed, key); var hotkeyString = hotkeyModel.ToString(); if (hotkeyString == tbHotkey.Text) { - return; + return false; } + Log.Debug("test hotkey" + hotkeyString); _ = Dispatcher.InvokeAsync(async () => { @@ -67,6 +125,8 @@ private void TbHotkey_OnPreviewKeyDown(object sender, KeyEventArgs e) if (!token.IsCancellationRequested) await SetHotkey(hotkeyModel); }); + + return false; } public async Task SetHotkey(HotkeyModel keyModel, bool triggerValidate = true) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 2b9d830002b..beb2ce981b5 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -106,6 +106,8 @@ Hotkey Flow Launcher Hotkey Enter shortcut to show/hide Flow Launcher. + Recommended Hotkeys + List of recommended hotkeys. Open Result Modifier Key Select a modifier key to open selected result via keyboard. Show Hotkey diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index e15d5285cd0..52be01c02f5 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -1998,11 +1998,8 @@ - - - - + - - - - - - - + + + + + + + + + - -  - - - - + +  + + + - - - - - - + + + + + + + - - - - - + FontSize="14"> + + + + + + - - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - -