Flow.Launcher/Flow.Launcher.Infrastructure/Hotkey/GlobalHotkey.cs

100 lines
3.2 KiB
C#
Raw Permalink Normal View History

2024-12-10 12:44:28 +00:00
using System;
using System.Diagnostics;
2014-03-18 16:26:09 +00:00
using System.Runtime.InteropServices;
2020-04-21 09:12:17 +00:00
using Flow.Launcher.Plugin;
2024-12-10 12:44:28 +00:00
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.Input.KeyboardAndMouse;
using Windows.Win32.UI.WindowsAndMessaging;
2014-03-18 16:26:09 +00:00
2020-04-21 09:12:17 +00:00
namespace Flow.Launcher.Infrastructure.Hotkey
2014-03-18 16:26:09 +00:00
{
/// <summary>
/// Listens keyboard globally.
/// <remarks>Uses WH_KEYBOARD_LL.</remarks>
/// </summary>
2021-12-06 00:22:41 +00:00
public unsafe class GlobalHotkey : IDisposable
2014-03-18 16:26:09 +00:00
{
2024-12-11 01:57:13 +00:00
private static readonly HOOKPROC _procKeyboard = HookKeyboardCallback;
2024-12-10 12:44:28 +00:00
private static readonly UnhookWindowsHookExSafeHandle hookId;
2014-03-18 16:26:09 +00:00
2024-12-11 01:57:13 +00:00
public delegate bool KeyboardCallback(KeyEvent keyEvent, int vkCode, SpecialKeyState state);
2024-12-10 12:44:28 +00:00
internal static Func<KeyEvent, int, SpecialKeyState, bool> hookedKeyboardCallback;
2014-03-18 16:26:09 +00:00
static GlobalHotkey()
{
2014-03-18 16:26:09 +00:00
// Set the hook
2024-12-11 01:57:13 +00:00
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);
2014-03-18 16:26:09 +00:00
}
public static SpecialKeyState CheckModifiers()
2014-03-18 16:26:09 +00:00
{
SpecialKeyState state = new SpecialKeyState();
2024-12-10 12:44:28 +00:00
if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_SHIFT) & 0x8000) != 0)
2014-03-18 16:26:09 +00:00
{
//SHIFT is pressed
state.ShiftPressed = true;
}
2024-12-10 12:44:28 +00:00
if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_CONTROL) & 0x8000) != 0)
2014-03-18 16:26:09 +00:00
{
//CONTROL is pressed
state.CtrlPressed = true;
}
2024-12-10 12:44:28 +00:00
if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_MENU) & 0x8000) != 0)
2014-03-18 16:26:09 +00:00
{
//ALT is pressed
state.AltPressed = true;
}
2024-12-11 01:57:49 +00:00
if ((PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_LWIN) & 0x8000) != 0 ||
(PInvoke.GetKeyState((int)VIRTUAL_KEY.VK_RWIN) & 0x8000) != 0)
2014-03-18 16:26:09 +00:00
{
2016-01-22 12:47:00 +00:00
//WIN is pressed
2014-03-18 16:26:09 +00:00
state.WinPressed = true;
}
return state;
}
2024-12-11 01:57:13 +00:00
private static LRESULT HookKeyboardCallback(int nCode, WPARAM wParam, LPARAM lParam)
2014-03-18 16:26:09 +00:00
{
bool continues = true;
if (nCode >= 0)
{
2024-12-11 01:57:13 +00:00
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)
2014-03-18 16:26:09 +00:00
{
if (hookedKeyboardCallback != null)
2024-12-11 01:57:13 +00:00
continues = hookedKeyboardCallback((KeyEvent)wParam.Value, Marshal.ReadInt32(lParam), CheckModifiers());
2014-03-18 16:26:09 +00:00
}
}
if (continues)
{
2024-12-10 12:44:28 +00:00
return PInvoke.CallNextHookEx(hookId, nCode, wParam, lParam);
2014-03-18 16:26:09 +00:00
}
2024-12-11 01:57:13 +00:00
return new LRESULT(1);
2014-03-18 16:26:09 +00:00
}
2021-12-06 00:22:41 +00:00
public void Dispose()
2014-03-18 16:26:09 +00:00
{
hookId.Dispose();
2014-03-18 16:26:09 +00:00
}
2021-12-06 00:22:41 +00:00
~GlobalHotkey()
{
Dispose();
}
2014-03-18 16:26:09 +00:00
}
2024-12-10 12:44:28 +00:00
}