鍵盤鉤子在64位系統中運行

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms; 

namespace  Hook
{
  public class Hook : IDisposable
  {
    public delegate int HookProc(WH_CODE nCode, Int32 wParam, IntPtr lParam);
    #region 常數和結構

    public const int WM_KEYDOWN = 0x100;

    public const int WM_KEYUP = 0x101;

    public const int WM_SYSKEYDOWN = 0x104;

    public const int WM_SYSKEYUP = 0x105;

    public const int WH_KEYBOARD_LL = 13;
    #endregion
    public enum WH_CODE : int
    {
      WH_JOURNALRECORD = 0,
      WH_JOURNALPLAYBACK = 1,
      /// <summary>
      /// 進程鉤子
      /// {系統級或線程級; 截獲鍵盤消息}
      /// </summary>
      WH_KEYBOARD = 2,
      /// <summary>
      /// 底層鍵盤鉤子 全局鉤子就是用這個
      /// </summary>
      WH_KEYBOARD_LL = 13,
    }

    public enum HC_CODE : int
    {
      HC_ACTION = 0,
      HC_GETNEXT = 1,
      HC_SKIP = 2,
      HC_NOREMOVE = 3,
      HC_NOREM = 3,
      HC_SYSMODALON = 4,
      HC_SYSMODALOFF = 5
    }
    [StructLayout(LayoutKind.Sequential)]
    public class KeyboardHookStruct
    {
      public int vkCode;  //定一個虛擬鍵碼。該代碼必須有一個價值的範圍1至254
      public int scanCode; // 指定的硬件掃描碼的關鍵
      public int flags;  // 鍵標誌
      public int time; // 指定的時間戳記的這個訊息
      public int dwExtraInfo; // 指定額外信息相關的信息
    }

    /// <summary>
    /// 安裝鉤子
    /// </summary>
    [DllImport("user32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    public static extern IntPtr SetWindowsHookEx(WH_CODE idHook, HookProc lpfn, IntPtr pInstance, uint threadId);

    /// <summary>
    /// 卸載鉤子
    /// </summary>
    [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
    public static extern bool UnhookWindowsHookEx(IntPtr pHookHandle);
    /// <summary>
    /// 傳遞鉤子
    /// </summary>
    [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
    public static extern int CallNextHookEx(IntPtr pHookHandle, WH_CODE nCodem, Int32 wParam, IntPtr lParam);

    /// <summary>
    /// 獲取全部按鍵狀態
    /// </summary>
    /// <param name="pbKeyState"></param>
    /// <returns>非0表示成功</returns>
    [DllImport("user32.dll")]
    public static extern int GetKeyboardState(byte[] pbKeyState);

    /// <summary>
    /// 獲取程序集模塊的句柄
    /// </summary>
    /// <param name="lpModuleName"></param>
    /// <returns></returns>
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr GetModuleHandle(string lpModuleName);

    /// <summary>
    /// 獲取當前進程中的當前線程ID
    /// </summary>
    /// <returns></returns>
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern uint GetCurrentThreadId();

    #region 私有變量

    private byte[] mKeyState = new byte[256];
    private Keys mKeyData = Keys.None; //專門用於判斷按鍵的狀態

    /// <summary>
    /// 鍵盤鉤子句柄
    /// </summary>
    private IntPtr mKetboardHook = IntPtr.Zero;

    /// <summary>
    /// 鍵盤鉤子委託實例
    /// </summary>
    private HookProc mKeyboardHookProcedure;

    #endregion

 
 
    /// <summary>
    /// 構造函數
    /// </summary>
    public Hook()
    {
      GetKeyboardState(this.mKeyState);
    }

    ~Hook()
    {
      Dispose();
    }
    bool KeyDown = true;
    public bool Ekey = false;
    public bool Rkey = false;

    /// <summary>
    /// 鍵盤鉤子處理函數
    /// </summary>
    private int KeyboardHookProcNew(WH_CODE nCode, Int32 wParam, IntPtr lParam)
    {
      /*全局鉤子應該這樣設定
       KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
      */
      // 定義爲線程鉤子時,wParam的值是擊打的按鍵,與Keys裏的對應按鍵相同
      if ((int)nCode == (int)HC_CODE.HC_NOREMOVE)
      {
        if (FormStatus)
        {
          mKeyData = (Keys)wParam;
          KeyEventArgs keyEvent = new KeyEventArgs(mKeyData);
          if (KeyDown && lParam.ToInt64() > 0)
          {
            //這裏簡單的通過lParam的值的正負情況與按鍵的狀態相關聯
            if (mKeyData == Keys.Space && lParam.ToInt64() > 0)
            {
              this.OnSpaceKeyDown();
            }
          }
        }
      }
      return CallNextHookEx(this.mKetboardHook, nCode, wParam, lParam);
    }
    #region 事件的聲明
    // public event KeyEventHandler KeyDownEvent;

    private static readonly object _eventKeyDown = new object();
    private EventHandlerList _events;
    protected EventHandlerList Events => _events ??= new EventHandlerList();
    [Category("Property Changed")]
    public event KeyEventHandler KeyDownEvent
    {
      add { this.Events.AddHandler(_eventKeyDown, value); }
      remove { this.Events.RemoveHandler(_eventKeyDown, value); }
    }
    #endregion
    /// <summary>
    /// 鍵盤鉤子處理函數
    /// </summary>
    private int KeyboardHookProc(WH_CODE nCode, Int32 wParam, IntPtr lParam)
    {
      /*全局鉤子應該這樣設定
       KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
      */
      // 定義爲線程鉤子時,wParam的值是擊打的按鍵,與Keys裏的對應按鍵相同
      if ((int)nCode == (int)HC_CODE.HC_NOREMOVE)
      {
        if (FormStatus)
        {
          //  Debug.WriteLine($"{nCode} {(Keys)wParam} {lParam} ");
          mKeyData = (Keys)wParam;

          if (lParam.ToInt64() > int.MaxValue)
          {
            Debug.WriteLine($"鬆開了{mKeyData}鍵");
          }
          if (lParam.ToInt64() > 0 && lParam.ToInt64() < int.MaxValue)
          {
            KeyEventArgs e = new(mKeyData);//獲取KeyEventArgs事件的相關信息
            if (Events[_eventKeyDown] is KeyEventHandler handler)
              handler.Invoke(this, e); 
          }
        }
      }
      return CallNextHookEx(this.mKetboardHook, nCode, wParam, lParam);
    }
    /// <summary>
    /// 安裝鉤子
    /// </summary>
    /// <returns></returns>
    public bool InstallHook(bool status)
    {
      //線程鉤子時一定要通過這個取得的值纔是操作系統下真實的線程
      uint result = GetCurrentThreadId();

      if (this.mKetboardHook == IntPtr.Zero)
      {
        if (status)
        {
          this.mKeyboardHookProcedure = new HookProc(this.KeyboardHookProc);
        }
        else
        {
          this.mKeyboardHookProcedure = new HookProc(this.KeyboardHookProcNew);
        }
        //註冊線程鉤子時第三個參數是空
        this.mKetboardHook = SetWindowsHookEx(WH_CODE.WH_KEYBOARD, this.mKeyboardHookProcedure, IntPtr.Zero, result);
        /*
        如果是全局鉤子應該這樣使用
        this.mKetboardHook = SetWindowsHookEx(WH_CODE.WH_KEYBOARD_LL, mKeyboardHookProcedure,GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName), 0);
        */
        if (this.mKetboardHook == IntPtr.Zero)
        {
          return false;
        }
      }
      return true;
    }


    /// <summary>
    /// 卸載鉤子
    /// </summary>
    /// <returns>true表示成功 </returns>
    public bool UnInstallHook()
    {
      bool result = true;
      if (this.mKetboardHook != IntPtr.Zero)
      {
        result = UnhookWindowsHookEx(this.mKetboardHook) && result;
        this.mKetboardHook = IntPtr.Zero;
      }
      return result;
    }

    public void Dispose()
    {
      UnInstallHook();
      GC.SuppressFinalize(this);
    }
  }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章