-
-
Notifications
You must be signed in to change notification settings - Fork 344
/
Copy pathGlobalHotkey.cs
127 lines (114 loc) · 4.25 KB
/
GlobalHotkey.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Flow.Launcher.Plugin;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.Input.KeyboardAndMouse;
using Windows.Win32.UI.WindowsAndMessaging;
namespace Flow.Launcher.Infrastructure.Hotkey
{
/// <summary>
/// Listens keyboard globally.
/// <remarks>Uses WH_KEYBOARD_LL.</remarks>
/// </summary>
public unsafe class GlobalHotkey : IDisposable
{
private static readonly HOOKPROC _procKeyboard = HookKeyboardCallback;
private static readonly UnhookWindowsHookExSafeHandle hookId;
public delegate bool KeyboardCallback(KeyEvent keyEvent, int vkCode, SpecialKeyState state);
internal static Func<KeyEvent, int, SpecialKeyState, bool> hookedKeyboardCallback;
static GlobalHotkey()
{
// Set the hook
hookId = SetHook(_procKeyboard, WINDOWS_HOOK_ID.WH_KEYBOARD_LL);
}
private static UnhookWindowsHookExSafeHandle SetHook(HOOKPROC proc, WINDOWS_HOOK_ID hookId)
{
using var curProcess = Process.GetCurrentProcess();
using var curModule = curProcess.MainModule;
return PInvoke.SetWindowsHookEx(hookId, proc, PInvoke.GetModuleHandle(curModule.ModuleName), 0);
}
public static SpecialKeyState CheckModifiers()
{
SpecialKeyState state = new SpecialKeyState();
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_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_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_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;
}
return state;
}
private static LRESULT HookKeyboardCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
bool continues = true;
if (nCode >= 0)
{
if (wParam.Value == (int)KeyEvent.WM_KEYDOWN ||
wParam.Value == (int)KeyEvent.WM_KEYUP ||
wParam.Value == (int)KeyEvent.WM_SYSKEYDOWN ||
wParam.Value == (int)KeyEvent.WM_SYSKEYUP)
{
if (hookedKeyboardCallback != null)
continues = hookedKeyboardCallback((KeyEvent)wParam.Value, Marshal.ReadInt32(lParam), CheckModifiers());
}
}
if (continues)
{
return PInvoke.CallNextHookEx(hookId, nCode, wParam, lParam);
}
return new LRESULT(1);
}
public void Dispose()
{
hookId.Dispose();
}
~GlobalHotkey()
{
Dispose();
}
}
}