Skip to content

fix(emulation): restart input emulation after it failed - #525

Draft
minh-tg wants to merge 1 commit into
feschber:mainfrom
minh-tg:fix/emulation-restart
Draft

minh-tg wants to merge 1 commit into
feschber:mainfrom
minh-tg:fix/emulation-restart

Conversation

@minh-tg

@minh-tg minh-tg commented Oct 9, 2026

Copy link
Copy Markdown

Refs #193.

When input emulation fails, the emulation task logs input emulation exited: ... and waits for a request to enable it again. Only the GUI and the CLI (enable-emulation) send one, so emulation stays off until someone does it by hand. While it is off, the receiving side drops incoming events, and the sending side sees emulation_active = false and releases capture.

This starts emulation again after an error, with growing delays, and stops after a few attempts.

In #193 the maintainer wanted to avoid a loop that keeps re-enabling emulation and failing, for example when the compositor is gone, and said some sort of timeout makes sense for recoverable errors. A user suggested 1 s, 10 s, 30 s and then stop. The schedule below is in that spirit.

Behaviour

  • After a failed session, retry after 250 ms, 500 ms, 1 s, 2 s, 5 s, 10 s and 30 s, then stop. Stopping is today's behaviour: enable emulation by hand.
  • A request from the GUI or CLI skips the wait and starts the delays over.
  • The delays also start over after a session that ran for at least 10 seconds.
  • Nothing is retried after the user cancelled the permission prompt, or after exit was requested.
  • InputEmulationError::cancelled_by_user is new and public, because the check was only available inside input-emulation.

Choices

I picked a default for each. The alternatives are listed so the call can go the other way.

1. How long to keep trying

Pros Cons
Stop after the delays, about 48 s (default) Bounded. No unattended loop. Covers a stall or a compositor restart. A compositor that needs longer leaves emulation off. If the portal does not persist the permission, each restart can show the prompt again.
Retry every 5 s forever Recovers from anything eventually. Log noise. The permission prompt can keep coming back. A persistent cause keeps toggling capture on the sender.
Stop sooner (1 s, 10 s, 30 s) Fewer attempts. Less margin for a slow compositor restart.

2. A cancelled permission prompt

Pros Cons
Never retry (default) The user's answer is respected. No repeating dialog. The user has to enable emulation by hand if they change their mind.
Retry like any other error One rule for all errors. The dialog the user dismissed comes back.

3. What the GUI shows during retries

Pros Cons
No change (default) No new code. The status is always true, and the existing Reenable button works as "retry now". The status flips to Disabled and back to Enabled on each attempt.
Hide the Disabled status until retries are used up No flicker. The GUI says Enabled while emulation is off.
Add a "Retrying" status Accurate. Changes the IPC protocol and the GUI.

4. A refused SendInput on Windows (#516)

Pros Cons
Treat it like any error (default) No special case. While nothing succeeds, the delays limit it to about 7 off/on cycles. Each cycle makes the sender release capture. A session that ran over 10 seconds before the next refused event starts the delays over, so a cause that only fails on activity can toggle emulation each time.
Never retry this error No toggling. Manual enable after every time an elevated window had focus. Needs a typed error.
Drop the refused event and keep the session No toggling, no manual step. Changes #516. A silently dead cursor on the Windows machine.

Testing

Unit tests cover the delay schedule, and the wait: it ends after the delay, a request to enable ends it early, terminate ends it, and other requests are ignored. cargo fmt, cargo clippy --workspace --all-targets --all-features and cargo test --workspace pass.

The restart loop itself is not covered. It needs a backend that can be made to fail, and the dummy backend never fails. I have not tried it against a real compositor or on Windows.

Related and overlapping

When input emulation fails, the emulation task logs the error and waits
for a request to enable it again. Only the GUI and the CLI send one, so
emulation stays off until someone does it by hand, and the sending side
releases capture because the receiver reports emulation as disabled.

Start emulation again after 250 ms, 500 ms, 1 s, 2 s, 5 s, 10 s and
30 s, then stop and wait for a request as before. A request to enable
emulation skips the wait and starts the delays over, as does a session
that ran for at least 10 seconds before it failed.

Do not restart on its own when the user cancelled the permission prompt,
since the prompt would come back every time. Expose that check as
`InputEmulationError::cancelled_by_user`.

Refs feschber#193
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