c# 钩子 捕获键盘鼠标所有事件,可用于:判断鼠标键盘无操作时,关闭 winform 窗体
5分钟没有操作,自动关闭 form 窗体
钩子(hook)的作用主要体现在监视和拦截系统或进程中的各种事件消息,并进行自定义处理。钩子可以截获并处理相应的消息,例如键盘钩子可以截获键盘消息,外壳钩子可以截取、启动和关闭应用程序的消息等。钩子分为线程钩子和系统钩子,线程钩子监视指定线程的事件消息,而系统钩子监视系统中的所有线程的事件消息
钩子的具体应用场景和功能
键盘和鼠标输入监控:钩子可以截获键盘和鼠标的输入,用于记录用户的操作或进行自动化测试。
屏幕取词和日志监视:通过监控系统事件,钩子可以实现屏幕取词功能或记录系统的操作日志。
应用程序监控:外壳钩子可以截取、启动和关闭应用程序的消息,用于监控或管理应用程序的行为。
钩子的种类及其功能
键盘钩子:截获键盘消息,用于记录键盘输入或进行输入拦截。
鼠标钩子:截获鼠标事件,用于监控鼠标操作。
外壳钩子:截取、启动和关闭应用程序的消息,用于管理应用程序行为。
日志钩子:监控系统日志事件,用于记录系统操作日志。
钩子的工作原理
钩子是windows消息处理机制中的一个监视点,应用程序可以在这里安装一个监视子程序,从而在系统的消息流到达目的窗口的过程前监控它们。通过这种方式,钩子能够实现各种自定义的功能和处理逻辑
- globalhook
- keyboardhook
- mousehook
- keyboardsimulator
- mousesimulator
globalhook
using system; using system.text; using system.runtime.interopservices; using system.reflection; using system.windows.forms; namespace vipsoft.baseclass.hook { /// <summary> /// abstract base class for mouse and keyboard hooks /// </summary> public abstract class globalhook { #region windows api code /// <summary> /// 用于控制结构体或类的字段在内存中的布局方式 /// 具体来说,layoutkind.sequential 表示字段将按照它们在源代码中声明的顺序排列 /// 结构体字段将按照 x、y 的顺序在内存中排列 /// - sequential:字段按声明顺序排列,不插入填充字节。 /// - explicit:允许开发者精确控制每个字段的存储位置,使用 fieldoffset 属性指定偏移量。 /// - auto:由编译器选择最优布局方式,通常不推荐用于与非托管代码交互的场景 /// </summary> [structlayout(layoutkind.sequential)] protected class point { public int x; public int y; } [structlayout(layoutkind.sequential)] protected class mousehookstruct { public point pt; public int hwnd; public int whittestcode; public int dwextrainfo; } [structlayout(layoutkind.sequential)] protected class mousellhookstruct { public point pt; public int mousedata; public int flags; public int time; public int dwextrainfo; } [structlayout(layoutkind.sequential)] protected class keyboardhookstruct { public int vkcode; public int scancode; public int flags; public int time; public int dwextrainfo; } /// <summary> /// callingconvention属性指定调用约定,它定义了函数如何接收参数和返回值。常见的调用约定包括: /// - callingconvention.cdecl:调用者清理堆栈,多用于c/c++库。 /// - callingconvention.stdcall:被调用者清理堆栈,windows api常用。 /// - callingconvention.thiscall:用于c++类方法。 /// - callingconvention.fastcall:用于快速调用,较少使用。 /// charset属性用于指定字符串的字符集,影响字符串的处理和传递方式。主要选项有: /// - charset.ansi:将字符串作为ansi编码传递。 /// - charset.unicode:将字符串作为unicode编码传递。 /// - charset.auto:根据平台自动选择ansi或unicode。 /// setlasterror属性指定是否在调用非托管函数后调用getlasterror。设置为true时,可以使用marshal.getlastwin32error获取错误代码。 /// /// idhook, 指示欲被安装的挂钩处理过程之类型 /// lpfn, 指向相应的挂钩处理过程.若参数dwthreadid为0或者指示了一个其他进程创建的线程之标识符,则参数lpfn必须指向一个动态链接中的挂钩处理过程.否则,参数lpfn可以指向一个与当前进程相关的代码中定义的挂钩处理过程 /// hmod 指示了一个动态链接的句柄,该动态连接库包含了参数lpfn 所指向的挂钩处理过程.若参数dwthreadid指示的线程由当前进程创建,并且相应的挂钩处理过程定义于当前进程相关的代码中,则参数hmod必须被设置为null(0)。 /// dwthreadid 指示了一个线程标识符,挂钩处理过程与线程相关.若此参数值为0,则该挂钩处理过程与所有现存的线程相关。 /// /// </summary> [dllimport("user32.dll", charset = charset.auto, callingconvention = callingconvention.stdcall, setlasterror = true)] protected static extern int setwindowshookex( int idhook, hookproc lpfn, intptr hmod, int dwthreadid); [dllimport("user32.dll", charset = charset.auto, callingconvention = callingconvention.stdcall, setlasterror = true)] protected static extern int unhookwindowshookex(int idhook); [dllimport("user32.dll", charset = charset.auto,callingconvention = callingconvention.stdcall)] protected static extern int callnexthookex( int idhook, int ncode, int wparam, intptr lparam); [dllimport("user32")] protected static extern int toascii( int uvirtkey, int uscancode, byte[] lpbkeystate, byte[] lpwtranskey, int fustate); [dllimport("user32")] protected static extern int getkeyboardstate(byte[] pbkeystate); [dllimport("user32.dll", charset = charset.auto, callingconvention = callingconvention.stdcall)] protected static extern short getkeystate(int vkey); protected delegate int hookproc(int ncode, int wparam, intptr lparam); protected const int wh_mouse_ll = 14; //此挂钩只能在windows nt中被安装,用来对底层的鼠标输入事件进行监视.详情参见lowlevelmouseproc挂钩处理过程. protected const int wh_keyboard_ll = 13; //此挂钩只能在windows nt中被安装,用来对底层的键盘输入事件进行监视.详情参见lowlevelkeyboardproc挂钩处理过程. protected const int wh_mouse = 7; //安装一个挂钩处理过程,对鼠标消息进行监视. 详情参见 mouseproc挂钩处理过程. protected const int wh_keyboard = 2; //安装一个挂钩处理过程对击键消息进行监视. 详情参见keyboardproc挂钩处理过程. protected const int wm_mousemove = 0x200; //鼠标移动 protected const int wm_lbuttondown = 0x201; //鼠标左健按下 protected const int wm_rbuttondown = 0x204; //鼠标右健按下 protected const int wm_mbuttondown = 0x207; //鼠标滚轮按下 protected const int wm_lbuttonup = 0x202; protected const int wm_rbuttonup = 0x205; protected const int wm_mbuttonup = 0x208; protected const int wm_lbuttondblclk = 0x203; protected const int wm_rbuttondblclk = 0x206; protected const int wm_mbuttondblclk = 0x209; protected const int wm_mousewheel = 0x020a; protected const int wm_keydown = 0x100; protected const int wm_keyup = 0x101; protected const int wm_syskeydown = 0x104; protected const int wm_syskeyup = 0x105; protected const byte vk_shift = 0x10; protected const byte vk_capital = 0x14; protected const byte vk_numlock = 0x90; protected const byte vk_lshift = 0xa0; protected const byte vk_rshift = 0xa1; protected const byte vk_lcontrol = 0xa2; protected const byte vk_rcontrol = 0x3; protected const byte vk_lalt = 0xa4; protected const byte vk_ralt = 0xa5; protected const byte llkhf_altdown = 0x20; #endregion #region private variables protected int _hooktype; protected int _handletohook; protected bool _isstarted; protected hookproc _hookcallback; #endregion #region properties public bool isstarted { get { return _isstarted; } } #endregion #region constructor public globalhook() { application.applicationexit += new eventhandler(application_applicationexit); } #endregion #region methods /// <summary> /// 启用钩子 /// </summary> public void start() { if (!_isstarted && _hooktype != 0) { // make sure we keep a reference to this delegate! // if not, gc randomly collects it, and a nullreference exception is thrown _hookcallback = new hookproc(hookcallbackprocedure); _handletohook = setwindowshookex( _hooktype, _hookcallback, marshal.gethinstance(assembly.getexecutingassembly().getmodules()[0]), 0); // were we able to sucessfully start hook? if (_handletohook != 0) { _isstarted = true; } } } /// <summary> /// 停止钩子 /// </summary> public void stop() { if (_isstarted) { unhookwindowshookex(_handletohook); _isstarted = false; } } protected virtual int hookcallbackprocedure(int ncode, int32 wparam, intptr lparam) { // this method must be overriden by each extending hook return 0; } protected void application_applicationexit(object sender, eventargs e) { if (_isstarted) { stop(); } } #endregion } }
keyboardhook
using system; using system.text; using system.windows.forms; using system.runtime.interopservices; namespace vipsoft.baseclass.hook { /// <summary> /// captures global keyboard events /// </summary> public class keyboardhook : globalhook { #region events public event keyeventhandler keydown; public event keyeventhandler keyup; public event keypresseventhandler keypress; #endregion #region constructor public keyboardhook() { _hooktype = wh_keyboard_ll; } #endregion #region methods protected override int hookcallbackprocedure(int ncode, int wparam, intptr lparam) { bool handled = false; if (ncode > -1 && (keydown != null || keyup != null || keypress != null)) { keyboardhookstruct keyboardhookstruct = (keyboardhookstruct)marshal.ptrtostructure(lparam, typeof(keyboardhookstruct)); // is control being held down? bool control = ((getkeystate(vk_lcontrol) & 0x80) != 0) || ((getkeystate(vk_rcontrol) & 0x80) != 0); // is shift being held down? bool shift = ((getkeystate(vk_lshift) & 0x80) != 0) || ((getkeystate(vk_rshift) & 0x80) != 0); // is alt being held down? bool alt = ((getkeystate(vk_lalt) & 0x80) != 0) || ((getkeystate(vk_ralt) & 0x80) != 0); // is capslock on? bool capslock = (getkeystate(vk_capital) != 0); // create event using keycode and control/shift/alt values found above keyeventargs e = new keyeventargs( (keys)( keyboardhookstruct.vkcode | (control ? (int)keys.control : 0) | (shift ? (int)keys.shift : 0) | (alt ? (int)keys.alt : 0) )); // handle keydown and keyup events switch (wparam) { case wm_keydown: case wm_syskeydown: if (keydown != null) { keydown(this, e); handled = handled || e.handled; } break; case wm_keyup: case wm_syskeyup: if (keyup != null) { keyup(this, e); handled = handled || e.handled; } break; } // handle keypress event if (wparam == wm_keydown && !handled && !e.suppresskeypress && keypress != null) { byte[] keystate = new byte[256]; byte[] inbuffer = new byte[2]; getkeyboardstate(keystate); if (toascii(keyboardhookstruct.vkcode, keyboardhookstruct.scancode, keystate, inbuffer, keyboardhookstruct.flags) == 1) { char key = (char)inbuffer[0]; if ((capslock ^ shift) && char.isletter(key)) key = char.toupper(key); keypresseventargs e2 = new keypresseventargs(key); keypress(this, e2); handled = handled || e.handled; } } } if (handled) { return 1; } else { return callnexthookex(_handletohook, ncode, wparam, lparam); } } #endregion } }
mousehook
using system; using system.text; using system.windows.forms; using system.runtime.interopservices; namespace vipsoft.baseclass.hook { /// <summary> /// captures global mouse events /// </summary> public class mousehook : globalhook { #region mouseeventtype enum private enum mouseeventtype { none, mousedown, mouseup, doubleclick, mousewheel, mousemove } #endregion #region events public event mouseeventhandler mousedown; public event mouseeventhandler mouseup; public event mouseeventhandler mousemove; public event mouseeventhandler mousewheel; public event eventhandler click; public event eventhandler doubleclick; #endregion #region constructor public mousehook() { _hooktype = wh_mouse_ll; } #endregion #region methods protected override int hookcallbackprocedure(int ncode, int wparam, intptr lparam) { if (ncode > -1 && (mousedown != null || mouseup != null || mousemove != null)) { mousellhookstruct mousehookstruct = (mousellhookstruct)marshal.ptrtostructure(lparam, typeof(mousellhookstruct)); mousebuttons button = getbutton(wparam); mouseeventtype eventtype = geteventtype(wparam); mouseeventargs e = new mouseeventargs( button, (eventtype == mouseeventtype.doubleclick ? 2 : 1), mousehookstruct.pt.x, mousehookstruct.pt.y, (eventtype == mouseeventtype.mousewheel ? (short)((mousehookstruct.mousedata >> 16) & 0xffff) : 0)); // prevent multiple right click events (this probably happens for popup menus) if (button == mousebuttons.right && mousehookstruct.flags != 0) { eventtype = mouseeventtype.none; } switch (eventtype) { case mouseeventtype.mousedown: if (mousedown != null) { mousedown(this, e); } break; case mouseeventtype.mouseup: if (click != null) { click(this, new eventargs()); } if (mouseup != null) { mouseup(this, e); } break; case mouseeventtype.doubleclick: if (doubleclick != null) { doubleclick(this, new eventargs()); } break; case mouseeventtype.mousewheel: if (mousewheel != null) { mousewheel(this, e); } break; case mouseeventtype.mousemove: if (mousemove != null) { mousemove(this, e); } break; default: break; } } return callnexthookex(_handletohook, ncode, wparam, lparam); } private mousebuttons getbutton(int32 wparam) { switch (wparam) { case wm_lbuttondown: case wm_lbuttonup: case wm_lbuttondblclk: return mousebuttons.left; case wm_rbuttondown: case wm_rbuttonup: case wm_rbuttondblclk: return mousebuttons.right; case wm_mbuttondown: case wm_mbuttonup: case wm_mbuttondblclk: return mousebuttons.middle; default: return mousebuttons.none; } } private mouseeventtype geteventtype(int32 wparam) { switch (wparam) { case wm_lbuttondown: case wm_rbuttondown: case wm_mbuttondown: return mouseeventtype.mousedown; case wm_lbuttonup: case wm_rbuttonup: case wm_mbuttonup: return mouseeventtype.mouseup; case wm_lbuttondblclk: case wm_rbuttondblclk: case wm_mbuttondblclk: return mouseeventtype.doubleclick; case wm_mousewheel: return mouseeventtype.mousewheel; case wm_mousemove: return mouseeventtype.mousemove; default: return mouseeventtype.none; } } #endregion } }
keyboardsimulator
using system; using system.collections.generic; using system.linq; using system.runtime.interopservices; using system.text; using system.threading.tasks; using system.windows.forms; namespace vipsoft.baseclass.hook { /// <summary> /// standard keyboard shortcuts used by most applications /// </summary> public enum standardshortcut { copy, cut, paste, selectall, save, open, new, close, print } /// <summary> /// simulate keyboard key presses /// </summary> public static class keyboardsimulator { #region windows api code const int keyeventf_extendedkey = 0x1; const int keyeventf_keyup = 0x2; [dllimport("user32.dll")] static extern void keybd_event(byte key, byte scan, int flags, int extrainfo); #endregion #region methods public static void keydown(keys key) { keybd_event(parsekey(key), 0, 0, 0); } public static void keyup(keys key) { keybd_event(parsekey(key), 0, keyeventf_keyup, 0); } public static void keypress(keys key) { keydown(key); keyup(key); } public static void simulatestandardshortcut(standardshortcut shortcut) { switch (shortcut) { case standardshortcut.copy: keydown(keys.control); keypress(keys.c); keyup(keys.control); break; case standardshortcut.cut: keydown(keys.control); keypress(keys.x); keyup(keys.control); break; case standardshortcut.paste: keydown(keys.control); keypress(keys.v); keyup(keys.control); break; case standardshortcut.selectall: keydown(keys.control); keypress(keys.a); keyup(keys.control); break; case standardshortcut.save: keydown(keys.control); keypress(keys.s); keyup(keys.control); break; case standardshortcut.open: keydown(keys.control); keypress(keys.o); keyup(keys.control); break; case standardshortcut.new: keydown(keys.control); keypress(keys.n); keyup(keys.control); break; case standardshortcut.close: keydown(keys.alt); keypress(keys.f4); keyup(keys.alt); break; case standardshortcut.print: keydown(keys.control); keypress(keys.p); keyup(keys.control); break; } } static byte parsekey(keys key) { // alt, shift, and control need to be changed for api function to work with them switch (key) { case keys.alt: return (byte)18; case keys.control: return (byte)17; case keys.shift: return (byte)16; default: return (byte)key; } } #endregion } }
mousesimulator
using system; using system.text; using system.runtime.interopservices; using system.drawing; using system.windows.forms; namespace vipsoft.baseclass.hook { /// <summary> /// and x, y point on the screen /// </summary> public struct mousepoint { public mousepoint(point p) { x = p.x; y = p.y; } public int x; public int y; public static implicit operator point(mousepoint p) { return new point(p.x, p.y); } } /// <summary> /// mouse buttons that can be pressed /// </summary> public enum mousebutton { left = 0x2, right = 0x8, middle = 0x20 } /// <summary> /// operations that simulate mouse events /// </summary> public static class mousesimulator { #region windows api code [dllimport("user32.dll")] static extern int showcursor(bool show); [dllimport("user32.dll")] static extern void mouse_event(int flags, int dx, int dy, int buttons, int extrainfo); const int mouseeventf_move = 0x1; const int mouseeventf_leftdown = 0x2; const int mouseeventf_leftup = 0x4; const int mouseeventf_rightdown = 0x8; const int mouseeventf_rightup = 0x10; const int mouseeventf_middledown = 0x20; const int mouseeventf_middleup = 0x40; const int mouseeventf_wheel = 0x800; const int mouseeventf_absolute = 0x8000; #endregion #region properties /// <summary> /// gets or sets a structure that represents both x and y mouse coordinates /// </summary> public static mousepoint position { get { return new mousepoint(cursor.position); } set { cursor.position = value; } } /// <summary> /// gets or sets only the mouse's x coordinate /// </summary> public static int x { get { return cursor.position.x; } set { cursor.position = new point(value, y); } } /// <summary> /// gets or sets only the mouse's y coordinate /// </summary> public static int y { get { return cursor.position.y; } set { cursor.position = new point(x, value); } } #endregion #region methods /// <summary> /// press a mouse button down /// </summary> /// <param name="button"></param> public static void mousedown(mousebutton button) { mouse_event(((int)button), 0, 0, 0, 0); } public static void mousedown(mousebuttons button) { switch (button) { case mousebuttons.left: mousedown(mousebutton.left); break; case mousebuttons.middle: mousedown(mousebutton.middle); break; case mousebuttons.right: mousedown(mousebutton.right); break; } } /// <summary> /// let a mouse button up /// </summary> /// <param name="button"></param> public static void mouseup(mousebutton button) { mouse_event(((int)button) * 2, 0, 0, 0, 0); } public static void mouseup(mousebuttons button) { switch (button) { case mousebuttons.left: mouseup(mousebutton.left); break; case mousebuttons.middle: mouseup(mousebutton.middle); break; case mousebuttons.right: mouseup(mousebutton.right); break; } } /// <summary> /// click a mouse button (down then up) /// </summary> /// <param name="button"></param> public static void click(mousebutton button) { mousedown(button); mouseup(button); } public static void click(mousebuttons button) { switch (button) { case mousebuttons.left: click(mousebutton.left); break; case mousebuttons.middle: click(mousebutton.middle); break; case mousebuttons.right: click(mousebutton.right); break; } } /// <summary> /// double click a mouse button (down then up twice) /// </summary> /// <param name="button"></param> public static void doubleclick(mousebutton button) { click(button); click(button); } public static void doubleclick(mousebuttons button) { switch (button) { case mousebuttons.left: doubleclick(mousebutton.left); break; case mousebuttons.middle: doubleclick(mousebutton.middle); break; case mousebuttons.right: doubleclick(mousebutton.right); break; } } /// <summary> /// show a hidden current on currently application /// </summary> public static void show() { showcursor(true); } /// <summary> /// hide mouse cursor only on current application's forms /// </summary> public static void hide() { showcursor(false); } #endregion } }
测试类
using system; using system.collections.generic; using system.componentmodel; using system.data; using system.drawing; using system.linq; using system.text; using system.windows.forms; using mousekeyboardlibrary; namespace sampleapplication { /* 上面的5个类编译成dll引用,使用例子 */ public partial class hooktestform : form { //用于判断,窗休是否自动关闭 system.windows.forms.timer mtimer = new system.windows.forms.timer(); //记录鼠标键盘操作时间,用于判断 form 窗体自动关闭 private datetime mrecordtime = datetime.now; mousehook mousehook = new mousehook(); keyboardhook keyboardhook = new keyboardhook(); public hooktestform() { initializecomponent(); } private void testform_load(object sender, eventargs e) { mtimer.tick += mtimer_tick; mtimer.interval = 2000; mtimer.start(); //开启定时器 mousehook.mousemove += new mouseeventhandler(mousehook_mousemove); mousehook.mousedown += new mouseeventhandler(mousehook_mousedown); mousehook.mouseup += new mouseeventhandler(mousehook_mouseup); mousehook.mousewheel += new mouseeventhandler(mousehook_mousewheel); keyboardhook.keydown += new keyeventhandler(keyboardhook_keydown); keyboardhook.keyup += new keyeventhandler(keyboardhook_keyup); keyboardhook.keypress += new keypresseventhandler(keyboardhook_keypress); mousehook.start(); keyboardhook.start(); setxylabel("", mousesimulator.x.tostring(), mousesimulator.y.tostring()); } void keyboardhook_keypress(object sender, keypresseventargs e) { addkeyboardevent( "keypress", "", e.keychar.tostring(), "", "", "" ); } void keyboardhook_keyup(object sender, keyeventargs e) { addkeyboardevent( "keyup", e.keycode.tostring(), "", e.shift.tostring(), e.alt.tostring(), e.control.tostring() ); } void keyboardhook_keydown(object sender, keyeventargs e) { addkeyboardevent( "keydown", e.keycode.tostring(), "", e.shift.tostring(), e.alt.tostring(), e.control.tostring() ); } void mousehook_mousewheel(object sender, mouseeventargs e) { addmouseevent( "mousewheel", "", "", "", e.delta.tostring() ); } void mousehook_mouseup(object sender, mouseeventargs e) { addmouseevent( "mouseup", e.button.tostring(), e.x.tostring(), e.y.tostring(), "" ); } void mousehook_mousedown(object sender, mouseeventargs e) { addmouseevent( "mousedown", e.button.tostring(), e.x.tostring(), e.y.tostring(), "" ); } void mousehook_mousemove(object sender, mouseeventargs e) { setxylabel("", e.x.tostring(), e.y.tostring()); } void setxylabel(string keyname, string x, string y) { this.text = $"current keyname={keyname} point: x={x}, y={y} {datetime.now.tostring("hh:mm:ss")}"; mrecordtime = datetime.now; } void addmouseevent(string eventtype, string button, string x, string y, string delta) { //this.text = $"current mouse eventtype ={eventtype} button ={button} delta ={delta} x ={x}, y ={y}"; setxylabel(button, x, y); } void addkeyboardevent(string eventtype, string keycode, string keychar, string shift, string alt, string control) { //this.text = $"current mouse eventtype ={eventtype} keycode ={keycode} keychar ={keychar} shift ={shift}, alt ={alt} control={control}"; setxylabel(button, x, y); } private void testform_formclosed(object sender, formclosedeventargs e) { // not necessary anymore, will stop when application exits //mousehook.stop(); //keyboardhook.stop(); } private bool stopform = false; //定时器 private void mtimer_tick(object sender, eventargs e) { if (stopform) { return; } if ((datetime.now - mrecordtime).totalminutes >= 5) //记录时间大于5分钟 { stopform = true; for (int i = application.openforms.count - 1; i >= 0; i--) { form item = application.openforms[i]; if (item.name != this.name && item.name != "userlogin") //关闭不是主窗体的打开窗体 { item.close(); } } this.windowstate = formwindowstate.maximized; stopform = false; } } } }
以上就是c#钩子hook监听键盘鼠标事件实现窗体自动关闭的详细内容,更多关于c#钩子hook监听键盘鼠标事件的资料请关注代码网其它相关文章!
发表评论