设置全局键盘钩子和消息钩子

前几天因为工作需要用到钩子,而且是全局钩子,用来监视别人的程序键盘消息。需要注意几点
1.如果只需要监视自己的应用程序,在自己程序里设置钩子就行。
2.如果需要监视别人的应用程序,一定要做成DLL形式的全局钩子。
首先我是用VS新建一个DLL 工程。头文件如下

#ifndef __KEYHOOK_H_H
#define __KEYHOOK_H_H
	  
#ifdef MY_HOOK_API
#else
#define MY_HOOK_API _declspec(dllimport)
#endif
	  
 #ifdef __cplusplus
	 extern "C" {
		#endif 

			 MY_HOOK_API	 BOOL __stdcall Reg_raw_input(HWND hwnd);//注册输入信息,这个可以不要,因为自己工作的原因需要加上
			 MY_HOOK_API BOOL __stdcall  InstallHook();
		     MY_HOOK_API BOOL __stdcall  UnInstallHook();
		  
		#ifdef __cplusplus
			 }
 #endif 
 #endif

.CPP文件

自己使用RegisterRawInputDevices这个函数时有一个小问题卡了很久,用这个RIDEV_INPUTSINK标志时(即窗口不在前台时也台捕捉输入源信息),微软文档明确说明不用指定hwndTarget,试了很多次也不成功。然后直接有DLL用FindWindows找自己需要的句柄传给hwndTarget,还是返回失败,只有设置RIM_INPUT才可以,最后偶尔把上层应用的主窗口GetSafeWind()返回的句柄给hwndTarget时才成功。

BOOL __stdcall Reg_raw_input(HWND hwnd)
{
	static bool bReg_raw_input = false;
	if(bReg_raw_input)
		return FALSE;  
	RAWINPUTDEVICE dev;
	memset(&dev, 0, sizeof(dev));
	dev.usUsagePage = 1;
	dev.usUsage = 6;
	dev.dwFlags = RIDEV_INPUTSINK;
	//dev.dwFlags = RIDEV_INPUTSINK;//RIM_INPUT;//Shejn 2015/7/17 16:34:31 add
	dev.hwndTarget = hwnd;
	BOOL bReg = RegisterRawInputDevices(&dev, 1, sizeof(dev));
	bReg_raw_input = true;
	return bReg;
};

BOOL __stdcall  InstallHook()
{
	BOOL bRet = 1;
	UProductCmd cmd;
	bNewKey = cmd.IsUseKeyNewMap();
	_hHook_msg1 = SetWindowsHookEx(WH_GETMESSAGE, msg_hook_Proc1,g_hInst, NULL);//GetCurrentThreadId());最后一个参数为0表明监视所有线程而不是本身
	if (_hHook_msg1 == NULL)
	{
		bRet = 0;
	}
	g_hHook = SetWindowsHookEx(WH_KEYBOARD_LL,//这里使用底层键盘钩子,在键盘动产生作用前就响应,而且底层钩子比消息钩子先响应
			LowLevelKeyboardProc,
			g_hInst,
			NULL);
	if (g_hHook == NULL)
	{
		bRet = 0;
	}
	
	return bRet;
	//return g_hHook == NULL ? FALSE : TRUE;
}
  
BOOL __stdcall  UnInstallHook()
{
	UnhookWindowsHookEx(_hHook_msg1); 
	return UnhookWindowsHookEx(g_hHook);
}
  
BOOL WINAPI DllMain(IN HINSTANCE hDllHandle,
					IN DWORD nReason,
					IN LPVOID Reserved)
{
	//g_hInst = hDllHandle;
	//return TRUE;
	switch (nReason)
	{
	case DLL_PROCESS_ATTACH:
		g_hInst=HINSTANCE(hDllHandle);
		break;
	case DLL_THREAD_ATTACH:
		break;
	case DLL_THREAD_DETACH:
		break;
	case DLL_PROCESS_DETACH:
		//UnInstallHook();//这个要注释掉,后来发现如果监视的程序关掉,会直接调用这里,导致全局钩子失效,需要卸载钩子时在上层应用关闭时调用
		break;
	}
	return TRUE;
}

