Detecting Simulated Keyboard/Mouse Input

Detecting simulated keyboard/mouse input

I might be wrong, but the on-screen keyboard (and other applications that simulate user input) most probably uses the SendInput API:

SendInput operates at the bottom level of the input stack. It is just a backdoor into the same input mechanism that the keyboard and mouse drivers use to tell the window manager that the user has generated input.
Source: http://blogs.msdn.com/b/oldnewthing/archive/2010/12/21/10107494.aspx

So there is probably no way to tell whether the input is coming from a "real" keyboard or not.

Detect if keyboard or mouse events are triggered by a software

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.

How to tell real and virtual keypresses apart?

As it turns out the proper term for virtual key/mouse events is "injected" and the low level keyboard hook does provide a related flag in the KBDLLHOOKSTRUCT.

Now I modified the hook related event management so it lets through any events with the "LLKHF_INJECTED" flag, without suppressing or informing the main logic about it.

How to send hardware level keyboard input by program?

I once used SendInput to control a game character. Game (icy tower?) was using directx input system (I think?) and somehow it was ignoring keybd_event calls but this method worked. I do not know how close to hardware you need to be but did this the trick for me. I used virtual key codes but turned them into scancodes for this answer.

UINT PressKeyScan(WORD scanCode)
{
INPUT input[1] = {0};
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = NULL;
input[0].ki.wScan = scanCode;
input[0].ki.dwFlags = KEYEVENTF_SCANCODE;

UINT ret = SendInput(1, input, sizeof(INPUT));

return ret;
}

UINT ReleaseKeyScan(WORD scanCode)
{
INPUT input[1] = {0};
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = NULL;
input[0].ki.wScan = scanCode;
input[0].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;

UINT ret = SendInput(1, input, sizeof(INPUT));

return ret;
}

To simulate press and release you use them sequentially (or you may create a separate function for press and release that use same INPUT structure).

WORD scanCodeSpace = 0x39;
PressKeyScan(scanCodeSpace);
ReleaseKeyScan(scanCodeSpace)

You can use MapVirtualKeyA to get scan code from virtual key code.

Keyboard inputs in c without using a library that does everything for you

You will probably want to process the following two window messages in your message loop:

  • WM_KEYDOWN
  • WM_KEYUP

See the Microsoft documentation on Keyboard Input for further information.



Related Topics



Leave a reply



Submit