需求:开发一款9键键盘DLL和演示程序,要求能控制灯亮、将9个键值映射为77001-77009。
固件:USB标准键盘0-9键值。
一些重要知识:
- 代码是在win10 64位系统下跑的,理应来说int占8个字节(64位),后来我想错了;我建立的工程是win32控制台应用,意味着编译器就是32位的–“int占多少个字节既由编译器决定,也由CPU或虚拟机或操作系统决定,但归根结底是由编译器决定。”
- char占1字节,short占 2 字节,int 、float、long 都占 4 字节,double 占8 字节,任意类型的指针都占4个字节
- 关于VS项目平台的x86,x64,Any CPU以及Debug和Release的区别
- 动态链接库构建的框架(生成和使用)
键盘open,根据键盘固件的PID、VID和版本连接键盘,并建立keyhook抓取键值的线程。功能稍微复杂。
BOOL OpenKeyboard(USHORT VendorID, USHORT ProductID, USHORT VersionNumber)
{
if((hDevHandle != INVALID_HANDLE_VALUE))
{
return FALSE;
}
SECURITY_ATTRIBUTES SecurityAttributes;
SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
SecurityAttributes.lpSecurityDescriptor = NULL;
SecurityAttributes.bInheritHandle = false;
DevInterfaceData.cbSize = sizeof(DevInterfaceData);
DevAttributes.Size = sizeof(DevAttributes);
HidD_GetHidGuid(&HidGuid);
hDevInfoSet = SetupDiGetClassDevs(&HidGuid,NULL,NULL,DIGCF_DEVICEINTERFACE|DIGCF_PRESENT);
MemberIndex = 0;
while(TRUE)
{
Result = SetupDiEnumDeviceInterfaces(hDevInfoSet,
NULL,
&HidGuid,
MemberIndex,
&DevInterfaceData);
if (Result == FALSE)
{
break;
}
MemberIndex++;
Result = SetupDiGetDeviceInterfaceDetail(hDevInfoSet,
&DevInterfaceData,
NULL,
NULL,
&RequiredSize,
NULL);
pDevDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(RequiredSize);
if (pDevDetailData == NULL)
{
SetupDiDestroyDeviceInfoList(hDevInfoSet);
return FALSE;
}
pDevDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
Result = SetupDiGetDeviceInterfaceDetail(hDevInfoSet,
&DevInterfaceData,
pDevDetailData,
RequiredSize,
NULL,
NULL);
MyDevPathName = pDevDetailData->DevicePath;
free(pDevDetailData);
if (Result == FALSE)
{
continue;
}
hDevHandle = CreateFile(MyDevPathName,
0,//GENERIC_WRITE,//GENERIC_READ|,//只有0值时有效
FILE_SHARE_READ |FILE_SHARE_WRITE,
&SecurityAttributes,
OPEN_EXISTING,
0,//FILE_FLAG_OVERLAPPED, //只有使用同步模式有效
NULL);
if (hDevHandle != INVALID_HANDLE_VALUE)
{
DevAttributes.Size = sizeof(DevAttributes);
Result = HidD_GetAttributes(hDevHandle, &DevAttributes);
PHIDP_PREPARSED_DATA PreparsedData;
Result = HidD_GetPreparsedData(hDevHandle, &PreparsedData);
HidP_GetCaps(PreparsedData, &Capabilities);
HidD_FreePreparsedData(PreparsedData);
if (Result == FALSE)
{
continue;
}
if ((DevAttributes.VendorID == VendorID) && (DevAttributes.ProductID == ProductID) && (DevAttributes.VersionNumber == VersionNumber))
{
//创建读线程,开始获取键盘的值存放到队列。
//————————————————————————————————————————————
StartKeyHook();
//————————————————————————————————————————————
SetupDiDestroyDeviceInfoList(hDevInfoSet);
return TRUE;
}
}
}
SetupDiDestroyDeviceInfoList(hDevInfoSet);
return FALSE;
}
BOOL StartKeyHook()
{
g_hKBHookThread = CreateThread(0, 0, KeyboardThread, 0, 0, &g_nKBHookThreadId);
return TRUE;
}
DWORD CALLBACK KeyboardThread(PVOID param)
{
MSG msg;
// set low-level keyboard hook
// if (!IsDebuggerPresent())
// {
// install the hook for *this* thread, even though it is a systemwide/global hook
g_hKeyboard = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, GetModuleHandle(0), 0);
// }
// pump messages to stop console from locking up
while (GetMessage(&msg, 0, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// remove the hook just before we exit
UnhookWindowsHookEx(g_hKeyboard);
return 0;
}
LRESULT CALLBACK KeyboardProc(
int code,
WPARAM wParam,
LPARAM lParam
)
{
//CString csMsg;
//csMsg.Format(_T("KeyboardPro code=%d"),code);
//AfxMessageBox(csMsg);
if (code == HC_ACTION)
{
KBDLLHOOKSTRUCT *Key = (KBDLLHOOKSTRUCT *)lParam;
if (!(Key->flags & LLKHF_UP))//
{
switch ((Key->vkCode & 0xff))//
{
case '1':
dwKeyValue = 77001;
return TRUE; //屏蔽该值;
case '2':
dwKeyValue = 77002;
return TRUE; //屏蔽该值
case '3':
dwKeyValue = 77003;
return TRUE; //屏蔽该值
case '4':
dwKeyValue = 77004;
return TRUE; //屏蔽该值
case '5':
dwKeyValue = 77005;
return TRUE; //屏蔽该值
case '6':
dwKeyValue = 77006;
return TRUE; //屏蔽该值
case '7':
dwKeyValue = 77007;
return TRUE; //屏蔽该值
case '8':
dwKeyValue = 77008;
return TRUE; //屏蔽该值
case '9':
dwKeyValue = 77009;
return TRUE; //屏蔽该值
default:
dwKeyValue =0;
break;
}
}
}
return CallNextHookEx(g_hKeyboard, code, wParam, lParam);
}
键盘close,即关闭键盘,关闭devhandle并结束抓取keyvalue的线程。
函数CloseKeyboard:
BOOL CloseKeyboard()
{
if (hDevHandle == INVALID_HANDLE_VALUE)
{
return FALSE;
}
if (!CloseHandle(hDevHandle))
{
return FALSE;
}
else
{
//结束线程
StopKeyHook();
hDevHandle = INVALID_HANDLE_VALUE;
return TRUE;
}
}
键盘灯控制,设一个变量dwSettings[unsigned long int(DWORD)],其中每一比特位0/1对应着灭/亮。用一个字节,2个8位。
9 | |||||||
---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
函数SetKeyLight:
MYLIBDLL BOOL SetKeyLight(DWORD dwSettings)
{
USHORT usFeatureReportByteLength;
BYTE CommandBuffer[100];
if (hDevHandle == INVALID_HANDLE_VALUE)
{
return FALSE;
}
usFeatureReportByteLength = Capabilities.FeatureReportByteLength;
CommandBuffer[0] = 0x00;
CommandBuffer[1] = BYTE(0xFF&dwSettings);
CommandBuffer[2] = BYTE((0x0100&dwSettings)>>8);
CommandBuffer[3] = CommandBuffer[1]+CommandBuffer[2];
return HidD_SetFeature(hDevHandle, CommandBuffer, usFeatureReportByteLength);
}
键值抓取,设一个参数dwTimeout[unsigned long int(DWORD)],执行抓取动作直到过时,返回tempKeyValue作为转换后的值。
函数SetKeyLight:
MYLIBDLL DWORD GetKeyValue(DWORD dwTimeout)
{
DWORD tempKeyValue=0;
DWORD i;
DWORD timeOut=0;
timeOut = dwTimeout / 10;
if (hDevHandle == INVALID_HANDLE_VALUE)
{
return 0;
}
for (i = 0; i < timeOut; i++)
{
if (dwKeyValue == 0)
{
Sleep(10);
}
else
{
tempKeyValue = dwKeyValue;
dwKeyValue = 0;
break;
}
}
return tempKeyValue;
}
这个函数非常简单,即等到timeout后将获取到的最后一个键值(dwKeyValue)返回。
其中dwKeyValue是在键盘open到键盘close的整个过程不断获取的。
在外面做一个简单的调用demo就可以使用了。
打开键盘: