Skip to content

fix(windows): stop retrying SendInput forever when it is refused - #516

Open
minh-tg wants to merge 1 commit into
feschber:mainfrom
minh-tg:windows-bounded-sendinput
Open

minh-tg wants to merge 1 commit into
feschber:mainfrom
minh-tg:windows-bounded-sendinput

Conversation

@minh-tg

@minh-tg minh-tg commented Sep 29, 2026 •

Copy link
Copy Markdown

On Windows, SendInput returns 0 when it does not insert an event. That happens when UIPI
blocks it, for example while a window started as administrator has focus, or when another
thread blocked input. Microsoft documents that neither the return value nor GetLastError
says which one it was.

send_input_safe called SendInput in a loop until it returned non-zero. For as long as the
refusal lasted, the loop did not end. The daemon runs on a single-threaded runtime, so input
and IPC stopped, and so did the cleanup that releases held keys. The key repeat task had the
same loop.

Changes:

  • send_input makes one attempt and returns an error if it fails. Retrying in a loop would
    block the runtime again.
  • The error ends the emulation session like any other emulation error. Releasing held keys
    is attempted on the way out, but it goes through the same call and is refused too while the
    cause lasts, so held keys can stay pressed. Making release_keys continue past a refused release is a separate change.
  • The key repeat task logs the failure and stops repeating.
  • The README lists the limitation under Known Issues, including the held keys.

With an elevated window focused, the log now shows
input emulation exited: ... SendInput refused the event, and emulation stays off until it is
enabled again from the frontend. Before, the daemon froze.

I have not run this on Windows because I don't have a machine. CI compiles it. To check by hand:
run lan-mouse on Windows, focus a window started as administrator, send a key from the other
machine, and confirm the log line above and that emulation shows as disabled. Then enable it
again and confirm input works.

Related: #404 reports that Task Manager, which runs elevated, cannot be controlled and that input stops once it has focus. That may be this freeze. This change does not make elevated windows controllable. #373 proposes running as a Windows service, which would. #469 and #513 also edit windows.rs, so whichever merges second needs a rebase.

@minh-tg
minh-tg marked this pull request as ready for review September 29, 2026 09:08
@minh-tg

minh-tg commented Oct 2, 2026

Copy link
Copy Markdown
Author

CI is waiting for approval to run. Could a maintainer approve it when you have a moment? Thanks!

`send_input_safe` called `SendInput` in a loop until it reported
success. SendInput returns zero when the event is not inserted, because
UIPI blocks it (for example while a window with a higher integrity
level has focus) or because another thread blocked input. For as long as
that lasts, the loop never ended. The daemon runs on a single-threaded
runtime, so it stopped handling input and IPC, and the cleanup that
releases held keys could not run either. The key repeat task spun the
same way.

Make a single attempt and return an error when it fails. The error ends
the emulation session like any other emulation error. Releasing held
keys is attempted on the way out, but goes through the same call and is
refused too while the cause persists, so held keys can stay pressed.
Stop the key repeat task when its injection is refused, and note the
limitation in the README.
@minh-tg
minh-tg force-pushed the windows-bounded-sendinput branch from 10d9e92 to b3a7c6b Compare October 9, 2026 10:37
@minh-tg

minh-tg commented Oct 9, 2026

Copy link
Copy Markdown
Author

Reworked after a second look. The three immediate retries are gone because nothing changes
between them. The comment on the repeat task is corrected (the error does not reach the caller,
it is logged), and the DOC.md change is dropped because that file describes the architecture,
not individual backends. The README now documents the limitation instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant