Skip to content

Release held modifiers before synthesizing the paste - #18

Merged
willkotheimer merged 1 commit into
mainfrom
paste-targeting
Sep 11, 2026
Merged

willkotheimer merged 1 commit into
mainfrom
paste-targeting

Conversation

@willkotheimer

Copy link
Copy Markdown
Owner

Unspooling advanced the spool and never pasted. This is why, and the fix.

The cause

A hotkey fires on the key down. So at the instant Spool's handler runs, the user is still holding Win+Alt — they have not let go of Win+Alt+U yet. Synthesizing Ctrl+V into that state delivers Win+Alt+Ctrl+V, which is a paste in no application on earth, so nothing happens.

It looked intermittent because a handler that happened to run after the keys came up worked perfectly. That is how it passed a round of testing: my own verification pressed the keys with a 60ms hold, short enough that the modifiers were often already up by the time the paste fired. A person holds them far longer.

The fix

The addon lifts every modifier currently down before pressing Ctrl+V:

const WORD kModifiers[] = {VK_LWIN,   VK_RWIN,   VK_LMENU,    VK_RMENU,
                           VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, VK_RCONTROL};

They are not restored afterwards. The user's own keys are still physically held, so their next release is harmless — whereas re-pressing Win here would open the Start menu.

Verified by holding the modifiers 700ms past the hotkey, which is what a person actually does. Three unspools in a row now deliver three clips in order, and paste-all delivers the joined spool.

Two things that follow from the report rather than the code

Pasting the whole spool now pastes. One key that pastes and one that silently changes the clipboard is an inconsistency, not a design — Win+Alt+V looked completely dead from the user's seat. The setting is renamed autoPaste to cover both placements, and still reads a settings file written under the old pasteOnServe name.

A paste that does not land says so, naming Ctrl+V as the way out. Windows refuses synthesized input to windows running as administrator, and some terminals paste with Ctrl+Shift+V. In those cases silence is exactly what makes a user conclude the app is broken, which is what happened here.

Unspooling while Spool's own window is in front now dismisses the window and pastes into whatever was behind it, rather than refusing in silence. A global hotkey does not steal focus, so this only arises when the user summoned Spool and has not clicked away — and then the only sensible target is what they were in before.

Verification

395 tests, typecheck, lint, and the zero-network gate pass. The two new tests cover the case that was silently wrong: a paste that fails must produce a notice, and one that succeeds must not.

Still to confirm: the same flow in the installed MSIX against a real editor, which is the configuration that originally failed.

Note

Conflicts with #17 are likely — both touch session.ts. Merge order is whichever you prefer; I will rebase the other.

🤖 Generated with Claude Code

Unspooling advanced the spool and never pasted. The cause is that a hotkey fires
on the key down, so when the handler runs the user is still holding Win+Alt.
Synthesizing Ctrl+V into that state delivers Win+Alt+Ctrl+V, which is a paste in
no application, and nothing happens. It looked intermittent because a handler
that happened to run after the keys came up worked fine, which is how it got
through a round of testing with a false pass.

The addon now lifts every modifier that is currently down before pressing Ctrl+V.
They are not restored: the user's keys are still physically held, their release
is harmless, and re-pressing Win would open the Start menu. Verified by holding
the modifiers 700ms past the hotkey, which is what a person actually does — three
unspools in a row now deliver three clips in order.

Two things follow from the report rather than from the code. Pasting the whole
spool now pastes as well, because one key that pastes and one that silently
changes the clipboard is an inconsistency rather than a design; the setting is
renamed autoPaste to cover both, still reading the old pasteOnServe key. And a
paste that does not land now says so and names Ctrl+V as the way out — Windows
refuses synthesized input to elevated windows and some terminals want
Ctrl+Shift+V, and in those cases silence is what makes a user conclude the app is
broken.

Unspooling while Spool's own window is in front now dismisses it and pastes into
whatever was behind, rather than refusing in silence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@willkotheimer
willkotheimer merged commit 6e7e258 into main Sep 11, 2026
2 checks passed
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