[Xiao Mu learns C++] C++ implements mouse and keyboard hook HOOK

1 Introduction

https://learn.microsoft.com/zh-cn/windows/win32/winmsg/about-hooks

Hooks are mechanisms by which applications intercept events such as messages, mouse operations, and keystrokes. Functions that intercept specific types of events are called hook procedures. A hooked procedure can perform an action on each event it receives and then modify or discard the event.
Insert image description here

A hook is a point in the system's message-handling mechanism where an application can install subroutines to monitor message traffic in the system and process certain types of messages before they reach the target window procedure.
Insert image description here

Here are some examples using hooks:

  • Monitor messages for debugging
  • Supports recording and playing macros
  • Provides support for help keys (F1)
  • Simulate mouse and keyboard input
  • Implement computer-based training (CBT) applications

Insert image description here

2. Related functions

2.1 SetWindowsHookEx

Install application-defined hook procedures into the hook chain. You will install hook procedures to monitor the system for certain types of events. These events are associated with a specific thread or with all threads in the same desktop as the calling thread.

HHOOK SetWindowsHookExA(
  [in] int       idHook,
  [in] HOOKPROC  lpfn,
  [in] HINSTANCE hmod,
  [in] DWORD     dwThreadId
);

HHOOK SetWindowsHookExW(
  [in] int       idHook,
  [in] HOOKPROC  lpfn,
  [in] HINSTANCE hmod,
  [in] DWORD     dwThreadId
);
  • WH_KEYBOARD
    installs a hook process for monitoring keystroke messages. For more information, see KeyboardProc hook procedure.
LRESULT CALLBACK KeyboardProc(
  _In_ int    code,
  _In_ WPARAM wParam,
  _In_ LPARAM lParam
);
  • WH_KEYBOARD_LL
    installs hook procedures for monitoring low-level keyboard input events. For more information, see the [LowLevelKeyboardProc] (/windows/win32/winmsg/lowlevelkeyboardproc) hook procedure.
LRESULT CALLBACK LowLevelKeyboardProc(
  _In_ int    nCode,
  _In_ WPARAM wParam,
  _In_ LPARAM lParam
);
// 其中lParam指向 KBDLLHOOKSTRUCT 结构的指针。
  • WH_MOUSE
    installs a hook process that monitors mouse messages. For more information, see MouseProc Hooking Procedure.
LRESULT CALLBACK MouseProc(
  _In_ int    nCode,
  _In_ WPARAM wParam,
  _In_ LPARAM lParam
);
  • WH_MOUSE_LL
    installs hook procedures for monitoring low-level mouse input events. For more information, see the LowLevelMouseProc hook procedure.
LRESULT CALLBACK LowLevelMouseProc(
  _In_ int    nCode,
  _In_ WPARAM wParam,
  _In_ LPARAM lParam
);
// 其中lParam指向 MSLLHOOKSTRUCT 结构的指针。

2.2 UnhookWindowsHookEx

Remove the SetWindowsHookEx function that installs the hook procedure in the hook chain.

BOOL UnhookWindowsHookEx(
  [in] HHOOK hhk
);

2.3 CallNextHookEx

Pass hooking information to the next hooking process in the current hooking chain. The hook procedure can call this function before or after processing hook information.

LRESULT CallNextHookEx(
  [in, optional] HHOOK  hhk,
  [in]           int    nCode,
  [in]           WPARAM wParam,
  [in]           LPARAM lParam
);

3. Related structures

3.1 KBDLLHOOKSTRUCT

Contains information about low-level keyboard input events.

typedef struct tagKBDLLHOOKSTRUCT {
    
    
  DWORD     vkCode;
  DWORD     scanCode;
  DWORD     flags;
  DWORD     time;
  ULONG_PTR dwExtraInfo;
} KBDLLHOOKSTRUCT, *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;

3.2 MSLLHOOKSTRUCT

Contains information about low-level mouse input events.

typedef struct tagMSLLHOOKSTRUCT {
    
    
  POINT     pt;
  DWORD     mouseData;
  DWORD     flags;
  DWORD     time;
  ULONG_PTR dwExtraInfo;
} MSLLHOOKSTRUCT, *LPMSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT;

4. Hooking process

  • Defining a hook procedure
    To take advantage of a specific type of hook, the developer provides a hook procedure and installs it into the chain associated with the hook using the SetWindowsHookEx function. The hook procedure must have the following syntax:
LRESULT CALLBACK HookProc(
  int nCode, 
  WPARAM wParam, 
  LPARAM lParam
)
{
    
    
   // process event
   ...

   return CallNextHookEx(NULL, nCode, wParam, lParam);
}

