はじめに
グローバルキーフックのためのクラスを作成したので、忘備録として残しておきます。
インスタンスを生成し「KeyBoardHook」を呼び出してから「KeyBoardUnHook」を呼び出すまでグローバルキーフックの検出を行います。
グローバルキーフックを検出した後、独自イベント「KeyHookDownEvent」(キー押下時)と「KeyHookUpEvent」(キー離上時)にイベントを発生させます。
コード
using System; using System.Diagnostics; using System.Runtime.InteropServices; /// <summary> /// グローバルキーフックイベントを実装するクラス /// </summary> public class Common_KeyBoardHook { #region Const private protected const int WH_KEYBOARD_LL = 0x000D; private protected const int HC_ACTION = 0; private protected const int WM_KEYDOWN = 0x0100; private protected const int WM_KEYUP = 0x0101; private protected const int WM_SYSKEYDOWN = 0x0104; private protected const int WM_SYSKEYUP = 0x0105; [Flags] private enum KBDLLHOOKSTRUCTFlags : uint { LLKHF_EXTENDED = 0x01, LLKHF_INJECTED = 0x10, LLKHF_ALTDOWN = 0x20, LLKHF_UP = 0x80 } [StructLayout(LayoutKind.Sequential)] private class KBDLLHOOKSTRUCT { public uint vkCode; public uint scanCode; public KBDLLHOOKSTRUCTFlags flags; public uint time; public UIntPtr dwExtraInfo; } public enum HookKeyCode : int { VK_LBUTTON = 0x01, VK_RBUTTON, VK_CANCEL, VK_MBUTTON, VK_XBUTTON1, VK_XBUTTON2, VK_BACK = 0x08, VK_TAB, VK_CLEAR = 0x0C, VK_RETURN, VK_SHIFT = 0x10, VK_CONTROL, VK_MENU, VK_PAUSE, VK_CAPITAL, VK_KANA, VK_JUNJA = 0x17, VK_FINAL, VK_KANJI, VK_ESCAPE = 0x1B, VK_CONVERT, VK_NONCONVERT, VK_ACCEPT, VK_MODECHANGE, VK_SPACE, VK_PRIOR, VK_NEXT, VK_END, VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_SELECT, VK_PRINT, VK_EXECUTE, VK_SNAPSHOT, VK_INSERT, VK_DELETE, VK_HELP, VK_0, VK_1, VK_2, VK_3, VK_4, VK_5, VK_6, VK_7, VK_8, VK_9, VK_A = 0x41, VK_B, VK_C, VK_D, VK_E, VK_F, VK_G, VK_H, VK_I, VK_J, VK_K, VK_L, VK_M, VK_N, VK_O, VK_P, VK_Q, VK_R, VK_S, VK_T, VK_U, VK_V, VK_W, VK_X, VK_Y, VK_Z, VK_LWIN, VK_RWIN, VK_APPS, VK_SLEEP = 0x5F, VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, VK_NUMPAD8, VK_NUMPAD9, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE, VK_F1, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, VK_NUMLOCK = 0x90, VK_SCROLL, VK_LSHIFT = 0xA0, VK_RSHIFT, VK_LCONTROL, VK_RCONTROL, VK_LMENU, VK_RMENU, VK_BROWSER_BACK, VK_BROWSER_FORWARD, VK_BROWSER_REFRESH, VK_BROWSER_STOP, VK_BROWSER_SEARCH, VK_BROWSER_FAVORITES, VK_BROWSER_HOME, VK_VOLUME_MUTE, VK_VOLUME_DOWN, VK_VOLUME_UP, VK_MEDIA_NEXT_TRACK, VK_MEDIA_PREV_TRACK, VK_MEDIA_STOP, VK_MEDIA_PLAY_PAUSE, VK_LAUNCH_MAIL, VK_LAUNCH_MEDIA_SELECT, VK_LAUNCH_APP1, VK_LAUNCH_APP2, VK_OEM_1 = 0xBA, VK_OEM_PLUS, VK_OEM_COMMA, VK_OEM_MINUS, VK_OEM_PERIOD, VK_OEM_2, VK_OEM_3, VK_OEM_4 = 0xDB, VK_OEM_5, VK_OEM_6, VK_OEM_7, VK_OEM_8, VK_OEM_102 = 0xE2, VK_PROCESSKEY = 0xE5, VK_PACKET = 0xE7, VK_ATTN = 0xF6, VK_CRSEL, VK_EXSEL, VK_EREOF, VK_PLAY, VK_ZOOM, VK_NONAME, VK_PA1, VK_OEM_CLEAR } #endregion #region Private private delegate IntPtr KeyBoardHookProc(int nCode, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr SetWindowsHookEx(int idHook, KeyBoardHookProc lpfn, IntPtr hMod, uint dwThreadId); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool UnhookWindowsHookEx(IntPtr hhk); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr GetModuleHandle(string lpModuleName); private IntPtr HookPtr = IntPtr.Zero; private KeyBoardHookProc? HookProc; private protected void OnKeyHookDownEvent(int KeyCode) { KeyHookDownEvent?.Invoke(this, new(KeyCode)); } private protected void OnKeyHookUpEvent(int KeyCode) { KeyHookUpEvent?.Invoke(this, new(KeyCode)); } private IntPtr HookCallBack(int nCode, IntPtr wParam, IntPtr lParam) { IntPtr NextHookPtr = CallNextHookEx(HookPtr, nCode, wParam, lParam); //例外処理 if (nCode < HC_ACTION) { return NextHookPtr; } //キーコードの取得 object? PtrStructure = Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT)); if (PtrStructure == null) { return NextHookPtr; } KBDLLHOOKSTRUCT KeyHookStruct = (KBDLLHOOKSTRUCT)PtrStructure; int KeyCode = (int)KeyHookStruct.vkCode; //キーダウンイベント if (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN) { OnKeyHookDownEvent(KeyCode); } //キーアップイベント else if (wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP) { OnKeyHookUpEvent(KeyCode); } return NextHookPtr; } #endregion #region Public /// <summary> /// キーボードフックを設定する /// </summary> /// <returns>設定の是非(T/F)</returns> public bool KeyBoardHook() { Process CurrentProcess = Process.GetCurrentProcess(); ProcessModule? CurrentModule = CurrentProcess.MainModule; if (CurrentModule == null) { return false; } string? NameModule = CurrentModule.ModuleName; if (NameModule == null) { return false; } HookProc = HookCallBack; HookPtr = SetWindowsHookEx(WH_KEYBOARD_LL, HookProc, GetModuleHandle(NameModule), 0); return true; } /// <summary> /// キーボードフックを解除する /// </summary> /// <returns>解除の是非</returns> public bool KeyBoardUnHook() { bool RetUnhook = UnhookWindowsHookEx(HookPtr); HookPtr = IntPtr.Zero; return RetUnhook; } /// <summary> /// キーボードフックイベント /// </summary> /// <param name="sender">KBDLLHOOKSTRUCT構造へのポインタ</param> /// <param name="e">キーフックイベント</param> public delegate void KeyHookEventHandler(object sender, KeyHookEventArgs e); public event KeyHookEventHandler? KeyHookDownEvent; public event KeyHookEventHandler? KeyHookUpEvent; #endregion } /// <summary> /// キーフックイベント /// </summary> public class KeyHookEventArgs : EventArgs { public int KeyCode { get; } public KeyHookEventArgs(int InputKeyCode) { KeyCode = InputKeyCode; } }
使い方
参考程度に。
//WPF OnStartUp等の開始処理内に記載 KeyBoardHook.KeyHookDownEvent += KeyHookDown; KeyBoardHook.KeyHookUpEvent += KeyHookUp; _ = KeyBoardHook.KeyBoardHook();
void KeyHookDown(object sender, KeyHookEventArgs e){//キー押下時の処理} void KeyHookUp(object sender, KeyHookEventArgs e){//キー離上時の処理}
//WPF OnExit等の終了処理内に記載 _ = KeyBoardHook.KeyBoardUnHook();
コメント