做了一个mfc的外挂程序,连接了多个扫描枪以及一个键盘,需要区分哪些内容是哪个设备输入的。
网上找了很多资料,大多是在扫描枪中设置前后缀,然后使用Hook回调函数获取键盘输入,再根据前后缀判断是哪一把扫描枪。一开始我这样实现,但是发现会有换设备就要重新设置前后缀和前后缀可能与输入内容有重复的问题。
后来发现在MFC中,PreTranslateMessage是虚函数,是用来截获消息的。我们可以通过重载它来处理键盘和鼠标消息,键盘消息会存放在一个缓存池中,缓存池的名字包含了vid,我们可以根据缓存池名字判断是哪个扫描枪输入,这种方法用到的是mfc的消息处理,比上面打方法CPU占用率小,实时性高,当然这种方法现在只适用于MFC。
代码如下:
//全局扫描枪数据
//int:第i把扫码枪
//string:扫码枪积累的字符
//DWORD:上一次接收扫码枪消息的时间 超过设置的timeout,清除
std::map<int, std::pair<std::string, DWORD>> g_scaner_data;
MainFrm.cpp
extern std::map<int, std::pair<std::string, DWORD>> g_scaner_data;
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{
// TODO: 在此添加专用代码和/或调用基类
if (pMsg->message == WM_INPUT)
{
{
UINT dwSize;
GetRawInputData((HRAWINPUT)pMsg->lParam, RID_INPUT, NULL, &dwSize,
sizeof(RAWINPUTHEADER));
LPBYTE lpb = new BYTE[dwSize];
if (lpb == NULL)
{
return 0;
}
if (GetRawInputData((HRAWINPUT)pMsg->lParam, RID_INPUT, lpb, &dwSize,
sizeof(RAWINPUTHEADER)) != dwSize)
OutputDebugString(TEXT("GetRawInputData doesn't return correct size !\n"));
int type = 0;
RAWINPUT* raw = (RAWINPUT*)lpb;
{
//为键盘设备名准备缓冲区大小
GetRawInputDeviceInfo
(raw->header.hDevice,
RIDI_DEVICENAME,
NULL,
&dwSize);
WCHAR stringBuffer[1024];
//将设备名读入缓冲区stringBuffer
GetRawInputDeviceInfo(raw->header.hDevice, RIDI_DEVICENAME, stringBuffer,
&dwSize);
std::string tmp = wideCharToMultiByte(stringBuffer);
//transform(tmp.begin(), tmp.end(), tmp.begin(), ::toupper);
//根据设备路径名称,区分扫码枪
if (tmp.find(VID) != std::string::npos)
{
type = 1;
}
LogNode *pMsgNode = NULL;
pMsgNode = new LogNode;
pMsgNode->FormatMsg(LOG_SHOE_AND_PRINT, Normal, CString(tmp.c_str()));
//::SendMessage(this->GetSafeHwnd(), WM_LOG_MSG, NULL, (LPARAM)pMsgNode);
if (type == 0)
{
//无关设备输入,忽略
delete[] lpb;
return 0;
type = 1;
}
}
//raw->header.hDevice
if (raw->header.dwType == RIM_TYPEKEYBOARD)
{
if (raw->data.keyboard.Message == WM_KEYDOWN)
{
char keytext[50] = { 0 };
BYTE state[256] = { 0 };
//通过虚拟键盘码得到名字
ToAscii(raw->data.keyboard.VKey, raw->data.keyboard.MakeCode, state, (LPWORD)keytext, 0);
/*if(! ((keytext[0] >= 'A'&&keytext[0] <= 'Z') || (keytext[0] >= 'a'&&keytext[0] <= 'z')))
{
delete[] lpb;
return 0;
}*/
/*if (g_scaner_data[type].first == ""&&keytext[0] != 's')
{
delete[] lpb;
return 0;
}*/
if (GetTickCount() - g_scaner_data[type].second > 2000)
{
//键盘消息超过两秒,自动清除
g_scaner_data[type].first = "";
}
std::string org_text = g_scaner_data[type].first;
g_scaner_data[type] = std::make_pair(org_text + keytext, GetTickCount());
}
}
delete[] lpb;
return 0;
}
}
else
return CFrameWnd::PreTranslateMessage(pMsg);
}