previous_sequence caught PermissionError and IsADirectoryError and returned 0,
so an unreadable command file was silently overwritten with a restarted
sequence. main() already rejects directory targets, so only FileNotFoundError
is a valid empty start. Cover the unreadable case with a mocked PermissionError,
which needs no chmod and also runs for privileged writers.
Addresses the changes requested in the review of 19.10. and 24.10.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Ensure pad_input writes controller commands with explicit UTF-8 encoding and UNIX LF newlines across all host platforms. Validate that the target path is not a directory and that its parent directory exists before attempting to write.
Some titles wait for a chord on their title screen: RollerCoaster Tycoon
Adventures Deluxe (PPSA17330) asks for L1 + R1. The command file already
carries a button bit field, but the helper accepted one name. Names joined
by '+' are now combined into one command; unknown names, duplicates and
release in a chord are rejected without touching the command file.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
pad_timeline.py now takes its sequence from pad_input.next_sequence, and
pad_input.previous_sequence reads the sequence from an APS5_PAD_TIMELINE
header, so a pulse or timeline queued after a host reboot still exceeds
the sequence the runtime loaded from the existing command file.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
APS5_PAD_INPUT_FILE commands can set bit 0x200000 or 0x400000 to put a
finger on the left or right half of the touchpad, as the TouchLeft and
TouchRight keys do, so scripted runs can press touchpad combinations.
tools/pad_input.py queues them as touch-left and touch-right.
AI-assisted: yes
Add an optional input helper for test runs without desktop input injection. Preserve physical input and release injected buttons automatically.
Validation: guest_pad tests and Python helper CLI smoke checks passed. Written with AI assistance.