zoukankan      html  css  js  c++  java
  • VSTO中使用线程钩子响应鼠标键盘事件

          由于VSTO本身没有提供充分的鼠标键盘事件,在制作Add-in的时候非常不方便,迫于无奈想到使用Hook来辅助一下,大部分网上参考文章都只是展示了全局钩子的写法,而线程钩子的写法和介绍相对少一些,特别是关键语句上如果定义的不正确是没有任何效果的,在自己反复尝试后决定留下一个正确的版本分享出来,毕竟全局钩子性能差,没有办法用到VSTO中的。

    View Code
     1     public class Win32API
    2 {
    3 #region 导入API
    4
    5 /// <summary>
    6 /// 安装钩子
    7 /// </summary>
    8 [DllImport("user32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    9 public static extern IntPtr SetWindowsHookEx(WH_CODE idHook, HookProc lpfn, IntPtr pInstance, uint threadId);
    10
    11 /// <summary>
    12 /// 卸载钩子
    13 /// </summary>
    14 [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
    15 public static extern bool UnhookWindowsHookEx(IntPtr pHookHandle);
    16
    17 /// <summary>
    18 /// 传递钩子
    19 /// </summary>
    20 [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
    21 public static extern int CallNextHookEx(IntPtr pHookHandle, int nCodem, Int32 wParam, IntPtr lParam);
    22
    23 /// <summary>
    24 /// 获取全部按键状态
    25 /// </summary>
    26 /// <param name="pbKeyState"></param>
    27 /// <returns>非0表示成功</returns>
    28 [DllImport("user32.dll")]
    29 public static extern int GetKeyboardState(byte[] pbKeyState);
    30
    31 /// <summary>
    32 /// 获取程序集模块的句柄
    33 /// </summary>
    34 /// <param name="lpModuleName"></param>
    35 /// <returns></returns>
    36 [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    37 public static extern IntPtr GetModuleHandle(string lpModuleName);
    38
    39 /// <summary>
    40 /// 获取指定句柄的线程ID
    41 /// </summary>
    42 /// <param name="hwnd"></param>
    43 /// <param name="ID"></param>
    44 /// <returns></returns>
    45 [DllImport("user32.dll", CharSet = CharSet.Auto)]
    46 public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);
    47
    48 /// <summary>
    49 /// 获取当前进程中的当前线程ID
    50 /// </summary>
    51 /// <returns></returns>
    52 [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    53 public static extern uint GetCurrentThreadId();
    54
    55 /// <summary>
    56 /// 获取指定按键状态
    57 /// </summary>
    58 /// <param name="keyCode"></param>
    59 /// <returns></returns>
    60 [DllImport("user32.dll", CharSet = CharSet.Auto)]
    61 public static extern int GetKeyState(int keyCode);
    62
    63 #endregion
    64 }
    View Code
      1     #region 定义结构
    2
    3 public enum WH_CODE : int
    4 {
    5 WH_JOURNALRECORD = 0,
    6 WH_JOURNALPLAYBACK = 1,
    7
    8 /// <summary>
    9 /// 进程钩子
    10 /// </summary>
    11 WH_KEYBOARD = 2,
    12
    13 WH_GETMESSAGE = 3,
    14 WH_CALLWNDPROC = 4,
    15 WH_CBT = 5,
    16 WH_SYSMSGFILTER = 6,
    17 /// <summary>
    18 /// 进程钩子
    19 /// </summary>
    20 WH_MOUSE = 7,
    21 WH_HARDWARE = 8,
    22 WH_DEBUG = 9,
    23 WH_SHELL = 10,
    24 WH_FOREGROUNDIDLE = 11,
    25 WH_CALLWNDPROCRET = 12,
    26 /// <summary>
    27 /// 底层键盘钩子
    28 /// </summary>
    29 WH_KEYBOARD_LL = 13,
    30
    31 /// <summary>
    32 /// 底层鼠标钩子
    33 /// </summary>
    34 WH_MOUSE_LL = 14
    35 }
    36
    37 public enum WM_MOUSE : int
    38 {
    39 /// <summary>
    40 /// 鼠标开始
    41 /// </summary>
    42 WM_MOUSEFIRST = 0x200,
    43
    44 /// <summary>
    45 /// 鼠标移动
    46 /// </summary>
    47 WM_MOUSEMOVE = 0x200,
    48
    49 /// <summary>
    50 /// 左键按下
    51 /// </summary>
    52 WM_LBUTTONDOWN = 0x201,
    53
    54 /// <summary>
    55 /// 左键释放
    56 /// </summary>
    57 WM_LBUTTONUP = 0x202,
    58
    59 /// <summary>
    60 /// 左键双击
    61 /// </summary>
    62 WM_LBUTTONDBLCLK = 0x203,
    63
    64 /// <summary>
    65 /// 右键按下
    66 /// </summary>
    67 WM_RBUTTONDOWN = 0x204,
    68
    69 /// <summary>
    70 /// 右键释放
    71 /// </summary>
    72 WM_RBUTTONUP = 0x205,
    73
    74 /// <summary>
    75 /// 右键双击
    76 /// </summary>
    77 WM_RBUTTONDBLCLK = 0x206,
    78
    79 /// <summary>
    80 /// 中键按下
    81 /// </summary>
    82 WM_MBUTTONDOWN = 0x207,
    83
    84 /// <summary>
    85 /// 中键释放
    86 /// </summary>
    87 WM_MBUTTONUP = 0x208,
    88
    89 /// <summary>
    90 /// 中键双击
    91 /// </summary>
    92 WM_MBUTTONDBLCLK = 0x209,
    93
    94 /// <summary>
    95 /// 滚轮滚动
    96 /// </summary>
    97 /// <remarks>WINNT4.0以上才支持此消息</remarks>
    98 WM_MOUSEWHEEL = 0x020A
    99 }
    100
    101 public enum WM_KEYBOARD : int
    102 {
    103 /// <summary>
    104 /// 非系统按键按下
    105 /// </summary>
    106 WM_KEYDOWN = 0x100,
    107
    108 /// <summary>
    109 /// 非系统按键释放
    110 /// </summary>
    111 WM_KEYUP = 0x101,
    112
    113 /// <summary>
    114 /// 系统按键按下
    115 /// </summary>
    116 WM_SYSKEYDOWN = 0x104,
    117
    118 /// <summary>
    119 /// 系统按键释放
    120 /// </summary>
    121 WM_SYSKEYUP = 0x105
    122 }
    123
    124 public enum HC_CODE : int
    125 {
    126 HC_ACTION = 0,
    127 HC_GETNEXT = 1,
    128 HC_SKIP = 2,
    129 HC_NOREMOVE = 3,
    130 HC_NOREM = 3,
    131 HC_SYSMODALON = 4,
    132 HC_SYSMODALOFF = 5
    133 }
    134
    135 public enum VK_CODE : int
    136 {
    137 VK_LBUTTON = 0x01,
    138 VK_RBUTTON = 0x02,
    139 VK_SHIFT = 0x10,
    140 VK_CONTROL = 0x11,
    141 VK_MENU = 0x12,//ALT
    142 VK_C = 0x43,
    143 VK_V = 0x56,
    144 VK_X = 0x58,
    145 VK_Y = 0x59,
    146 VK_Z = 0x5A,
    147 VK_APPS = 0x5D,
    148 VK_LSHIFT = 0xA0,
    149 VK_RSHIFT = 0xA1,
    150 VK_LCONTROL = 0xA2,
    151 VK_RCONTROL = 0xA3,
    152 VK_LMENU = 0xA4,
    153 VK_RMENU = 0xA5
    154 }
    155
    156 /// <summary>
    157 /// 键盘钩子事件结构定义
    158 /// </summary>
    159 /// <remarks>详细说明请参考MSDN中关于 KBDLLHOOKSTRUCT 的说明</remarks>
    160 [StructLayout(LayoutKind.Sequential)]
    161 public struct KeyboardHookStruct
    162 {
    163 /// <summary>
    164 /// Specifies a virtual-key code. The code must be a value in the range 1 to 254.
    165 /// </summary>
    166 public UInt32 VKCode;
    167
    168 /// <summary>
    169 /// Specifies a hardware scan code for the key.
    170 /// </summary>
    171 public UInt32 ScanCode;
    172
    173 /// <summary>
    174 /// Specifies the extended-key flag, event-injected flag, context code,
    175 /// and transition-state flag. This member is specified as follows.
    176 /// An application can use the following values to test the keystroke flags.
    177 /// </summary>
    178 public UInt32 Flags;
    179
    180 /// <summary>
    181 /// Specifies the time stamp for this message.
    182 /// </summary>
    183 public UInt32 Time;
    184
    185 /// <summary>
    186 /// Specifies extra information associated with the message.
    187 /// </summary>
    188 public UInt32 ExtraInfo;
    189 }
    190
    191 [StructLayout(LayoutKind.Sequential)]
    192 public struct POINT
    193 {
    194 public int X;
    195 public int Y;
    196 }
    197
    198 /// <summary>
    199 /// 鼠标钩子事件结构定义
    200 /// </summary>
    201 /// <remarks>详细说明请参考MSDN中关于 MSLLHOOKSTRUCT 的说明</remarks>
    202 [StructLayout(LayoutKind.Sequential)]
    203 public struct MouseHookStruct
    204 {
    205 public POINT Point;
    206 public uint hwnd;
    207 public uint wHitTestCode;
    208 public uint dwExtraInfo;
    209 }
    210
    211 #endregion
    View Code
      1     public class Hook
    2 {
    3 #region 私有变量
    4
    5 private byte[] mKeyState = new byte[256];
    6 private Keys mKeyData = Keys.None; //专门用于判断按键的状态
    7
    8 /// <summary>
    9 /// 键盘钩子句柄
    10 /// </summary>
    11 private IntPtr mKetboardHook = IntPtr.Zero;
    12 /// <summary>
    13 /// 鼠标钩子句柄
    14 /// </summary>
    15 private IntPtr mMouseHook = IntPtr.Zero;
    16 /// <summary>
    17 /// 键盘钩子委托实例
    18 /// </summary>
    19 private HookProc mKeyboardHookProcedure;
    20 /// <summary>
    21 /// 鼠标钩子委托实例
    22 /// </summary>
    23 private HookProc mMouseHookProcedure;
    24
    25 #endregion
    26
    27 #region 鼠标事件
    28
    29 public event MouseEventHandler OnMouseDown;
    30 public event MouseEventHandler OnMouseUp;
    31 public event MouseEventHandler OnMouseMove;
    32
    33 #endregion
    34
    35 #region 键盘事件
    36
    37 public event KeyEventHandler OnKeyDown;
    38 public event KeyEventHandler OnKeyUp;
    39
    40 #endregion
    41
    42 /// <summary>
    43 /// 构造函数
    44 /// </summary>
    45 public Hook()
    46 {
    47 Win32API.GetKeyboardState(this.mKeyState);
    48 }
    49
    50 ~Hook()
    51 {
    52 UnInstallHook();
    53 }
    54
    55 /// <summary>
    56 /// 键盘钩子处理函数
    57 /// </summary>
    58 private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
    59 {
    60 // 定义为线程钩子时,wParam的值是击打的按键,与Keys里的对应按键相同
    61 if ((nCode == (int)HC_CODE.HC_ACTION) && (this.OnKeyDown != null || this.OnKeyUp != null))
    62 {
    63 //使用全局Hook才需要
    64 //KeyboardHookStruct KeyboardInfo = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
    65
    66 mKeyData = (Keys)wParam;
    67 KeyEventArgs keyEvent = new KeyEventArgs(mKeyData);
    68 //这里简单的通过lParam的值的正负情况与按键的状态相关联
    69 if (lParam.ToInt32() > 0 && this.OnKeyDown != null)
    70 {
    71 this.OnKeyDown(this, keyEvent);
    72 }
    73 else if (lParam.ToInt32() < 0 && this.OnKeyUp != null)
    74 {
    75 this.OnKeyUp(this, keyEvent);
    76 }
    77 }
    78
    79 return Win32API.CallNextHookEx(this.mKetboardHook, nCode, wParam, lParam);
    80 }
    81
    82 /// <summary>
    83 /// 鼠标钩子处理函数
    84 /// </summary>
    85 private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
    86 {
    87 if ((nCode == (int)HC_CODE.HC_ACTION))
    88 {
    89 MouseHookStruct mouseInfo = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
    90 MouseEventArgs mouseEvent;
    91 if (wParam == (int)WM_MOUSE.WM_LBUTTONDOWN)
    92 {
    93 mouseEvent = new MouseEventArgs(MouseButtons.Left, 1, mouseInfo.Point.X, mouseInfo.Point.Y, 0);
    94 if (this.OnMouseDown != null)
    95 {
    96 this.OnMouseDown(this, mouseEvent);
    97 }
    98 }
    99 else if (wParam == (int)WM_MOUSE.WM_RBUTTONDOWN)
    100 {
    101 mouseEvent = new MouseEventArgs(MouseButtons.Right, 1, mouseInfo.Point.X, mouseInfo.Point.Y, 0);
    102 if (this.OnMouseDown != null)
    103 {
    104 this.OnMouseDown(this, mouseEvent);
    105 }
    106 }
    107 else if (wParam == (int)WM_MOUSE.WM_LBUTTONUP)
    108 {
    109 mouseEvent = new MouseEventArgs(MouseButtons.Left, 1, mouseInfo.Point.X, mouseInfo.Point.Y, 0);
    110 if (this.OnMouseUp != null)
    111 {
    112 this.OnMouseUp(this, mouseEvent);
    113 }
    114 }
    115 else if (wParam == (int)WM_MOUSE.WM_RBUTTONUP)
    116 {
    117 mouseEvent = new MouseEventArgs(MouseButtons.Right, 1, mouseInfo.Point.X, mouseInfo.Point.Y, 0);
    118 if (this.OnMouseUp != null)
    119 {
    120 this.OnMouseUp(this, mouseEvent);
    121 }
    122 }
    123 else if (wParam == (int)WM_MOUSE.WM_MOUSEMOVE)
    124 {
    125 mouseEvent = new MouseEventArgs(MouseButtons.None, 0, mouseInfo.Point.X, mouseInfo.Point.Y, 0);
    126 if (this.OnMouseMove != null)
    127 {
    128 this.OnMouseMove(this, mouseEvent);
    129 }
    130 }
    131 }
    132
    133 return Win32API.CallNextHookEx(this.mMouseHook, nCode, wParam, lParam);
    134 }
    135
    136 /// <summary>
    137 /// 安装钩子
    138 /// </summary>
    139 /// <returns></returns>
    140 public bool InstallHook()
    141 {
    142 //线程钩子时一定要通过这个取得的值才是操作系统下真实的线程
    143 uint result = Win32API.GetCurrentThreadId();
    144
    145 #region 全局Hook
    146 //IntPtr pInstance = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().ManifestModule);
    147 //using (Process curProcess = Process.GetCurrentProcess())
    148 //{
    149 // using (ProcessModule curModule = curProcess.MainModule)
    150 // {
    151 // pInstance = Win32API.GetModuleHandle(curModule.ModuleName);
    152 // }
    153 //}
    154 #endregion
    155
    156 if (this.mKetboardHook == IntPtr.Zero)
    157 {
    158 this.mKeyboardHookProcedure = new HookProc(this.KeyboardHookProc);
    159 //注册线程钩子时第三个参数是空
    160 this.mKetboardHook = Win32API.SetWindowsHookEx(WH_CODE.WH_KEYBOARD, this.mKeyboardHookProcedure, IntPtr.Zero, result);
    161 if (this.mKetboardHook == IntPtr.Zero)
    162 {
    163 return false;
    164 }
    165 }
    166 if (this.mMouseHook == IntPtr.Zero)
    167 {
    168 this.mMouseHookProcedure = new HookProc(this.MouseHookProc);
    169 //注册线程钩子时第三个参数是空
    170 this.mMouseHook = Win32API.SetWindowsHookEx(WH_CODE.WH_MOUSE, this.mMouseHookProcedure, IntPtr.Zero, result);
    171 if (this.mMouseHook == IntPtr.Zero)
    172 {
    173 this.UnInstallHook();
    174 return false;
    175 }
    176 }
    177
    178 return true;
    179 }
    180
    181 /// <summary>
    182 /// 卸载钩子
    183 /// </summary>
    184 /// <returns></returns>
    185 public bool UnInstallHook()
    186 {
    187 bool result = true;
    188 if (this.mKetboardHook != IntPtr.Zero)
    189 {
    190 result = Win32API.UnhookWindowsHookEx(this.mKetboardHook) && result;
    191 this.mKetboardHook = IntPtr.Zero;
    192 }
    193 if (this.mMouseHook != IntPtr.Zero)
    194 {
    195 result = (Win32API.UnhookWindowsHookEx(this.mMouseHook) && result);
    196 this.mMouseHook = IntPtr.Zero;
    197 }
    198
    199 return result;
    200 }
    201 }




  • 相关阅读:
    多种开源OLAP引擎测评报告
    Go的单元测试
    C#的List实现IComparer接口排序实例
    Java 多线程:(一)
    android:theme
    android:excludeFromRecents="true"
    RK:主屏幕
    Gatsby xinhua log boork(三)
    RK:Provision.apk、SettingsProvider的分析、使用
    Camera(一):查看Camera设备详细信息
  • 原文地址:https://www.cnblogs.com/BeanHsiang/p/2405844.html
Copyright © 2011-2022 走看看