From 1c60b8e586c54d2a3e6969fd1815bcb0ae3dc857 Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Sat, 27 Nov 2021 13:50:22 -0600 Subject: [PATCH] Use Function Pointer to handle the low level keyboard proc --- .../Hotkey/GlobalHotkey.cs | 41 ++++++------------- .../Hotkey/InterceptKeys.cs | 6 +-- Flow.Launcher/HotkeyControl.xaml.cs | 2 +- Flow.Launcher/PublicAPIInstance.cs | 2 +- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- 5 files changed, 18 insertions(+), 35 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs index e92a93c12..3ea8915f7 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs @@ -9,13 +9,14 @@ namespace Flow.Launcher.Infrastructure.Hotkey /// Listens keyboard globally. /// Uses WH_KEYBOARD_LL. /// - public class GlobalHotkey : IDisposable + public unsafe static class GlobalHotkey { - private static GlobalHotkey instance; - private InterceptKeys.LowLevelKeyboardProc hookedLowLevelKeyboardProc; - private IntPtr hookId = IntPtr.Zero; + private static readonly IntPtr hookId; + + + public delegate bool KeyboardCallback(KeyEvent keyEvent, int vkCode, SpecialKeyState state); - public event KeyboardCallback hookedKeyboardCallback; + internal static Func hookedKeyboardCallback; //Modifier key constants private const int VK_SHIFT = 0x10; @@ -23,27 +24,14 @@ namespace Flow.Launcher.Infrastructure.Hotkey private const int VK_ALT = 0x12; private const int VK_WIN = 91; - public static GlobalHotkey Instance + static GlobalHotkey() { - get - { - if (instance == null) - { - instance = new GlobalHotkey(); - } - return instance; - } - } - - private GlobalHotkey() - { - // We have to store the LowLevelKeyboardProc, so that it is not garbage collected runtime - hookedLowLevelKeyboardProc = LowLevelKeyboardProc; // Set the hook - hookId = InterceptKeys.SetHook(hookedLowLevelKeyboardProc); + hookId = InterceptKeys.SetHook(& LowLevelKeyboardProc); + AppDomain.CurrentDomain.ProcessExit += (_, _) => Dispose(); } - public SpecialKeyState CheckModifiers() + public static SpecialKeyState CheckModifiers() { SpecialKeyState state = new SpecialKeyState(); if ((InterceptKeys.GetKeyState(VK_SHIFT) & 0x8000) != 0) @@ -71,7 +59,7 @@ namespace Flow.Launcher.Infrastructure.Hotkey } [MethodImpl(MethodImplOptions.NoInlining)] - private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam) + private static IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam) { bool continues = true; @@ -94,12 +82,7 @@ namespace Flow.Launcher.Infrastructure.Hotkey return (IntPtr)1; } - ~GlobalHotkey() - { - Dispose(); - } - - public void Dispose() + public static void Dispose() { InterceptKeys.UnhookWindowsHookEx(hookId); } diff --git a/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs b/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs index c45e685f3..7fec3c383 100644 --- a/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs +++ b/Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs @@ -4,13 +4,13 @@ using System.Runtime.InteropServices; namespace Flow.Launcher.Infrastructure.Hotkey { - internal static class InterceptKeys + internal static unsafe class InterceptKeys { public delegate IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam); private const int WH_KEYBOARD_LL = 13; - public static IntPtr SetHook(LowLevelKeyboardProc proc) + public static IntPtr SetHook(delegate* proc) { using (Process curProcess = Process.GetCurrentProcess()) using (ProcessModule curModule = curProcess.MainModule) @@ -20,7 +20,7 @@ namespace Flow.Launcher.Infrastructure.Hotkey } [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId); + public static extern IntPtr SetWindowsHookEx(int idHook, delegate* lpfn, IntPtr hMod, uint dwThreadId); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs index 2b6e275df..a20537e3a 100644 --- a/Flow.Launcher/HotkeyControl.xaml.cs +++ b/Flow.Launcher/HotkeyControl.xaml.cs @@ -33,7 +33,7 @@ namespace Flow.Launcher //when alt is pressed, the real key should be e.SystemKey Key key = (e.Key == Key.System ? e.SystemKey : e.Key); - SpecialKeyState specialKeyState = GlobalHotkey.Instance.CheckModifiers(); + SpecialKeyState specialKeyState = GlobalHotkey.CheckModifiers(); var hotkeyModel = new HotkeyModel( specialKeyState.AltPressed, diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index e90a53fc3..562db43f1 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -40,7 +40,7 @@ namespace Flow.Launcher _settingsVM = settingsVM; _mainVM = mainVM; _alphabet = alphabet; - GlobalHotkey.Instance.hookedKeyboardCallback += KListener_hookedKeyboardCallback; + GlobalHotkey.hookedKeyboardCallback += KListener_hookedKeyboardCallback; WebRequest.RegisterPrefix("data", new DataWebRequestFactory()); } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index d7bbaf1cd..9d6b124a0 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -227,7 +227,7 @@ namespace Flow.Launcher.ViewModel { bool hideWindow = result.Action != null && result.Action(new ActionContext { - SpecialKeyState = GlobalHotkey.Instance.CheckModifiers() + SpecialKeyState = GlobalHotkey.CheckModifiers() }); if (hideWindow)