The SetWindowsHookEx function always installs the hook procedure at the beginning of the hook chain. When an event occurs that is monitored by a specific type of hook, the system calls a procedure at the beginning of the hook chain associated with the hook. Each hooked process in the chain determines whether to pass the event to the next process. The hook process passes the event to the next process by calling the CallNextHookEx function.

  • Installing and releasing hook procedures
    SetWindowsHookEx passes the module handle, a pointer to the hook procedure entry point, and a thread identifier of 0, indicating that the hook procedure should be associated with all threads in the same desktop as the calling thread. This sequence is shown in the following example.
HOOKPROC hkprcSysMsg;
static HINSTANCE hinstDLL; 
static HHOOK hhookSysMsg; 
 
hinstDLL = LoadLibrary(TEXT("c:\\myapp\\sysmsg.dll")); 
hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc"); 

hhookSysMsg = SetWindowsHookEx( 
                    WH_SYSMSGFILTER,
                    hkprcSysMsg,
                    hinstDLL,
                    0);

You can release a thread-specific hook procedure by calling the UnhookWindowsHookEx function, removing its address (from the hook chain), and specifying the handle of the hook procedure to be released. Release the hooked process as soon as it is no longer needed by the application.

5. Code testing

5.1 Code 1


#include "pch.h"
#include <Windows.h>
#include <iostream>

std::string get_time()
{
    
    
	SYSTEMTIME sys;
	GetLocalTime(&sys);
	char time[255] = {
    
     0 };
	sprintf_s(time, "[%4d/%02d/%02d %02d:%02d:%02d]", sys.wYear, sys.wMonth, sys.wDay, sys.wHour, sys.wMinute, sys.wSecond);

	return std::string(time);
}

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    
    
	/*
	typedef struct tagKBDLLHOOKSTRUCT {
	DWORD     vkCode;		// 按键代号
	DWORD     scanCode;		// 硬件扫描代号,同 vkCode 也可以作为按键的代号。
	DWORD     flags;		// 事件类型,一般按键按下为 0 抬起为 128。
	DWORD     time;			// 消息时间戳
	ULONG_PTR dwExtraInfo;	// 消息附加信息,一般为 0。
	}KBDLLHOOKSTRUCT,*LPKBDLLHOOKSTRUCT,*PKBDLLHOOKSTRUCT;
	*/
	KBDLLHOOKSTRUCT* ks = (KBDLLHOOKSTRUCT*)lParam;		// 包含低级键盘输入事件信息
	char buffer[255];
	DWORD code = ks->vkCode;
	std::string t = get_time();
	char state[20];

	if (wParam == WM_KEYDOWN)
	{
    
    
		strcpy_s(state, "按下");
	}
	else if (wParam == WM_KEYUP)
	{
    
    
		strcpy_s(state, "抬起");
	}

	sprintf_s(buffer, "[键盘]%s 键代码:%d %s", t.c_str(), code, state);
	std::cout << buffer << std::endl;

	//return 1;	// 拦截消息
	return CallNextHookEx(NULL, nCode, wParam, lParam);
}

LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    
    
	/*
	typedef struct tagMOUSEHOOKSTRUCT {
		POINT   pt;					// Point数据
		HWND    hwnd;				// 接收鼠标消息的窗体的句柄
		UINT    wHitTestCode;		// 指定点击测试值
		ULONG_PTR dwExtraInfo;		// 指定和该消息相关联的附加信息。
	} MOUSEHOOKSTRUCT, FAR* LPMOUSEHOOKSTRUCT, * PMOUSEHOOKSTRUCT;
	*/

	MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;
	POINT pt = ms->pt;
	std::string time = get_time();
	char buffer[1024];
	char state[20] = "未知";

	if (wParam == WM_LBUTTONDOWN)
	{
    
    
		strcpy_s(state, "左键按下");
	}
	else if (wParam == WM_LBUTTONUP)
	{
    
    
		strcpy_s(state, "左键抬起");
	}
	else if (wParam == WM_RBUTTONDOWN)
	{
    
    
		strcpy_s(state, "右键按下");
	}
	else if (wParam == WM_RBUTTONUP)
	{
    
    
		strcpy_s(state, "右键抬起");
	}
	else if (wParam == WM_MOUSEMOVE)
	{
    
    
		strcpy_s(state, "移动");
	}

	sprintf_s(buffer, "[鼠标]%s 键代码:x:%d y:%d %s", time.c_str(), pt.x, pt.y, state);
	std::cout << buffer << std::endl;

	//return 1;	// 拦截消息
	return CallNextHookEx(NULL, nCode, wParam, lParam);

}

int main()
{
    
    
	HINSTANCE hM = GetModuleHandle(NULL), hK = GetModuleHandle(NULL);
	HHOOK g_Hook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, hK, 0);
	HHOOK g_Hook2 = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, hM, 0);

	// 消息循环
	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))
	{
    
    
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	UnhookWindowsHookEx(g_Hook);

	return 0;
}


Insert image description here

Conclusion

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)// ,就在评论处留言,作者继续改进;o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡)
感谢各位大佬童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)! ! !

Guess you like

Origin blog.csdn.net/hhy321/article/details/126945038