I'm working on an application that uses Window's window and raw input APIs.
I can get input without too much difficulty and right now I'm trying to detect when devices are connected or disconnected from the application. To do so I'm listening to WM_INPUT_DEVICE_CHANGE and using GetRawInputDeviceInfo() to fetch device information.
My current issue is that, when having a mouse and keyboard connected, the OS detects three devices: two keyboards and a mouse. The mouse works fine but, due to having two different keyboards, I can't identify which one is actually the "main" one. When the mouse or keyboard are disconnected, one of the keyboard devices is removed. In order to have no keyboards, all devices must be disconnected.
Is there any simple way for detecting which keyboard is the "main" one? Or there isn't any concept of a "main" keyboard on this API?
Right now I have though the following "solutions":
First one would be to store the device handle when a key is pressed and keep it as the main keyboard but this sounds a bit "hacky".
Second one would be to try to differentiate the "main" keyboard based on number of keys. Issue is that this also seems a bit hacky as keyboard could vary in number of keys easily.
Although I don't deem it necessary, I'm providing a bit of code about how I'm checking connection and disconnection status for devices, just for completion.
// Read LPARAM from WM_INPUT_DEVICE_CHANGE and fetch the information.
HANDLE DeviceHandle = (HANDLE)LParam;
bool bIsConnected = WParam == GIDC_ARRIVAL;
if(!bIsConnected)
return;
// Get the device data.
RID_DEVICE_INFO DeviceInfoData;
UINT SizeData = sizeof(RID_DEVICE_INFO);
UINT DeviceResult = GetRawInputDeviceInfo((void*)LParam, RIDI_DEVICEINFO, &DeviceInfoData, &SizeData);
// Launch any callback based on device type read from dwType variable inside DeviceInfoData.
Many thanks :)
There is no such concept such as "main keyboard" in Windows API. All keyboard button presses are posted to message queue as WM_KEYDOWN/WM_KEYUP and WM_INPUT. With RawInput you can distinguish which keyboard sent particular input - but it is your decision which keyboard you want to hear (you can filter by keyboard handle for example).
Some mouse devices or USB mouse receivers can emulate HID keyboard for special things like macros or hotkey press etc. Thats probably why you're seeing second keyboard in a list.
Second one would be to try to differentiate the "main" keyboard based on number of keys. Issue is that this also seems a bit hacky as keyboard could vary in number of keys easily.
You cannot detect how many keys keyboard really have. RID_DEVICE_INFO_KEYBOARD
has same fake info for any HID keyboard.
You can look at my test code here for example how to differentiate devices.
Also note that in some cases device handle is not provided with WM_INPUT
. See details here.
UPDATE: If you're really want to detect number of keys that keyboard have - you can try to open keyboard device handle and use IOCTL_KEYBOARD_QUERY_EXTENDED_ATTRIBUTES IOCTL that may give you KEYBOARD_EXTENDED_ATTRIBUTES structure. Its PhysicalLayout field may have Keyboard Physical Layout (Usage ID: 0x2C3) value:
Value | Description |
---|---|
0x00 | Unknown Layout |
0x01 | 101 (e.g., US) |
0x02 | 103 (Korea) |
0x03 | 102 (e.g., German) |
0x04 | 104 (e.g., ABNT Brazil) |
0x05 | 106 (DOS/V Japan) |
0x06 | Vendor‐specific – If specified, VendorSpecificPhysicalLayout must also be specified. |
This will work only with some newer keyboards that are supporting HID Usage Table Review Request 42: Consumer Page Keyboard Assist Controls extension (HID Features 0x2C1-0x2C6 under Generic Desktop(Keyboard) Top‐Level Application Collection).
Here is my example code:
KEYBOARD_EXTENDED_ATTRIBUTES extended_attributes{ KEYBOARD_EXTENDED_ATTRIBUTES_STRUCT_VERSION_1 };
DWORD len = 0;
if (!DeviceIoControl(interfaceHandle.get(), IOCTL_KEYBOARD_QUERY_EXTENDED_ATTRIBUTES, nullptr, 0, &extended_attributes, sizeof(extended_attributes), &len, nullptr))
return; // keyboard do not support 0x2C1-0x2C6 HID features
DCHECK_EQ(len, sizeof(extended_attributes));
// extended_attributes.PhysicalLayout - will have keyboard layout type