Add keyboard and joystick REST API#698
Open
chrisgleissner wants to merge 7 commits into
Open
Conversation
…stick port toggle via F12
There was a problem hiding this comment.
Pull request overview
Adds a new REST API surface for injecting keyboard matrix and two-port joystick state into U64-class devices via GET/POST /v1/machine:input, plus host-side tooling and tests to validate/drive the feature.
Changes:
- Introduces
/v1/machine:inputroute with JSON batch validation and atomic application of keyboard/joystick events. - Adds REST-owned keyboard matrix/tap overlay support and a joystick output combiner that merges USB (mouse/joystick) and REST joystick state.
- Adds host tools (
input_test.py,input_tool.py) and C++ host tests for validation and state behavior.
Reviewed changes
Copilot reviewed 23 out of 25 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/api/input_tool.py | Interactive Linux input capture + REST injection tool (manual/E2E exercising). |
| tools/api/input_test.py | Host-driven contract/E2E validation for the new REST input endpoint. |
| target/u64ii/riscv/ultimate/Makefile | Wires new input route + joystick output module into U64-II build. |
| target/u64/nios2/ultimate/Makefile | Wires new input route + joystick output module into U64 build. |
| target/u2plus/nios/ultimate/Makefile | Builds input route but returns 501 for non-U64 hardware. |
| target/u2plus_L/riscv/ultimate/Makefile | Builds input route but returns 501 for non-U64 hardware. |
| target/u2/riscv/ultimate/Makefile | Builds input route but returns 501 for non-U64 hardware. |
| software/io/usb/usb_hid.cc | Routes joy1 SWOUT updates through new JoystickOutput combiner on U64. |
| software/io/usb/tests/Makefile | Updates test include paths for new dependencies. |
| software/io/usb/keyboard_usb.h | Adds REST keyboard state/tap overlay API and storage. |
| software/io/usb/keyboard_usb.cc | Implements REST keyboard matrix state, tap queue/overlay, and timer tick. |
| software/io/c64/keyboard_c64.h | Adds helper to detect when joystick activity should block keyboard scan. |
| software/io/c64/keyboard_c64.cc | Prevents REST-injected joystick activity from starving local keyboard scan. |
| software/io/c64/joystick_output.h | New output combiner interface for USB + REST joystick state. |
| software/io/c64/joystick_output.cc | Implements merged joystick output + POT mapping for fire2/fire3. |
| software/api/tests/Makefile | Adds build/run targets for new API validation + state host tests. |
| software/api/tests/input_api_validation_test.cpp | Unit tests for JSON schema/validation of input batches. |
| software/api/tests/input_api_state_test.cpp | Host tests for REST keyboard/joystick state overlay behavior. |
| software/api/routes.cc | Treats zero-length bodies as “no body” for multipart writers (prevents parsing). |
| software/api/route_machine.cc | Clears REST-injected input state on reset/reboot (U64). |
| software/api/route_input.cc | New /v1/machine:input GET/POST endpoint with apply + snapshot logic. |
| software/api/json.h | Whitespace-only formatting tweak. |
| software/api/json.cc | Hardens JSON conversion against empty/invalid token ranges and OOM. |
| software/api/input_api.h | New header-only JSON validation + keyboard/joystick mapping tables. |
| .gitignore | Ignores newly added host-test binaries. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…stick and keyboard APIs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR resolves #670 by adding U64-class keyboard and joystick injection on CIA level through
GET /v1/machine:inputandPOST /v1/machine:input.The endpoint accepts validated JSON input batches, applies keyboard and joystick state through separate REST-owned lanes, and returns a REST-injected state snapshot without reporting physical USB input.
For a detailed specification of this change as well as a documentation of the two new REST endpoints please see #670 (comment)
Demo
Demo 1: Anykey
The following video demonstrates how an Ultimate 64 Elite I is controlled from a Kubuntu 24.04 machine via REST calls:
https://youtu.be/KSnNvxM2S2s
Overview
RESTOREkey.fire,fire2, andfire3as per the REST API) are pressed in sequence.Setup
input_tool.pyscript (part of this PR and useful for manual tests) intercepts both devices and transforms their signals to REST calls against the C64.Demo 2: The Great Giana Sisters
The following video demonstrates how to play one of the best games of all time, The Great Giana Sisters:
https://youtu.be/aIj1hI3g45I
input_tool.pytool started in verbose mode (-Vflag) which relays the USB XBox 360 Controller and Keychron C3 Pro keyboard actions via REST to an Ultimate 64 Elite I.High-Level Changes
machine:inputREST endpoint with sharederrors,keyboard, and two-portjoysticksresponse shape forGETand successfulPOST.fire2/fire3support through POTX/POTY state while keeping digital joystick bits 5..7 high.Implementation Details
C64_JOY1_SWOUT.MATRIX_WASD_TO_JOYoff at the keyboard matrix owner and restores the configured value when REST keyboard state clears, matching the existing keyboard-scan workaround that keeps the C64 keyboard usable.fire2/fire3use POTX/POTY and leave joystick digital bits 5..7 high; U64-visible POT lows are mirrored through the first paddle register pair so port 2 extra buttons are observable by C64 software.fire2/fire3while C64-side POT reads still remained released without that mirror.Tests
make -C software/api/testspassed, andmake -C software/io/usb/testspassed.python3 tools/api/input_test.py --host u64passed against a deployed U64 build withinput_test: OK (38 checks).python3 tools/api/input_tool.py --self-test --host u64 --no-gamepadpassed withinput_tool self-test: OK; interactive typing/gamepad exercise was not run in this non-interactive session.input_tool.pyis best used with a US keyboard and uses positional mapping from the host keyboard to C64 keys.The following run was performed after having flashed the u64 image built by https://github.com/GideonZ/1541ultimate/actions/runs/26129320557 on my Ultimate 64 Elite:
Concurrent Use Test: