fangorn/sunshine-qemu
public
ref:main
Pull requests
Links
Phase 2: gamepads for Linux guests
Parent: #1. Depends on #5 (input routing). Windows guests are tracked separately in #11.
Requirements
- REQ-INP-004: gamepad input for Linux guests
Background
- QEMU’s D-Bus display has no gamepad interface (verified in
ui/dbus-display1.xml, QEMU 11.1). - Sunshine on Linux already creates host uinput gamepads through libvirtualhid (
platf::alloc_gamepad,gamepad_updateinsrc/platform/virtualhid_input.cpp), including Xbox/DS4/DS5-style devices with rumble feedback. - QEMU can pass a host evdev device to the guest:
-device virtio-input-host-pci,evdev=/dev/input/eventN. Linux guests have virtio-input drivers. Unverified: whether force-feedback/rumble goes through virtio-input-host, and whether guests see a usable joystick (buttons/axes) rather than just raw events. - Gamepads appear dynamically when a client connects a controller, so the evdev device doesn’t exist when QEMU starts. It has to be hot-plugged over QMP (
device_add driver=virtio-input-host-pci,evdev=...,id=...) and removed on disconnect (device_del).
Tasks
- Spike first: create a uinput gamepad by hand (or with Sunshine’s existing path), hot-plug it into a running Linux guest with QMP, and check in the guest with
evtestandjstest(buttons, axes, triggers, D-pad, rumble). Record the results in a comment on this issue. If virtio-input-host doesn’t give a working gamepad, stop and escalate with the alternatives:usb-hostpassthrough of the uinput device isn’t possible because uinput isn’t USB; that leaves a QEMU USB gamepad device (#11) for Linux guests too. - QMP client in
qemu/qmp.{h,cpp}: config keyqemu_qmp_socket; minimal JSON QMP with capabilities negotiation,device_add,device_del, and waiting for theDEVICE_DELETEDevent. Keep it small; nlohmann/json is already a Sunshine dependency, so check before adding anything. - Wire-up: when
capture == qemuandqemu_qmp_socketis set, the gamepad functions still create the libvirtualhid uinput device. After creation, find its/dev/input/eventNnode through the existing libvirtualhid API or sysfs, thendevice_add. On gamepad removal or client disconnect,device_del, then destroy the uinput device. - The uinput devices must not also drive the host desktop. Document that the host shouldn’t run a session that grabs them, or
EVIOCGRABthem for exclusive use; test whether QEMU’sgrab_all/exclusive grab behavior is enough. - Rumble feedback: guest FF events → host uinput → Moonlight feedback queue, only if the spike shows FF works through virtio-input-host.
- Permissions: document udev rules so the Sunshine user can create uinput devices and QEMU can open the event nodes.
Tests
- Unit: QMP client against a fake QMP socket (negotiation, device_add/del, errors, DEVICE_DELETED wait).
- E2E: the test client sends gamepad state (button A, left stick full right); the guest evdev logger shows
BTN_SOUTHandABS_Xmax; disconnect →device_delobserved.
Done when
REQ-INP-004 is linked to passing tests, a manual check with a real controller through Moonlight into a Linux guest is noted in the PR, and anvil requirement status passes. PR Closes #7.