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
Related
I'm in the middle of adding custom Windows Touchpad handling into my Windows C++ desktop application. From a high level, the app has its own cursor and objects that can be clicked. The cursor needs to be directly controlled by a Windows Precision Touchpad, and completely decoupled from the standard Windows mouse. I'm accomplishing this via processing raw input from WM_INPUT messages, and using low level mouse hooks to prevent controlling the normal mouse pointer.
I'm able to interpret single and multi-finger gestures just fine using the WM_INPUT data, but haven't figured out how to get "clicks" or "taps" from the touchpad. Legacy Mouse Input events will obviously not work for my use case since they:
Aren't global and require my app to be focused
Are generated by any connected mouse/pointing device, not just the touchpad I registered for.
Interact at the location of the Windows mouse pointer, which is not driving the cursor in my app.
Are clicks/taps contained in the WM_INPUT reports, and I'm just not able to find them, or is there another way I can capture raw clicks from only the touchpad in my application?
RAWMOUSE struct that comes with WM_INPUT mouse message contains usButtonFlags with mouse button up/down transition state.
You cannot get clicks/taps because AFAIK classic Win32 API is not suitable for touch input at all - it just emulating mouse in case of touchpad.
According to touchpad spec all compatible Windows Precision Touchpad's are HID devices that are sending touchpad data in their Input Reports. They should contain corresponding Top Level Collection Page 0x0D (Digitizers), Usage 0x05 (Touch Pad) - and this will be seen as separate HID device from Win32 user-mode. See sample HID Report Descriptor.
Knowing this you can register to receive touchpad data with RegisterRawInputDevices call. After that you'll receive WM_INPUT message with RAWHID struct for each tounchpad input report - this needs to be handled manually (according to device's Preparsed HID Report Descriptor Data etc).
It's not easy but doable.
See example code here.
Update: Also there are WM_TOUCH and WM_GESTURE messages available since Windows 7. Maybe its what you're looking for. Sample code.
you can use PostMessage(applicationWinhandle, WM_INPUT, wparam, mouseDeviceHandle) send WM_INPUT message to your application, and then hook GetRawInputData or GetRawInputBuffer to send data.
Is there a way to determine whether the keyboard or mouse events are triggered from a hardware rather than an application like TeamViewer, Steam or some other remote desktop software in a desktop application running on Windows?
My purpose is not to prevent bots, but to prevent remote access to the application.
It seems that RawInput API lets me detect fake events sent using SendInput API. Is it correct?
The low-level keyboard/mouse hooks provided by SetWindowsHookEx() report if input was generated by actual devices or injected by application code.
For a low-level keyboard hook, the hook provides a pointer to a KBDLLHOOKSTRUCT structure, which has a flags member that contains a LLKHF_INJECTED flag for fake input.
For a low-level mouse hook, the hook provides a pointer to a MSLLHOOKSTRUCT structure, which has a flags member that contains either a LLMHF_INJECTED or LLMHF_LOWER_IL_INJECTED flag for fake input.
Either hook can return a non-zero value to block the input from being passed to the rest of the hook chain, and consequently to the target window.
Regarding the Raw Input API, according to (an older version of 1) the documentation for the GetRawInputDeviceInfo() function:
hDevice [in, optional]
Type: HANDLE
A handle to the raw input device. This comes from the lParam of the WM_INPUT message, from the hDevice member of RAWINPUTHEADER, or from GetRawInputDeviceList. It can also be NULL if an application inserts input data, for example, by using SendInput.
1: the highlighted note has been removed in the current version of the documentation, I do not know why.
So, the hDevice that is reported by a WM_INPUT message will be NULL for fake input.
however, it is not possible to block input with the Raw Input API. You still need a low-level hook for that.
I have my own keyboard and an USB barcode scanner that works like a second keyboard.
I would like to use the main keyboard to control the computer (as you usually do) and the second keyboard (that is actually the barcode scanner) to log all the input into a file.
Is this possible to do?
The point is, I could be on the internet, word, excel or whatever. I would use the main keyboard to write to that processes while in the background the second keyboard (barcode scanner) could be at the same time writing but to a log file. The program that I could be using in the moment would never know about the second keyboard input.
Thanks, all suggestions are very welcome.
You can use the Raw Input API to monitor keyboard events before the OS processes them. The API will tell you which device is sending each event, so you can log events from just the scanner.
However, the Raw Input API does not allow you to block input, so to block the scanner's events from being processed as normal keyboard events, you would need to use SetWindowsHookEx() to setup a keyboard hook that dismisses the events.
However, SetWindowsHookEx() does not report which device is sending each event, so you will have to coordinate the two APIs manually. When Raw Input detects a keyboard event, set a flag based on which device the event came from. When the hook detects the cooresponding event, check the flag and dismiss the event if the flag indicates the scanner device.
See Combining Raw Input and keyboard Hook to selectively block input from multiple keyboards on CodeProject.
I want to send the mouse and keyboard input, which is recieved from android client, to games running on windows.
SendInput works for almost all games I have worked so far. But for SendInput to work the game must be a foreground window.
To solve that I used PostMessage(hwnd,...) with hwnd being handle to the game window. But this does not work if game is using DirectInput. That was solved by hooking GetDeviceState. Now another game I started working on is using WM_INPUT or raw input and I have to create raw input to make it work.
According to this MSDN Article
DirectInput is a set of API calls that abstracts input devices on the
system. Internally, DirectInput creates a second thread to read
WM_INPUT data, and using the DirectInput APIs will add more overhead
than simply reading WM_INPUT directly.
directInput works using WM_INPUT.
The SendInput function inserts the events in the INPUT structures
serially into the keyboard or mouse input stream. These events are not
interspersed with other keyboard or mouse input events inserted either
by the user (with the keyboard or mouse) or by calls to keybd_event,
mouse_event, or other calls to SendInput.
So SendInput is also providing abstraction.
All I want is to send the input to application independently even when its window is not in focus. That way I will be able to send input to multiple games at once. Is there any way to achieve this using one higher level API call like SendInput? Can this be done with SendInput? Is there any C/C++ library for that?
When registering your input device using the RAWINPUTDEVICE structure,
set dwFlags = RIDEV_EXINPUTSINK to receive input when the process is in the background.
Example:
RAWINPUTDEVICE rid;
rid.usUsagePage = 1;
rid.usUsage = 4; // Joystick
rid.dwFlags = RIDEV_EXINPUTSINK;
rid.hwndTarget = window;
if (!RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE)))
return -1;
What is the fastest way to determine a key press and also how to determine if a key is being held? It appears that window messaging is slow. Please provide an example of how to do so, and why it is faster than an alternative.
To be clear, this for a real time loop (a simulation) so I am looking for the fastest way to determine if a key has been pressed and also to check to see if it is being held.
GetAsyncKeyState() is what you're looking for. It reads the physical state of the keyboard, regardless of the input queue state. If the high-bit is set, then the key was down at the time of the call.
// Fetch tab key state.
SHORT tabKeyState = GetAsyncKeyState( VK_TAB );
// Test high bit - if set, key was down when GetAsyncKeyState was called.
if( ( 1 << 15 ) & tabKeyState )
{
// TAB key down...
}
Also, for the record, Windows is not a real-time operating system. If your application requires real-time precision, you may want to select another platform.
If you just want to poll the keyboard state so as to discover which keys are up/down as well as the shift/alt/ctrl state, just call GetKeyboardState (MSDN reference).
When I worked in a game studio, this is exactly how we got keyboard state for each frame. Should be applicable to your simulation code.
TL;DR: you can use GetAsyncKeyState for checking if a key is currently down, but for best application responsiveness to key presses and releases, you want to use the Win32 pipeline code near the bottom of my post.
GetAsyncKeyState works perfectly fine for determining if a key is currently down, but in terms of determining whether a key was first pressed or released and how many times this was done, GetAsyncKeyState misses keystrokes in a CPU-intensive application, even after storing the previous key state.
This was what I tried:
static const unsigned int NumberOfKeys = 256U;
bool previousKeyboardState[NumberOfKeys];
//Get the current state of each key as the application starts to ensure that keys held down beforehand are not processed as pressed keys.
for (unsigned int keyNum = 0U; keyNum < NumberOfKeys; ++keyNum)
{
previousKeyboardState[keyNum] = isKeyDown(keyNum);
}
//Works fine.
bool isKeyDown(int key)
{
return (GetAsyncKeyState(key) & (1 << 16));
}
//Misses key presses when application is bogged down.
bool isKeyFirstPressed(int key)
{
bool previousState = previousKeyboardState[key];
previousKeyboardState[key] = isKeyDown(key);
return (previousKeyboardState[key] && !previousState);
}
//Misses key releases when application is bogged down.
bool isKeyFirstReleased(int key)
{
bool previousState = previousKeyboardState[key];
previousKeyboardState[key] = isKeyDown(key);
return (!previousKeyboardState[key] && previousState);
}
//Example usage:
if (isKeyDown(VK_W))
{
//W key.
}
if (isKeyFirstReleased(VK_SNAPSHOT))
{
//Print screen.
}
GetKeyboardState is no good either, as it does not keep track of the number of key presses or releases. As Erik Philips said in his answer, these are unbuffered solutions, which are no good if you are e.g. writing a game. You would have to process all keystrokes faster than they are received.
Now, my code above works decently well, and may be suitable for many people, but I much prefer not to miss a single keystroke. I hate using applications that are unresponsive. I think the best solution for Win32 applications is to catch WM_KEYDOWN and WM_KEYUP messages in the pipeline and process them. What's nice is that WM_KEYDOWN also provides an auto-repeat count, which could be useful for applications that support entering text (e.g. chat, IDE's, etc.). This also adds a slight complication, which is mentioned in the WM_KEYDOWN documentation:
Because of the autorepeat feature, more than one WM_KEYDOWN message
may be posted before a WM_KEYUP message is posted. The previous key
state (bit 30) can be used to determine whether the WM_KEYDOWN message
indicates the first down transition or a repeated down transition.
There are also Windows keyboard hooks you could look into, but those are more difficult to use. They're good for receiving global key presses though.
Considering that all inter-windows communications are through windows messaging (keyboard events, mouse events, pretty much all events you can imagine), there isn't a lower level way to access the keyboard events (unless you write your own keyboard driver) that I know of.
DirectX still uses the windows keyboard messaging to provide DirectX programmers easier access to keyboard events.
Updated
My note about DirectX was not to use it, but that when Microsoft wanted to make an interface for programmers to use for real time games, they still wrote DirectX on top of the Windows Message Queue.
I would suggest taking a look at how to write a program that can read directly from the message queue. I believe there is a good example Code Project Windows Message Handling - Part 1.
Your two options are to either read from the message queue (buffered) or read directly from the keyboard state (as Bukes states) which means your own loop could techinically miss a keyboard event for any number of reasons.