Repository navigation
Add iPhone Duo support and fold controls - #179
Conversation
Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: Codex <[email protected]>
Read per-display corner geometry from the simulator profile and scale it to DeviceKit artwork. Keep asymmetric corners through clipping, resizing and rotation, and select the matching geometry when the active display changes. Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: Codex <[email protected]>
Rotate DeviceKit bezels and screen cutouts with native display readback, honor PDF page rotation for inner-display buttons, and use the Duo vendor orientation control. Preserve the toolbar request cycle when an app rejects a pose. Guard disconnected inner digitizers that crash backboardd. Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: Codex <[email protected]>
Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: Codex <[email protected]>
krystofwoldrich-agent
left a comment
There was a problem hiding this comment.
🤖 This is an automated review. Addressing it doesn't guarantee a merge.
Review: Add iPhone Duo support and fold controls
Verdict: REQUEST_CHANGES (posted as a comment: GitHub blocks request-changes from the PR author account)
Findings: 0 critical · 3 design · 4 suggestion · 4 nit
The PR adds a CoreDevice bridge for fold and orientation control, per-display Universal HID touch reports, active-display framebuffer selection, rotated DeviceKit chrome with per-corner radii, a hinge WebSocket command, and a hinge CLI. The Duo-specific work is careful and well tested. The main concern is that three changes alter the input path for every non-foldable device, and the PR only reports verification on the Duo.
I could not verify the non-foldable path live: on a booted iPhone 17 (iOS 27.2), taps failed with both this build and the released 0.2.3 build, so that simulator instance was not a usable oracle. Focused TypeScript tests pass locally.
| Check | Result |
|---|---|
| Focused bun tests (10 files) | 90 pass, 0 fail |
| iPhone 17 pushed config | screenId: 1 present |
| iPhone 17 tap, PR build | no effect, HID log confirms begin and end sent |
| iPhone 17 tap, 0.2.3 build | no effect |
Findings (details inline)
- [design] Legacy Indigo target changes for every non-foldable device —
Sources/StreamingPolicy/HIDTargetPolicy.swift:14 - [design] Legacy move events switch from Down to Dragged for all devices —
Sources/SimNative/HIDInjector.swift:257,:284 - [design] Private CoreDevice framework is loaded for every device session —
Sources/SimNative/HIDInjector.swift:91,Sources/SimNative/CoreDeviceBridge.swift:145 - [suggestion] A failed
setScreenmakes the session start fail silently —src/device-session.ts:1073,src/native.ts:184 - [suggestion] Fixed 16-byte buffers for resilient Swift structs —
Sources/CoreDeviceShim/CoreDeviceDigitizerShim.m:90 - [suggestion] Motion shim re-resolves symbols on every call —
Sources/CoreDeviceShim/CoreDeviceMotionShim.c:8 - [suggestion]
readStateargument differs from the other subcommands —src/index.ts:892 - [nit] Asset cache key reads the whole PDF per request —
src/devicekit-chrome.ts:844 - [nit] Unused asset —
src/client/assets/hinge-half-open-portrait.svg - [nit] Rotation cursor can ignore external rotation indefinitely —
src/client/simulator/rotation-cursor.ts:15 - [nit] Manager readiness poll blocks the bridge actor —
Sources/SimNative/CoreDeviceBridge.swift:40
One observation, not a finding: the iPhone 17 simulator shut down about one minute after a PR-build server attached and Settings was launched via simctl, with a splashboardd crash in BKSHIDEventDeliveryManager. No input had been sent. After a reboot the same server attached without incident. Cause undetermined.
Restore the original Indigo target and move encoding for non-foldables. Gate CoreDevice setup, controls, and display tracking on exactly two integrated displays. Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: Codex <[email protected]>
Log native HID setup errors once and disable input for the affected session without rejecting capture startup. Cover failed setup with and without screen metadata, continued video delivery, and subsequent display updates. Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: Codex <[email protected]>
Check both runtime value sizes before enabling the digitizer. Reject layouts that differ from the two-word buffers and Swift call signatures, preventing incompatible constructors or setters from running. Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: Codex <[email protected]>
Cache successful and failed initialization with dispatch_once so repeated capability checks do not resolve symbols or rewrite the async descriptor. Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: Codex <[email protected]>
Read the supplied device state directly, matching rotate, tap, gesture, and the other existing input commands. Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: Codex <[email protected]>
Version the rotation-aware PNG cache and parse PDF rotation only on a cache miss. Verify cached asset requests preserve the correct dimensions without rereading PDFs. Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: Codex <[email protected]>
Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: Codex <[email protected]>
Limit protection from delayed acknowledgements to 1.5 seconds per request. A declined pose no longer blocks later external rotations, while subsequent clicks can still cycle past unsupported poses. Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: Codex <[email protected]>
Coalesce concurrent readiness checks into one task with a monotonic five-second polling deadline. Fail explicitly before device enumeration on timeout and allow later retries without one caller's cancellation affecting other waiters. Co-authored-by: Krystof Woldrich <[email protected]> Co-authored-by: Codex <[email protected]>
Gate every SimHID operation on the shared setup task, preserving setup failures instead of calling a partially initialized injector. Test pending foldable setup and cached failures. Co-authored-by: Codex <[email protected]>
Handle rejected acknowledgements independently of the requested angle so the control clears pending state immediately and displays the server error. Cover timeout cancellation and successful-reply matching. Co-authored-by: Codex <[email protected]>
Extend the existing child suite to verify the setup-failure latch across every input method, per-handle recovery, and non-latching malformed-input errors. Retain the MJPEG streaming and screen-metadata checks during setup failure. Co-authored-by: Codex <[email protected]>
Preserve Duo display readiness and active-panel metadata alongside upstream capture timing diagnostics. Co-authored-by: Codex <[email protected]>
Adds iPhone Duo streaming, fold controls, and the correct frames and corner radii. Keeps the bezel and hardware buttons aligned during rotation.
Uses per-display Universal HID reports for Duo touch input. Verified corner taps, drags, wheel input, and two-finger input at 0°, 90°, and 180°, in portrait and both landscape directions. Build, focused tests, typecheck, and lint pass.
Closed — 0°

Half-fold — 90°, landscape

Fully open — 180°, opposite landscape

Streaming and rotation video
duo-correct-frames-rotation.mp4