Skip to content

Commit 1c60b8e

Browse files
committed
Use Function Pointer to handle the low level keyboard proc
1 parent b51e5d2 commit 1c60b8e

File tree

5 files changed

+18
-35
lines changed

5 files changed

+18
-35
lines changed

Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,41 +9,29 @@ namespace Flow.Launcher.Infrastructure.Hotkey
99
/// Listens keyboard globally.
1010
/// <remarks>Uses WH_KEYBOARD_LL.</remarks>
1111
/// </summary>
12-
public class GlobalHotkey : IDisposable
12+
public unsafe static class GlobalHotkey
1313
{
14-
private static GlobalHotkey instance;
15-
private InterceptKeys.LowLevelKeyboardProc hookedLowLevelKeyboardProc;
16-
private IntPtr hookId = IntPtr.Zero;
14+
private static readonly IntPtr hookId;
15+
16+
17+
1718
public delegate bool KeyboardCallback(KeyEvent keyEvent, int vkCode, SpecialKeyState state);
18-
public event KeyboardCallback hookedKeyboardCallback;
19+
internal static Func<KeyEvent, int, SpecialKeyState, bool> hookedKeyboardCallback;
1920

2021
//Modifier key constants
2122
private const int VK_SHIFT = 0x10;
2223
private const int VK_CONTROL = 0x11;
2324
private const int VK_ALT = 0x12;
2425
private const int VK_WIN = 91;
2526

26-
public static GlobalHotkey Instance
27+
static GlobalHotkey()
2728
{
28-
get
29-
{
30-
if (instance == null)
31-
{
32-
instance = new GlobalHotkey();
33-
}
34-
return instance;
35-
}
36-
}
37-
38-
private GlobalHotkey()
39-
{
40-
// We have to store the LowLevelKeyboardProc, so that it is not garbage collected runtime
41-
hookedLowLevelKeyboardProc = LowLevelKeyboardProc;
4229
// Set the hook
43-
hookId = InterceptKeys.SetHook(hookedLowLevelKeyboardProc);
30+
hookId = InterceptKeys.SetHook(& LowLevelKeyboardProc);
31+
AppDomain.CurrentDomain.ProcessExit += (_, _) => Dispose();
4432
}
4533

46-
public SpecialKeyState CheckModifiers()
34+
public static SpecialKeyState CheckModifiers()
4735
{
4836
SpecialKeyState state = new SpecialKeyState();
4937
if ((InterceptKeys.GetKeyState(VK_SHIFT) & 0x8000) != 0)
@@ -71,7 +59,7 @@ public SpecialKeyState CheckModifiers()
7159
}
7260

7361
[MethodImpl(MethodImplOptions.NoInlining)]
74-
private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam)
62+
private static IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam)
7563
{
7664
bool continues = true;
7765

@@ -94,12 +82,7 @@ private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam)
9482
return (IntPtr)1;
9583
}
9684

97-
~GlobalHotkey()
98-
{
99-
Dispose();
100-
}
101-
102-
public void Dispose()
85+
public static void Dispose()
10386
{
10487
InterceptKeys.UnhookWindowsHookEx(hookId);
10588
}

Flow.Launcher.Infrastructure/Hotkey/InterceptKeys.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44

55
namespace Flow.Launcher.Infrastructure.Hotkey
66
{
7-
internal static class InterceptKeys
7+
internal static unsafe class InterceptKeys
88
{
99
public delegate IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam);
1010

1111
private const int WH_KEYBOARD_LL = 13;
1212

13-
public static IntPtr SetHook(LowLevelKeyboardProc proc)
13+
public static IntPtr SetHook(delegate*<int, UIntPtr, IntPtr, IntPtr> proc)
1414
{
1515
using (Process curProcess = Process.GetCurrentProcess())
1616
using (ProcessModule curModule = curProcess.MainModule)
@@ -20,7 +20,7 @@ public static IntPtr SetHook(LowLevelKeyboardProc proc)
2020
}
2121

2222
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
23-
public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
23+
public static extern IntPtr SetWindowsHookEx(int idHook, delegate*<int, UIntPtr, IntPtr, IntPtr> lpfn, IntPtr hMod, uint dwThreadId);
2424

2525
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
2626
[return: MarshalAs(UnmanagedType.Bool)]

Flow.Launcher/HotkeyControl.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ void TbHotkey_OnPreviewKeyDown(object sender, KeyEventArgs e)
3333
//when alt is pressed, the real key should be e.SystemKey
3434
Key key = (e.Key == Key.System ? e.SystemKey : e.Key);
3535

36-
SpecialKeyState specialKeyState = GlobalHotkey.Instance.CheckModifiers();
36+
SpecialKeyState specialKeyState = GlobalHotkey.CheckModifiers();
3737

3838
var hotkeyModel = new HotkeyModel(
3939
specialKeyState.AltPressed,

Flow.Launcher/PublicAPIInstance.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public PublicAPIInstance(SettingWindowViewModel settingsVM, MainViewModel mainVM
4040
_settingsVM = settingsVM;
4141
_mainVM = mainVM;
4242
_alphabet = alphabet;
43-
GlobalHotkey.Instance.hookedKeyboardCallback += KListener_hookedKeyboardCallback;
43+
GlobalHotkey.hookedKeyboardCallback += KListener_hookedKeyboardCallback;
4444
WebRequest.RegisterPrefix("data", new DataWebRequestFactory());
4545
}
4646

Flow.Launcher/ViewModel/MainViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ private void InitializeKeyCommands()
227227
{
228228
bool hideWindow = result.Action != null && result.Action(new ActionContext
229229
{
230-
SpecialKeyState = GlobalHotkey.Instance.CheckModifiers()
230+
SpecialKeyState = GlobalHotkey.CheckModifiers()
231231
});
232232

233233
if (hideWindow)

0 commit comments

Comments
 (0)