C++ 使用RAWINPUT,获取键盘原始输入,拦截键盘消息,键盘钩子

#include "stdafx.h"
#include <windows.h>

//声明自定义消息处理函数
LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
HWND m_hWnd;

//注册原始输入设备
void RegKeyboardRawInput(HWND hWnd)
{	
	RAWINPUTDEVICE rawInputDevice[1];
	rawInputDevice[0].usUsagePage = 0x01;//设备类
	rawInputDevice[0].usUsage = 0x06;//设备类内的具体设备
	rawInputDevice[0].dwFlags = RIDEV_INPUTSINK;//意味着即使窗口失去焦点位置,仍然会一直接收输入消息
	rawInputDevice[0].hwndTarget = hWnd;
	if (RegisterRawInputDevices(rawInputDevice, 1, sizeof(rawInputDevice[0])) == FALSE)
	{
		printf("RegisterRawInputDevices failed");
	}
}

int _tmain(int argc, _TCHAR* argv[])
{	
	//创建一个隐藏窗口
	HINSTANCE hInst;
	hInst = GetModuleHandle(NULL);	//获取一个应用程序或动态链接库的模块句柄	
	WNDCLASSEX wcx;	
	wcx.cbSize = sizeof(wcx);  
	wcx.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_NOCLOSE;//窗口的风格	
	wcx.lpfnWndProc = WindowProc;     //采用自定义消息处理函数
	wcx.cbClsExtra = 0;                // no extra class memory  
	wcx.cbWndExtra = 0;                // no extra window memory  
	wcx.hInstance = hInst;         //当前应用程序的实例句柄 
	wcx.hIcon = LoadIcon(NULL,IDI_APPLICATION); //图标风格		
	wcx.hCursor = LoadCursor(NULL,IDC_ARROW);  //鼠标风格
	wcx.hbrBackground = (HBRUSH)WHITE_BRUSH; //背景色
	wcx.lpszMenuName =NULL;  //菜单名	
	wcx.lpszClassName = _T("ITSMYOSDCLASS"); //窗口类的名称
	wcx.hIconSm = NULL;		

	if (!RegisterClassEx(&wcx))
	{
		printf("RegisterClassEx failed");
		return 1;
	}

	//窗口在屏幕上的显示位置
	int OSDleft = GetSystemMetrics(SM_CXSCREEN) / 2 - 300;
	int OSDTop = GetSystemMetrics(SM_CYSCREEN) / 2;

	m_hWnd = CreateWindowEx(
		WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE,//窗口的扩展风格
		wcx.lpszClassName,//上面注册的类名lpszClassName,要完全一致  
		NULL,
		WS_VISIBLE | WS_POPUP,//窗口的风格
		OSDleft,//窗口相对于父级的X坐标  
		OSDTop,//窗口相对于父级的Y坐标 
		300,//窗口的宽度  
		300,//窗口的高度 
		(HWND)NULL,//没有父窗口,为(HWND)NULL//GetDesktopWindow(),
		(HMENU)NULL,//没有菜单,为NULL  
		hInst,//当前应用程序的实例句柄  
		(LPVOID)NULL);	//没有附加数据,为NULL  

	if (!m_hWnd)
	{
		printf("CreateWindowEx failed");
		return 1;
	}
	RegKeyboardRawInput(m_hWnd);
	//消息循环  
	MSG msg;
	while (GetMessage(&msg, (HWND)NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}	

	return 0;
}
//LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);  
// 自定义消息处理函数的实现
LRESULT CALLBACK WindowProc(_In_  HWND hwnd,_In_  UINT uMsg,_In_  WPARAM wParam,_In_  LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_COMMAND:
		break;
	case WM_PAINT:	
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;	
	case WM_INPUT:
	{		
		UINT dwSize = 0;		
		GetRawInputData((HRAWINPUT)lParam, (UINT)RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));//取数据,第一次调用函数将获取需要的字节大小		
		LPBYTE lpbBuffer = new BYTE[dwSize];//分配指定的缓冲区大小
		GetRawInputData((HRAWINPUT)lParam, (UINT)RID_INPUT, (LPVOID)lpbBuffer, (PUINT)&dwSize, (UINT)sizeof(RAWINPUTHEADER));//第二次调用获取原始输入数据,读入lpbBuffer

		RAWINPUT * raw = (RAWINPUT *)lpbBuffer;
		if (raw->header.dwType == RIM_TYPEKEYBOARD)//这里可以截获所有键盘信息,如需区分不同的键盘输入信息,可以通过设备句柄判断。
		{
			if (raw->data.keyboard.Message == WM_KEYUP)
			{
				//读取键盘名称
				UINT bufferSize;//为键盘设备名准备缓冲区大小
				GetRawInputDeviceInfo(raw->header.hDevice, RIDI_DEVICENAME, NULL, &bufferSize);
				WCHAR* RawDevName = new WCHAR[bufferSize];				
				GetRawInputDeviceInfo(raw->header.hDevice, RIDI_DEVICENAME, RawDevName, &bufferSize);//将设备名读入缓冲区RawDevName
				printf("dev=%ls\n", RawDevName);
				delete[] RawDevName;

				//获取键盘输入
				char keytext[10] = { 0 };
				BYTE state[256] = { 0 };
				ToAscii(raw->data.keyboard.VKey, raw->data.keyboard.MakeCode, state, (LPWORD)keytext, 0);//通过虚拟键盘码得到名字
				printf("key=%s\n", keytext);	

				printf("Kbd: make = % 04x Flags : % 04x Reserved : % 04x ExtraInformation : % 08x, msg = % 04x VK = % 04x \n",
					raw->data.keyboard.MakeCode,
					raw->data.keyboard.Flags,
					raw->data.keyboard.Reserved,
					raw->data.keyboard.ExtraInformation,
					raw->data.keyboard.Message,
					raw->data.keyboard.VKey);
			}			
		}
		delete[] lpbBuffer;
		return 0;
	}
	default:
		return DefWindowProc(hwnd, uMsg, wParam, lParam);
	}
	return 0;
}

效果图

 

 

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值