<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[winput notes]]></title><description><![CDATA[winput notes]]></description><link>https://winputnotes.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sun, 15 Nov 2026 20:22:06 GMT</lastBuildDate><atom:link href="https://winputnotes.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[The worst thing an RPA bot can do on Windows is steal the mouse]]></title><description><![CDATA[One Go library, two input backends: quiet when it can be, forceful when it has to be.]]></description><link>https://winputnotes.hashnode.dev/the-worst-thing-an-rpa-bot-can-do-on-windows-is-steal-the-mouse</link><guid isPermaLink="true">https://winputnotes.hashnode.dev/the-worst-thing-an-rpa-bot-can-do-on-windows-is-steal-the-mouse</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Windows]]></category><category><![CDATA[automation]]></category><category><![CDATA[rpa]]></category><dc:creator><![CDATA[winput notes]]></dc:creator><pubDate>Sat, 07 Nov 2026 06:28:47 GMT</pubDate><content:encoded><![CDATA[<p>If you write desktop automation for a living, you already know this screenshot.</p>
<p>Excel is open. A person is in the middle of a cell. Your script is supposed to keep keying invoices into a crusty Win32 line-of-business app in the background, then click "Done" in Teams, Slack, or whatever Electron shell the company uses for ticketing.</p>
<p>That should be two quiet steps. With <code>SendInput</code> and libraries in the robotgo family, it becomes one loud one. The cursor jumps. The target window comes to the front. The value that person was about to paste lands in someone else's form.</p>
<p>Vendors call this "foreground automation." Another way to say it: you just mugged the operator.</p>
<p>So you switch to posting window messages. The old Win32 app suddenly behaves. No focus grab, no physical cursor, the operator may not even notice the bot. Then the same calls hit the Electron app and disappear. The window is right there. The click never happened. Games, Raw Input apps, and a lot of modern UI toolkits simply do not eat <code>PostMessage</code>.</p>
<p>That split is the everyday Windows RPA problem: the backend that can stay in the background cannot punch through stubborn windows; the backend that can punch through cannot stay in the background.</p>
<p><a href="https://github.com/rpdg/winput">winput</a> is built around that crack.</p>
<p>You think in windows, not raw HWNDs and scan codes. Find the invoice app, find the <code>Edit</code> child, <code>Click</code>, <code>Type</code>, press Enter. By default that path uses the message backend. The operator's mouse can stay in Excel. The docs are explicit: the message backend needs no focus and does not move the physical mouse.</p>
<p>Invoices done, now the Electron app. Keep the same calls, just flip the backend first:</p>
<pre><code class="language-go">if err := winput.SetBackend(winput.BackendHID); err != nil {
    // driver not installed: degrade loudly, don't pretend it worked
}
</code></pre>
<p>After that it is still <code>Click</code>, still <code>Type</code>. But nothing is going into the window queue anymore. You are injecting HID through the Interception driver, which is how the library talks to games, anti-cheat-ish input paths, and other windows that shrug at synthetic messages. Electron apps with unreliable HWNDs sit in that same bucket.</p>
<p>Someone will ask: if HID is stronger, why not use it for everything?</p>
<p>Because it isn't free. You have to install the driver. The real cursor moves. The window usually needs to be in the foreground. Run HID all day against that old invoice app and you have given "background" back. Message input is for not bothering people. HID is for windows that refuse to listen. The point of winput is not that one mode is cooler. It's that you don't write two automations for two kinds of windows.</p>
<p>The thing I've been tired of, writing RPA, is not a missing <code>Click</code> helper. It's a single flow that contains two window types, and a library that will only give me one mouth. One side says "we support background" and then only works on Notepad. The other says "we can drive games" and then the operator swears the first time they touch the mouse.</p>
<p>Wiring both to the same <code>Window</code> object sounds plain. That's what infrastructure is supposed to sound like.</p>
<p>It is not a master key. The message backend loses to UIPI, so a higher-privilege window still won't accept your posts. Modifier hotkeys that the target reads with <code>GetKeyState</code> may not look like real chords, and the library will temporarily fall back to foreground key events. HID is Windows-only and tied to Interception. All of that is in the docs. Don't ship as if you didn't read it.</p>
<p>But on the desk that actually shows up in RPA shops (legacy Win32 on one side, an Electron shell on the other, and a human who does not want their mouse stolen), dual backends are not a bonus feature. They're why the library exists.</p>
<p>Other tools make you choose: be quiet, or get through.</p>
<p>This one lets you finish the quiet work quietly, then grow a second set of teeth for whatever's left.</p>
]]></content:encoded></item></channel></rss>