Skip to content

A hardware keyboard and trackpad on the device: keys without the Keyboard button, Esc, scrolling (#67, #68) - #80

Merged
Saffsanity merged 16 commits into
mainfrom
hardware-keyboard
Oct 15, 2026
Merged

Saffsanity merged 16 commits into
mainfrom
hardware-keyboard

Conversation

@Saffsanity

@Saffsanity Saffsanity commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

Why

What

Device only: no wire change, nothing on the Mac changed. The plan, its eleven open questions with the defaults taken, and every result: docs/hardware-keyboard-plan.md.

  • Esc (ESC not passed through? #67). InputOverlayView has key commands for Esc with each of the sixteen combinations of ⌃, ⌥, ⇧ and ⌘ (wantsPriorityOverSystemBehavior, no title), only while it holds the keyboard and no EscapeKey is on screen in its own window, so the tour's, the pairing overlay's and the Settings panel's Esc still win while they show. Each Sill window is its own: Settings open in one window leaves Esc to the stream in another, and an EscapeKey's Esc goes to the newest one in the window it was pressed in (EscapeKey.onScreen(in:), fire(in:)). One key press is sent once whichever channel brings it (ForwardedKeys.commanded, pressed, released: the press first, the command sends nothing; the command first, the press no later than it is swallowed with its up). The Settings panel's Done now answers Esc through EscapeKey too (it keeps .cancelAction for ⌘.). Debug builds print a line for every hardware key and the channel it came by (hwkey: usage 41 down via keyCommand (shift): to the Mac); -SillKeyProbe 1 adds GameController's own view.
  • Keys without the Keyboard button (Two finger scrolling on Magic Keyboard trackpad, and allowing typing into text fields without needing to hit the keyboard button #68). HardwareKeyboardPolicy (new, pure, with its check): while a hardware keyboard is attached (GameController's coalesced keyboard) and nothing open takes the keyboard (Settings, pairing, the tour, the Apps list, the Menus pull-down), the input view holds the keyboard by itself: at a session's start, after a rotation or a reconnect, and when the last of those closes; it lets go while one is open and when the keyboard goes. That hold is never counted as the person's own: the Keyboard button stays dark, and the tour's busy and activity tests ignore it, so keyboard users still get the tour. Nothing is drawn during it (an empty input view, no shortcuts bar), so no on-screen keyboard comes up over the stream even where UIKit and GameController disagree. The Keyboard button keeps its meaning for the software keyboard: pressed over the hold it becomes the person's (iPadOS's own keyboard views come back), pressed again the software keyboard goes and keys still reach the Mac.
  • Trackpad and wheel scrolling (Two finger scrolling on Magic Keyboard trackpad, and allowing typing into text fields without needing to hit the keyboard button #68). Two scroll-only pans on the input view, a continuous one (a trackpad's two fingers: a phased gesture, then Sill's own coast, as a finger's) and a discrete one (a wheel: plain deltas), sharing the finger pan's path, in every layout that shows the picture.
  • Tests/keyrig (TEST ONLY, as Tests/duorig): a virtual HID keyboard and mouse inside a simulator of your own, so UIKit routes real key and scroll events. Its README has what it showed.
  • Docs: CLAUDE.md, docs/DEVELOPMENT.md, the checks' README, README's How it works, the support page (a keyboard with your iPhone or iPad), the App Store description's keyboard bullet and the next version's What's New. The public words say only what a device can be expected to do from the simulator's evidence: a keyboard types on the Mac as soon as the picture shows, without the Keyboard button. Esc and scrolling with a trackpad or a mouse are built, but no device has shown them, so their words wait for Noah's steps 1, 7 and 9 (the plan's "Words that wait for a device" has each line).

The review, fixed

An adversarial review of 2fc53ed re-ran every claim. Each finding was checked here against the code first, then fixed in a commit of its own:

  1. Esc and EscapeKey across Sill's windows (should-fix; bdc121d). EscapeKey.onScreen counted EscapeKeys in every window, so Settings, the tour, the pairing overlay or the Add a Mac card open in one window removed the stream's Esc key commands in every other, and fire() answered with the newest EscapeKey in any window. Now onScreen(in:) and fire(in:) take the window. Reproduced on a private iPad simulator (-SillSecondWindow 1 -SillSettings 1 -SillEscViaCommand 1, the key rig's Esc then "a"): before, Esc was handed on and the host got only the "a"; after, via keyCommand (none): to the Mac and the host got key 53 down and up.
  2. Public words beyond what a device has shown (nit; af9f13c). README.md (public on merge), the support page, the App Store bullet and the next What's New promised Esc and trackpad scrolling; they now keep to typing without the Keyboard button, and the fuller lines wait in the plan. CLAUDE.md's "a pan gets no momentum events" is now a simulator observation.
  3. The support page's Keyboard button (nit; af9f13c): "It brings up your device’s keyboard bar, and from there the on-screen keyboard."
  4. Full Keyboard Access and Switch Control (nit; 7fdc902): with a keyboard attached the hold puts Tab, Space and the arrows on the Mac and the Keyboard button never lets go for good (toggled()), so the plan has open question 11 (default: the hold as for anyone; UIKit can tell Switch Control, not Full Keyboard Access) and step 13 for Noah.

And the two claims that did not hold: this pull request now says Towards #68 (no real trackpad's events reached the continuous pan); and run-all.sh's protocol check has a p = 0.001 statistical case ("digits uniform", StreamProtocol's pairing-code generator, not touched here) that failed once for the reviewer and passed alone. Here, on 7fdc902, run-all.sh passed all 41 at the first run.

Verified

Before the review (2fc53ed and earlier; the plan's Results):

  • Tests/checks/hardware-keyboard (new): 51 checks and 20,000 random sessions (690,353 events) against six invariants; 31 of 31 mutants caught; added to CI's mutants matrix.
  • Tests/checks/key-strokes: 347 checks (329 before, 18 new, Esc's key command among the random sessions' keys); 81 of 81 mutants (9 new).
  • The iOS app, Debug and Release for the generic simulator and Debug for a generic device (CODE_SIGNING_ALLOWED=NO), and swift build -c release: main's warnings only.
  • Harness photos, this branch against main's build on the same private simulators: 19 of 19 identical pixel for pixel (iPad 1000×710 with the drawer, Settings, the lit Keyboard button, the Menus pull-down open; 710×1000; 500×710; the Duo's book and laptop poses and cover; the iPhone's arrangement upright and sideways; the connect screen).
  • Live on private simulators against SillHost --synthetic on loopback (software encoder, its input log), with keys and wheels from Tests/keyrig: Esc, typed text, ⌘W (key 13 with command; Sill's window stayed) and F5 reached the Mac with no Keyboard button; on an iPhone, after a turn sideways and back too; Esc, ⇧Esc, ⌘Esc and ⌥⌘Esc through UIKit's key-command dispatch with their flags; with Settings open Esc closed it and nothing reached the Mac, then keys flowed again; the tour showed with a keyboard attached, a key during it reached nothing, Esc skipped it; a keyboard going let the hold go and its return took it back; on a fresh iPhone the Keyboard button brought the software keyboard up and took it down as main's does; one, two and one wheel notches gave 1, 2 and 1 scrolls.
  • The touch rig: 72 of 72 against main's surfaces. CI's Build and check passed on 807c8ef and 2fc53ed.

After the review (on 7fdc902; the commit after it is docs only):

  • The iOS app (Xcode 27.1, 27A9275) Debug and Release for the generic simulator and Debug for a generic device, CODE_SIGNING_ALLOWED=NO, from new derived data: each succeeded (22, 38 and 18 s) with only the StreamClient.swift:3430 capture warning and appintentsmetadataprocessor's note. The Release binary holds none of the DEBUG strings (the new escape: lines included) and links GameController.
  • swift build -c release from git archive of 7fdc902: complete in 43.4 s, only the CaptureProbe warning.
  • Tests/checks/run-all.sh: all 41 passed at the first run (347 s; hardware-keyboard 51 checks, key-strokes 347, protocol ALL PASS). No check compiles a file the review changed (AddMacCard.swift, InputOverlay.swift, ContentView.swift), so the mutants were not run again: 31 of 31 and 81 of 81 stand.
  • The touch rig, whose stub follows onScreen(in:): 72 scenarios on main's surfaces and on this branch's, compare.py 72 checks, 0 failed.
  • CI's Build and check passed on 7fdc902 (run 38498602356: swift build -c release in 51 s, run-all.sh all passed with hardware-keyboard's 51 and key-strokes' 347, the iOS app on Xcode 27.1 27A9269 with only the StreamClient capture warning) and on the head 46b208c (run 38499812932).
  • Live on a private iPad Pro 13-inch (M5) simulator (iOS 27.0) against loopback SillHost --synthetic: the two-window case above, before and after; a tour in each of two windows, then Settings opening in the one behind: Esc in the front window closed its own tour and left the other window's EscapeKey alone (1 in other windows, left alone); in one window, Esc closed Settings with nothing at the host, then Esc and "a" reached it; the tour showed 1.10 s after the picture with the keyboard attached, a key during it reached nothing, Esc skipped it, then keys reached the host; Esc, ⇧Esc and ⌥⌘Esc through the key command (-SillEscViaCommand 1), key 53 with each one's flags; -SillInputTest 1's Esc, ⇧Esc and scrolls (104 scroll events); the harness's Add a Mac card closed on Esc. No screen changed, so no harness photos were taken again. The simulators are deleted.

Untested, for Noah

On the iPad with a Magic Keyboard, a Debug build (the console's hwkey:, escape: and keyboard: lines), streaming a window; the plan's "Untested, for Noah" has each step:

  1. Esc reaches the Mac, and which channel brought it (hwkey: … via pressesBegan or via keyCommand; with -SillKeyProbe 1, if only via GameController comes, the next fix is a GameController path).
  2. Esc in iTerm2's vim, zsh's vi mode and Zed's vim mode; Control-[ in each.
  3. Typing right after connecting, after a turn, after Settings, Menus, the Apps list and Pair This iPad… close, and after a reconnect, with no Keyboard button.
  4. ⌘W closes the Mac's window, not Sill's.
  5. No on-screen keyboard or shortcuts bar over the stream, and none popping up when the keyboard is folded away or taken off.
  6. The Keyboard button with the keyboard attached: lit, iPadOS's own keyboard views; again, dark, typing still reaches the Mac.
  7. Esc closes Settings, skips the tour, cancels pairing, with nothing sent to the Mac.
  8. The tour on a fresh install (or -SillTourState fresh) with the keyboard attached.
  9. Two-finger trackpad scrolling over the picture (any double coast), and a mouse's wheel, one notch included.
  10. VoiceOver unchanged.
  11. An input method's candidates (none drawn during the hold; the Keyboard button brings iPadOS's views back).
  12. Two Sill windows side by side (Split View or Stage Manager), each streaming: Settings open in one, Esc in the other reaches the Mac and Settings stays open; Settings open in both, Esc closes only the window's own.
  13. Full Keyboard Access, then Switch Control with a keyboard key as its switch: can Tab, Space and Esc (or the switch) still move through Sill's bar, Settings and Disconnect while the stream holds the keyboard? If not, open question 11's alternative is no automatic hold while one runs.

When steps 1, 7 and 9 pass, the words waiting in the plan go into README, the support page and the App Store text.

For the reporter (#67): Control-[ reaches the Mac as Control plus the [ key, which iTerm2, zsh's vi mode and Zed's vim mode take as Escape (untested on a device).

Towards #67 (a device decides which channel brings Esc, and the hwkey: lines say so). Towards #68 (a real trackpad's two-finger scroll, and whether iPadOS adds a second coast, need a device).

🤖 Generated with Claude Code

Saffsanity and others added 11 commits October 14, 2026 07:45
#68)

Esc through a priority key command beside pressesBegan, one key press sent once;
hardware keys forwarded whenever a keyboard is attached (HardwareKeyboardPolicy,
a pure rule with its check), never the person's own action for the tour's rule;
trackpad and mouse-wheel scrolling over the stream. Open questions with the
defaults taken, and the test plan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mand, trackpad scrolling (#67, #68)

A hardware keyboard holds the keyboard by itself (#68). HardwareKeyboardPolicy
(pure, Tests/checks/hardware-keyboard: 51 checks, 20,000 random sessions against
the invariants, 31 of 31 mutants; in CI's mutants matrix): while GameController's
keyboard is attached and nothing open takes the keyboard (Settings, the pairing
overlay, the tour, the Apps drawer, the Menus pull-down), the stream's input view
takes it at a session's start, after a rotation or a reconnect, and when the last
taker closes, so keys and text reach the Mac without the Keyboard button; it lets
go when the keyboard goes. The hold is never the person's own: the Keyboard
button stays dark and the tour's busy and activity tests ignore it, so keyboard
users still get the tour. The button keeps its meaning for the software keyboard
(over the hold: the person's; again: back to the hardware keyboard's, the
software keyboard gone, keys still going). InputOverlayProxy owns the rule and
does what it answers; while the hold is the hardware keyboard's the input view
is an empty view with no assistant groups, so nothing is drawn over the stream
even where GameController and UIKit disagree (the iOS 27 iPhone simulator:
GameController counts its HID keyboard, UIKit still shows the software keyboard).
HardwareKeyboardMonitor reads GCKeyboard; DEBUG -SillHardwareKeyboard 1|0 and
-SillKeyProbe 1.

Esc through a priority key command, sent once (#67): InputOverlayView has Esc
key commands (each combination of ctrl, option, shift and command,
wantsPriorityOverSystemBehavior) while it holds the keyboard and no EscapeKey is
on screen. ForwardedKeys.commanded/pressed/released send one key press once
whichever channel delivers it (the press first: the command sends nothing; the
command first: the press no later than it is swallowed, with its up).
key-strokes: 347 checks (18 new; key commands in the random sessions), 81 of 81
mutants (9 new). DEBUG: an hwkey line for every hardware key and its channel,
-SillEscViaCommand 1. The Settings panel closes on Esc through EscapeKey (Done
keeps .cancelAction for cmd-period).

Trackpad and mouse-wheel scrolling over the stream (#68): two scroll-only pans,
continuous (a gesture, then Sill's coast) and discrete (plain deltas), sharing
the finger pan's path; a pointer scroll's first event and a lone wheel notch are
sent (in the simulator a wheel's pan began and ended at 3 pt with no change).

DEBUG: the input test's overlay part, the input script's esc, scroll, wheel,
keyboard attach|detach and orient, -SillTurnAt. The touch rig compiles the new
rule and stands in for EscapeKey.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…EST ONLY)

Key presses, pointer moves and wheel scrolls posted from a virtual HID device
inside a simulator of your own (HID.framework's HIDVirtualEventService, as
Tests/duorig posts the Duo's hinge; never on the Mac), so UIKit routes them as
a real keyboard's and mouse's: pressesBegan, key commands, the text system,
GameController, hover and scroll pans. run.sh build | UDID keys SPEC | UDID
point SCRIPT. Its README has what it showed on iOS 27.0 simulators: every
simulator's GameController counts its own keyboard while UIKit may still show
the software keyboard (and counts a hardware keyboard once keys arrive); Esc
reaches pressesBegan and a priority key command fires only for a press handed
on; a wheel's pan begins with its first notch and a lone notch has no change;
phased scrolls from a virtual mouse are discrete; momentum events never reach
a pan; iPadOS 27 refuses programmatic turns.

EscapeKey: a DEBUG line when it takes Esc, and its comment says what the
simulator now shows (it closed the Settings panel and skipped the tour with
nothing sent to the Mac).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CLAUDE.md's Current step entry and Layout and Build and run; the plan's
Results, Untested for Noah and Progress; docs/DEVELOPMENT.md (a section on
keyboards and trackpads, the harness's new flags, the key rig); the checks'
README (hardware-keyboard, key-strokes' counts); README's How it works; the
support page (a keyboard or trackpad with your iPhone or iPad, Control-[ in a
terminal); the App Store description's keyboard bullet (2,963 characters) and
the next version's What's New (247); the harness contract in ContentView.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d, for Noah to check

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uests

The plan's Progress and the Current step entry: CI's Build and check on 807c8ef (run 38489635350),
the private simulators deleted, and the merge order: the pull request merges into main without a
conflict; with #74, #75, #77, #78 and #79 it meets in the docs, and with #79 also in
StreamScreen.swift's DEBUG hooks (keep both).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…w of #80)

The review found that EscapeKey.onScreen counted EscapeKeys in every Sill window,
so Settings, the tour or the pairing overlay left open in one window removed the
stream's Esc key commands in every other window: on a device that gives Esc only
to the key command (#67's premise), Esc then went nowhere in the window in front.
Reproduced on a private iPad simulator against a loopback synthetic host
(-SillSecondWindow 1 -SillSettings 1 -SillEscViaCommand 1, the key rig's Esc):
before, "handed on" and no key 53 at the host; after, "via keyCommand (none): to
the Mac" and key 53 down and up.

It also found that EscapeKey.Anchor.fire() answered with the newest EscapeKey in
any window, so Esc in one window could close another window's panel. Now
EscapeKey.onScreen(in:) and fire(in:) take the window: the stream's input view
asks about its own window, and the command answers with the newest EscapeKey in
the window of the view controller UIKit hands it to (an EscapeKey's command sits
on its window's controller, so only a key pressed there reaches it). The DEBUG
"escape:" line says how many other windows' EscapeKeys it left alone.

Docs: the plan's design and Noah's two-window step, CLAUDE.md's entry,
DEVELOPMENT.md; the touch rig's stub follows the new signature.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The review found that README.md, public as soon as this merges, said Esc
reaches the Mac and a trackpad or a mouse scrolls, and so did the support page,
the App Store description's keyboard bullet and the next What's New, while no
device has shown either: in the simulator Esc came through pressesBegan, which
#67's iPad never used, and no real trackpad's events reached the continuous pan.
Those words now say only that a keyboard types on the Mac as soon as the picture
shows, without the Keyboard button; the plan's new "Words that wait for a
device" has each fuller line for when Noah's steps 1, 7 and 9 pass, and the
metadata doc points there (the description 2,899 characters, local-only 2,678,
the next What's New 138; with the waiting words 2,963, 2,742 and 247).

It also found that the support page said the Keyboard button "shows the
on-screen keyboard", where with a keyboard attached it brings up the keyboard
bar first: now "It brings up your device’s keyboard bar, and from there the
on-screen keyboard."

CLAUDE.md's "a pan gets no momentum events" is now what it was: a simulator
observation, with a device to decide whether iPadOS coasts too.
DEVELOPMENT.md says the key command and the trackpad's pan wait for a device.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…for Noah (review of #80)

The review found that the plan's Untested steps covered VoiceOver but not Full
Keyboard Access or Switch Control, which the automatic hold changes the most:
with a keyboard attached the stream's input view holds the keyboard whenever
nothing is open over the stream, so Tab, Space and the arrows go to the Mac and
Esc's commands ask for priority over the focus system, and the Keyboard button's
second press goes back to the hold (HardwareKeyboardPolicy.toggled(), checked
here) rather than letting go. Someone who moves through Sill's bar from the
keyboard may not reach Settings or Disconnect while streaming.

The plan gains open question 11 (default: the hold as for anyone until the
device step says otherwise; the alternative, no automatic hold while one runs:
UIKit has UIAccessibility.isSwitchControlRunning, and the iOS 27.1 SDK's UIKit
headers have no test for Full Keyboard Access, so for it the alternative is
Q1's) and step 13 for Noah; CLAUDE.md's entry says the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and CLAUDE.md

The plan's Results gain "The review (2026-10-14) and its fixes": the four
findings and the commit that fixed each, the two-window runs before and after
(2fc53ed's build sent no Esc to the host with Settings open in the window
behind; this build sent key 53; with a tour in each window, Esc closed the
front one's and left the other's alone), the one-window Esc cases again, the
two claims that did not hold ("Fixes #68", now Towards; run-all's flaky
protocol case), and the verification on 7fdc902: the three iOS builds from new
derived data and a clean swift build -c release with the known warnings only,
run-all.sh 41 of 41 at the first run, the touch rig 72 of 72, no mutants again
(no check compiles a file the review changed). Progress and "Not verified here"
follow; CLAUDE.md's entry gets a review bullet and its Verified bullet rewrapped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Saffsanity and others added 2 commits October 15, 2026 19:18
CLAUDE.md keeps both Current step entries, this branch's first; ci.yml's
mutants matrix and Tests/checks/README.md take every check; the App Store
metadata's next What's New draft has both paragraphs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
CLAUDE.md keeps every Current step entry, this branch's first; ci.yml's
mutants matrix and Tests/checks/README.md take window-restore too.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@addhumal

Copy link
Copy Markdown

Heads-up on the Xcode project file: this PR adds HardwareKeyboardPolicy.swift as A1000001000000000000AC01 / FC01, and #66 (Sill Viewer) adds ClientPlatform.swift under the same two IDs (with HEVCSampleFeed.swift at AC02 / FC02). Git merges both without a conflict, but whichever lands second leaves two files under one object ID, which breaks the project.

I've moved my own #93's KeyframeRecovery.swift, which used the same pair, to AC11 / FC11. As far as I can see, the IDs the other open PRs use are AA01–04, AB21–23, AC01–02, AC11, AC64, AD01, AD64, AE01 and AF01 (and their F… twins). So one of #80 and #66 needs a free pair, for example AC21 / FC21.

Saffsanity and others added 3 commits October 15, 2026 22:47
CLAUDE.md keeps every Current step entry, this branch's first, and both
paragraphs of the harness's arguments; README's How it works keeps the keyboard
sentence beside the iPhone bullet; the What's New draft has every paragraph;
StreamScreen's harness takes -SillTurnAt beside -SillAXDump and
-SillLargerPictureToggle.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Esc and scrolling with a trackpad or a mouse showed on the iPad through
Universal Control (the plan's Results), so README's How it works, the support
page, the App Store description's keyboard bullet and the next What's New take
the lines the plan held for them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Saffsanity
Saffsanity merged commit 3efa0c0 into main Oct 15, 2026
addhumal added a commit to addhumal/sill that referenced this pull request Oct 15, 2026
ashleigh-hopkins added a commit to ashleigh-hopkins/sill that referenced this pull request Oct 15, 2026
…FC21 and AC22/FC22: main's HardwareKeyboardPolicy.swift (Saffsanity#80) holds AC01/FC01, and two files under one ID break the project once both are in
ashleigh-hopkins added a commit to ashleigh-hopkins/sill that referenced this pull request Oct 15, 2026
…FC21 and AC22/FC22: main's HardwareKeyboardPolicy.swift (Saffsanity#80) holds AC01/FC01, and two files under one ID break the project once both are in
ashleigh-hopkins added a commit to ashleigh-hopkins/sill that referenced this pull request Oct 15, 2026
…both sides

ci.yml's mutants list and Tests/checks/README.md both sides' checks (key-strokes 348 and 82 with
the middle button's case); select() sets both `selecting` and main's missingPolls reset; the exit
stops every capture before restoreFits puts sized windows back and the displays go; StreamClient
takes Saffsanity#69's foreground rule through ClientPlatform (a Mac app is never in the background) and the
Mac viewer still never asks for the Desktop by itself; CLAUDE.md keeps both Current step entries.
Code-Tomato added a commit to Code-Tomato/sill that referenced this pull request Oct 18, 2026
… side

Main brought PRs Saffsanity#74, Saffsanity#75, Saffsanity#77, Saffsanity#78, Saffsanity#79, Saffsanity#80, Saffsanity#85 and Saffsanity#98. 19 files
conflicted; each kept both sides whole.

- Wire: kind 32 (the clipboard) beside 43 (the sound); 29-31 and 33-42
  stay free for Saffsanity#66.
- Settings: shareClipboard beside sendAudio in HostConfig, the app's
  defaults, the CLI (--no-clipboard, --audio) and sillclient.py.
- Larger Picture (Saffsanity#79): row 1 holds Sound before Settings from 384 pt
  (PhonePortraitLayout.row1Beside); narrower, Sound is the panel's switch.
- Saffsanity#75: a regular-mode window that streams on off the catalog's list keeps
  its sound (StreamCoordinator.streamedPID); before, it stopped.
- Docs and check labels that still called 29 the audio plan's, or said 32
  was free, now say what the merged tree does.

Verified: swift build -c release; iOS Debug and Release for the generic
simulator (only the known StreamClient warning); the CLI's CI paths;
Tests/checks/run-all.sh, all 47; the mutants of the 25 checks that compile
a file both sides changed, 936 of 936 caught.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Saffsanity added a commit to kyleparisi/sill that referenced this pull request Oct 19, 2026
Main moved on since this branch began at 985a733, to d1fa97e (Saffsanity#85, Saffsanity#74,
Saffsanity#77, Saffsanity#75, Saffsanity#79, Saffsanity#80, Saffsanity#78, Saffsanity#98, Saffsanity#153 and Saffsanity#142). None of them touched
Sources/SillHost/VirtualDisplay.swift, so the merge is clean and this pull
request's change applies to main as it is now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Saffsanity added a commit to ipavlidakis/sill that referenced this pull request Oct 19, 2026
Main moved on since this branch began at 985a733, to d1fa97e (Saffsanity#85, Saffsanity#74,
Saffsanity#77, Saffsanity#75, Saffsanity#79, Saffsanity#80, Saffsanity#78, Saffsanity#98, Saffsanity#153 and Saffsanity#142). None of them touched
Scripts/make-app.sh, so the merge is clean and this pull request's change
applies to main as it is now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HunterAhlquist pushed a commit to HunterAhlquist/sill that referenced this pull request Oct 19, 2026
… as a pen

Hunter Ahlquist's five commits (issue Saffsanity#81), from main at 985a733, merged as
they are onto main at d1fa97e and the stale-hover commit before this one.
Eighteen files conflicted; every resolution keeps both sides:

- StreamMessage: main's clipboard (32), then the pen (still 29 here).
- Switcher: WindowList keeps `clipboard` and gains `pencil`; one init with
  both parameters, and the coordinator's list sends both.
- InputOverlay: main moved the finger pan onto the scroll path it shares
  with the iPad's trackpad and a wheel (Saffsanity#80); the palm guard stays in
  handlePan, before scroll(gesture, .finger), so it silences fingers only.
  The view's leave as it goes sits beside main's keyboard proxy. The
  stale-hover flag of the commit before gives way to PenStrokes.hover, the
  same rule in both modes (gone() resets it as the view leaves the window).
- StreamClient, MockCatalog, HostSettingsPanel, ContentView, sillclient.py:
  the clipboard's lines and the Pencil's side by side (the This iPad group
  has Larger Picture, Share Clipboard, the gestures, then Pencil Pressure;
  -SillInputScript has Saffsanity#80's steps and the pen's; --copy and --pen).
- The checks: compatibility runs main's clipboard cases and the pen's, its
  mutants follow the new init; protocol and pointer-control list both; the
  README's rows and ci.yml's mutants matrix gain `pen`.
- docs/DEVELOPMENT.md: main's hardware keyboard and clipboard sections, then
  Apple Pencil; site/privacy.html and CLAUDE.md likewise.

Left for the commits after this one: the pen's kind 29 is a number main's
clipboard, compatibility, protocol and pointer-control checks keep free
(they fail on it here), PenStrokes.swift's project IDs AC01/FC01 are
HardwareKeyboardPolicy.swift's since Saffsanity#80 (the iOS app does not build here),
and the workspace file comes back. swift build -c release passes here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HunterAhlquist pushed a commit to HunterAhlquist/sill that referenced this pull request Oct 19, 2026
The fork gave PenStrokes.swift A1000001000000000000AC01 and …FC01, free on
985a733; Saffsanity#80 has since given the same pair to HardwareKeyboardPolicy.swift
on main. The project file merges without a conflict but then holds each ID
twice, xcodebuild keeps one ("Skipping duplicate build file"), and the iOS
build fails on HardwareKeyboardPolicy. A045/F045 (after the pen's kind) are
in no project file on main or in any open pull request's head, checked
against all of them today. CLAUDE.md's Layout line names the new pair.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HunterAhlquist pushed a commit to HunterAhlquist/sill that referenced this pull request Oct 19, 2026
…s rebase

Hunter's branch carried a 56-line Current step entry written for his fork
(its "the owner" meant him, and its numbers were the fork's); every other
open pull request edits the top of that section too, so the entry is now a
short one in the section's usual form: what the branch is, the wire, the
host, the device, what the maintainer's commits after the merge did, what
was verified, and what waits for a device. The details stay where they were
already: the plan, the Layout lines and Build and run. PenProbe's line in
Build and run says a person runs --post-to-this-mac by hand at the Mac,
never an agent (it said "the owner's to run").

docs/pencil-pressure-plan.md gains "Rebased onto main (2026-10-20)": the
order of the branch (the stale hover on main's mouse path first, Hunter's
five commits merged as they are, the maintainer's commits, main again), the
merge's resolutions (WindowList's one init with both `clipboard` and
`pencil`, the palm guard in handlePan before Saffsanity#80's shared
scroll(gesture, .finger), the stale-hover flag giving way to
PenStrokes.hover), kind 45 and the checks it touched, the project IDs, the
workspace file, the site's markers, and what was verified with its numbers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

2 participants