下面这段代码注意,如果是回车和空格互换,比如VK_RETURN变成VK_SPACE,keybd_event(VK_SPACE, 0 0, 0);似乎还会键盘钩子捕获到VK_SPACE,为了保险起见,最好设置一个标志,如果是第二个keybd_event产生,则直接return CallNextHookEx(g_hHook, code, wParam, lParam);  这点还没确认,高手可以去确认下。

DWORD dwIndex = 0;
BYTE g_bFreezeCAVK[2] = {VK_F2, VK_F8};
LRESULT CALLBACK LowLevelKeyboardProc(
	     int code,
	     WPARAM wParam,
	     LPARAM lParam)
{
	if(code == HC_ACTION)
	{
		
		PKBDLLHOOKSTRUCT pStruct = (PKBDLLHOOKSTRUCT)lParam;
		switch (pStruct->vkCode)
		{
		case VK_RETURN:	
			dwIndex = 0;
			break;	
		case VK_SPACE:
			dwIndex = 1;
			break;													  
		default:
			 bWork = FALSE;
			return CallNextHookEx(g_hHook, code, wParam, lParam);
		}

		if (wParam == WM_KEYDOWN)
		{
		  keybd_event(g_bVK[dwIndex], MapVirtualKey(g_bVK[dwIndex], 0), 0, 0);
		  return 1;//CallNextHookEx(g_hHook, code, wParam, lParam);//这里注意返回1是原按键无效,如果是CallNextHookEx则会断续传递还会产生原按键消息
               }
	}
	return CallNextHookEx(g_hHook, code, wParam, lParam);
}

 


//消息钩子,这段代码可以忽略,根据自己的需要来
LRESULT CALLBACK msg_hook_Proc1(int nCode, WPARAM wParam, LPARAM lParam)
{
	MSG* pMsg = (MSG*)lParam;
	if(nCode < 0)
		return CallNextHookEx(_hHook_msg1, nCode, wParam, lParam);

	if(pMsg->message == WM_INPUT)
	{
		HRAWINPUT hInput = (HRAWINPUT)pMsg->lParam;
		CString strDev_name = get_dev_name(hInput);
		
		UProductCmd cmd;
		CString strMini_kbd_id = cmd.get_setting("keyboard", "MiniKeyboardID", "Vid_04d9&Pid_1603");
		strMini_kbd_id.MakeLower();
		strDev_name.MakeLower();
	
		int aTest = strDev_name.Find(strMini_kbd_id);
		if(strDev_name.Find(strMini_kbd_id) >= 0  && bNewKey)//cmd.IsUseKeyNewMap())
		{
			_bHid = true;
		}
		else
		{
			_bHid = false;
		}
		//bWork = TRUE;
		if (bWork)
		{
			if(_bHid)
			{
				if (bFreeze)
				{
					keybd_event(g_bFreezeCAVK[dwIndex], MapVirtualKey(g_bFreezeCAVK[dwIndex], 0), 0, 0);
				}
				else
					keybd_event(g_bLiveCAVK[dwIndex], MapVirtualKey(g_bLiveCAVK[dwIndex], 0), 0, 0);
				//keybd_event(g_bCAVK[dwIndex], MapVirtualKey(g_bCAVK[dwIndex], 0), 0, 0);
				if (dwIndex == 0)
				{
					bFreeze = !bFreeze;
				}		
			}
			else
			{
				bKeep = TRUE;
				if (bNewKey)
				{
					keybd_event(g_bNewVK[dwIndex], MapVirtualKey(g_bNewVK[dwIndex], 0), 0, 0);
				}
				else
				{
					keybd_event(g_bOldVK[dwIndex], MapVirtualKey(g_bOldVK[dwIndex], 0), 0, 0);
				}
				
			}
		}
		bWork = FALSE;
	}	
	
	return CallNextHookEx(_hHook_msg1, nCode, wParam, lParam);
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值