fix(app): held Control shortcuts, replays and hold ends deliver each key to its own terminal (P0 1193 follow-up)
Summary
Follow-up of #29301 (P0 1193, held keys during a pending creation). It fixes the low findings of #29301's independent review (receipt at 201b1e4c804) and one gap of the same class found while checking #29530's finding. All of them can send a key to a terminal other than the one it was typed for, or lose it.
- A held Control shortcut runs on the terminal it was typed for. Before, only Command chords of a lane whose terminal is not focused went through app dispatch; Ctrl-`, Ctrl-Tab and Ctrl-1..9 were typed into that terminal as bytes. Now every chord (Command or Control) runs with that terminal's tab as its target and its key context; a chord that is no app shortcut (Ctrl-C) stays that terminal's key.
- A replay keeps each key's own terminal. When a replayed key opened a new creation (a held Cmd-D),
prependgave every later key the new creation's lane, so a line held for another terminal ran in the new split. Now each key keeps its lane (HeldKeycarries it); only the issuing key's own lane moves to the new creation; keys carried into a new hold keep their terminal (adopted lanes). - A remote split's keys reach its machine. A split's held keys record the split pane's own machine (
daemon.machineID), not the window's, so the daemon path reaches a remote split whose view was evicted. - At a hold's end, a key runs "as typed" only into its own terminal. Before, the focused lane's keys ran again through
NSApplication.sendEventinto whatever had the keyboard, so a hold that ended at its bound while the terminal's view was out of the window (a remount) lost them. Now the end names a focused terminal only when its shown view has the keyboard (keyboardTerminal, the check the early view already used); otherwise the terminal's own encoder types the keys. (#29530's claim that the 2 s bound counts from the hold's start does not hold: a pending creation has no bound; the bound starts at the reply.)
Base: this PR is stacked on #29301's branch fix/p0-1193-key-lanes. After #29301 merges, its base moves to feat-cmux-next (no rebase).
Testing
SecondCreationKeysTests (CmuxNextAppTests, real same-tree daemon, display steps on the fleet, CMUX_TEST_REQUIRE_GUI=1, console session):
| Ref | What it is | Job | Result |
|---|---|---|---|
cb962cf53bd (fix/p0-1193-followup-red-base) | #29301's code 201b1e4c804 + these tests only | 43fa946541a7fd8f597a307d | 6 pass; 3 fail, each first on the outcome: test 7 "the held Ctrl-` opened no tab" (1); test 8 "the line typed for the second terminal ran in the new split" (2); test 9 "lost at the hold's end" (4) |
| bd1112a1cfa (this head) | the fix | 92b8615008f3941cdf53fa79 | 9 of 9 pass; HeldKeyInputTests 3 of 3 |
More reds for test 9 alone (only the hold-end fix taken back): 8141f17fd895332cac6f392a, e6197633b8b7838f3220b23e, f65f2f0a64d66bc7c8012bed. Compiles: head 6df16fb0dc239829df48219d, base red ref e39660a3bfcf30538a45bbe9.
Observed / Not run
Observed: the runs above, each log read before counting. An earlier test-8 failure on red and green alike was the test rig: its 20 s wait-for ran on the app's own daemon connection, whose requests run in order, and held back the split it waited for; the test now reads app state first.
Not run: finding 3 (remote split with an evicted view) has no test of its own (it needs a second machine); a journey round of the follow-up cases.
Performance
No perf numbers: a correctness fix. The added work runs only when a creation hold ends or a held key is replayed; no work moves onto the main thread outside those paths. perf claim: none.
Changelog
Fixed: Shortcuts and lines typed while new panes open no longer run in a pane other than the one they were typed for
Proof
No capture: key routing between terminals; the evidence is the fleet display tests above.
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes P0 1193 follow-up key-routing bugs so held shortcuts, replayed keys, and keys at a hold's end reach the terminal they were typed for instead of another terminal or no terminal at all.
- Held Control shortcuts (Ctrl-`, Ctrl-Tab, Ctrl-1..9) now run as app shortcuts on the terminal they were typed for; previously only Command chords did, and Control chords were typed into that terminal as bytes.
- A replayed key that opens a new creation keeps every later key on its own terminal; only the issuing key's lane moves to the new creation, and keys carried over from another hold keep their terminal.
- A remote split's held keys record the split pane's own machine, not the window's, so the daemon path reaches a split whose view was evicted.
- At a hold's end, a key runs "as typed" only when its terminal's view has the keyboard; otherwise the terminal's own encoder types it.
- A held chord with no app shortcut (Ctrl-C) stays in its terminal's typing run, so keys keep the order they were typed in even when the terminal's view is gone.
This PR is stacked on fix/p0-1193-key-lanes and moves to feat-cmux-next once #29301 merges.