March 19th, 2025

You can’t simulate keyboard input with PostMessage, revisited

A customer was trying to manipulate another program, so they tried posting messages to it. They found that input didn’t work reliably because the program had its own WH_KEYBOARD hook, and the posted messages weren’t triggering the hook, so the program saw input come in the message queue with no corresponding WH_KEYBOARD hook, and things got out of sync and didn’t work right. What’s going on?

What’s going on is that you can’t simulate keyboard input with PostMessage. Posting input messages is like prank calling the program. “Hello, this is (giggle) the input system? Yeah, and um (covers handset, whispers what should I say? back into handset), yeah the user hit the um, the Enter key? When? Um, like (other person whispers in their ear) 5 seconds ago? Yeah, okay, so like Enter key, got it? Cool, thanks.” How successful this is depends on how much the program allows itself to be fooled.

In this case, the program was correlating the input messages with information from another channel (the WH_KEYBOARD hook), and only keyboard input goes through the WH_KEYBOARD hook, because it is when a message is fetched from the input queue that the WH_KEYBOARD hook is called. Posted messages masquerading as keyboard input don’t come from the input queue; they come from the posted message queue. And the code that pulls messages from the posted message queue doesn’t call the WH_KEYBOARD hook.

As usual, the typical¹ answers are either to use UI Automation to drive the target program, or if the target program’s support for UI Automation is insufficient, you can use Send­Input to generate synthetic input. Synthetic input is treated like real input, and it goes through the input system like hardware input.¹

¹ An atypical answer is to use the target program’s object model if it offers one. For example, Microsoft Word lets you manipulate the application and its active document through its Application object.

² Synthetic input can still be detected, for example, by looking for the LLKHF_INJECTED flag in the KBDLLHOOKSTRUCT‘s flags.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

7 comments

  • Georg Rottensteiner

    Using UI Automation is the preferred method, obviously. However at least with .NET 8.0 Forms (and probably also 6.0) you can’t use it for everything. Clicking a button waits until the button handler returns. Which is unfortunate for automation, when the button click opens a modal dialog which you also want to control. This didn’t happen with an older version of Forms.

    These are the cases when I didn’t find anything better than using PostMessage to place a mouse click on the button and hope for the best.

  • 許恩嘉 · Edited

    You can’t simulate keyboard input with PostMessage perfectly. But there are indeed many programs that can be fooled by this trick.
    I once came across an application where I could simulate keyboard input via PostMessage only if it had keyboard focus.
    In order to simulate input to the application while it is in the background, I sent it a fake WM_SETFOCUS message, which successfully fooled it.

  • skSdnW

    SendInput takes an array so you can perform “atomic” up/down events etc. without it getting mixed with real user input that might be happening at the same time.

  • Sigge Mannen · Edited

    Keyboard hooks and SendInput takes me back in time, i wrote a little utility which took the selected text from any program and could list files and other things matching the text string.
    It used keyboard hooks to register a global hotkey, and i think SendInput was used to do Ctrl-C to put the selected text into Clipboard from where it was later read, although it might have been too brittle so it just resorted to read from Clipboard directly and it was up to the user to put it there.
    It also used Raymond's favourite AttachThreadInput function to be...

    Read more
  • LOST 4 days ago · Edited

    I know I can’t simulate keyboard input with PostMessage, and yet I still resort to trying to do so (with extra pains to simulate raw input and other fun bits like the mentioned here keyboard hooks). The reason? Windows does not provide a supported way to simulate input for programs that are not in the foreground. I can't run multiple programs in parallel and simulate input in each, unless they are cooperative. The only supported options that I can think of are prohibitively expensive: run each in its own VM (Windows license per program instance) or use Windows Server and...

    Read more
  • Piotr Siódmak 4 days ago

    I still have an application I wrote years ago that uses mouse_event. Now that I look at the documentation for mouse_event and keybd_event it says “This function has been superseded. Use SendInput instead.”. Should I update my application before a Windows update breaks it or is SendInput just a wrapper for those two functions or does it do something more? The documentation for SendInput mentions these two only in context of “These events are not interspersed with other (…)”.

    • alan robinson 3 days ago

      I still use keybd_event without problems on several Win10 machines. Much easier API than SendInput IMHO.