mirror of
https://github.com/utmapp/UTM.git
synced 2026-10-12 02:24:01 +00:00
With the device partially folded on a table, the guest display takes the half above the fold and the half below becomes an input deck holding one of two things the user can swap: the on-screen keyboard with UTM's accessory row, or a new touchpad drawn like the keyboard. The trigger is the fold itself, reported by the iOS 27.1 SDK as an active horizontal division region; Apple keeps the hinge angle for effects and the reserved regions for layout. The deck is remembered per window so folding again brings the same one back. Only the guest display gets the touchpad; a terminal window keeps the keyboard in the deck. The display controller now constrains the Metal view above the deck, the fold and the accessory row, and requests the guest resolution for that area instead of the whole view, which is also what the dynamic resolution needs when the device opens or closes. Setting the deck from a SwiftUI update defers the resize to the next turn of the run loop, and a resize before the guest display exists no longer divides by its zero size. The hosted display takes whatever size SwiftUI proposes: SwiftUI measures the window against the part above the keyboard and centres a window that reports more, so a display sized from its own constraints lifted the whole window off the top of the screen once the reserved space below the guest display exceeded the keyboard's height. The toolbar keeps above the deck with a padding inside its own reader for the same reason, and leaves the keyboard to the system as before. The touchpad feeds the same relative pointer path as a connected mouse: one finger moves the pointer with the drag speed setting applied, a tap clicks, a two finger tap right-clicks, two fingers scroll with inertia and a finger held down drags. Clicks come with a rigid haptic tap and a lighter one on release of a drag, so a press feels like a physical trackpad; nothing for motion or scrolling. A key on the accessory row swaps to the touchpad, a key on the touchpad swaps back and the toolbar's keyboard button steps between the two while folded. The layout is done by hand from the division's frame rather than with ArrangementView so the hosted display keeps its identity across the fold and is not torn down and recreated. A fold becoming active does not change the window's size, so the region is read again whenever the hinge moves, and the deck passes the count of those readings down to the other readers in the window. Without the 27.1 SDK the deck code is compiled out and Xcode 27.0 still builds the project. While the deck is active the accessory row leaves the keyboard and sits between the guest display and the fold, so that the guest display and the toolbar can lay out around it. The swap dismisses and re-shows the keyboard, since reloading the input views while the keyboard moves between the panels crashes inside UIKit. The keyboard itself is asked for once the pose has settled, with one retry. A keyboard the system places off the screen while it moves between the panels is not counted as shown, since reacting to it asks for the keyboard again and the two keep bouncing. The display controller learns whether the keyboard is shown from the window instead of watching the notifications itself. Touches on the deck reach the display controller through the responder chain, so its touch handling only takes touches on the guest display. Folding locks the zoom to fit and shows the keyboard, and restores the window's own choices when the device opens again; neither forced value is persisted, and a window restored while folded keeps them forced. Assisted-by: Claude:claude-fable-5-1 Assisted-by: Claude:claude-opus-5-5