Files
RetroArch/.github/workflows/Linux-samples-input.yml
T
LibretroAdmin 547fa2369c Input: winraw reads a DualShock 3 on Sony's sixaxis.sys
A DualShock 3 on Sony's own driver, sixaxis.sys, or on DsHidMini in
the mode that stands in for it, sends no input reports: its state is
feature report 0, asked for. Under the raw input joypad driver such a
pad showed up and did nothing.

The driver's own thread now asks a DualShock 3 for that report every
4 ms and hands the newest to the poll through three buffers swapped
with an atomic exchange; the poll lays it out as the pad's own HID
description does - buttons 1 to 19, the sticks X, Y, Z and Rz - so a
profile for the pad binds it. Its motors and player light go as that
driver's commands. A DualShock 3 on Windows' own HID driver, which has
not started it, has no report 0: it is asked once and left alone, and
one whose input reports come after all is no longer asked. With no
such pad nothing changes: the thread waits on wakes alone, and the
poll looks at one counter.

The writer thread's timed wait now goes through a high resolution
waitable timer on Windows, where a short wait was otherwise a whole
timer tick.

winraw_joypad_sixaxis_test runs the driver under Wine with the pad's
driver faked.
2026-10-21 09:10:49 +02:00

1176 lines
58 KiB
YAML

name: CI Linux samples/input
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
samples-input:
name: Build and run samples/input
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Install dependencies
timeout-minutes: 20
run: |
pkgs="build-essential libusb-1.0-0-dev libudev-dev libsdl2-dev libx11-dev libxtst-dev libxi-dev xvfb gcc-mingw-w64-x86-64 wine64"
if dpkg -s $pkgs >/dev/null 2>&1; then
echo "All packages already present on runner image; skipping apt."
exit 0
fi
for i in 1 2 3; do
sudo timeout 90 apt-get update -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 && break
echo "apt-get update failed (attempt $i); retrying in 10s"
sleep 10
done
# Fetch first, under a bound: a download is safe to stop and
# resumes, an install is not. A mirror that stalls is left for
# the main archive on the next attempt.
for i in 1 2 3; do
sudo timeout 240 apt-get install -y --download-only \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs && break
[ $i = 3 ] && exit 1
echo "package download failed or stalled (attempt $i); retrying from archive.ubuntu.com"
if [ ! -d /etc/apt/ra-orig ]; then
sudo mkdir /etc/apt/ra-orig
sudo cp -a /etc/apt/sources.list.d /etc/apt/ra-orig/
[ ! -f /etc/apt/sources.list ] || sudo cp -a /etc/apt/sources.list /etc/apt/ra-orig/
fi
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*; do
[ -f "$f" ] || continue
sudo sed -i -e 's#mirror+file:/etc/apt/apt-mirrors.txt#http://archive.ubuntu.com/ubuntu/#g' \
-e 's#http://azure\.archive\.ubuntu\.com/ubuntu#http://archive.ubuntu.com/ubuntu#g' "$f"
done
# A refresh cut short or refused leaves apt no package lists: it
# is retried, without translations or command-not-found data, and
# the mirror is put back when the archive will not answer either.
upd="-o Acquire::Retries=3 -o Acquire::http::Timeout=30
-o Acquire::Languages=none
-o Acquire::IndexTargets::deb::CNF::DefaultEnabled=false
-o APT::Update::Error-Mode=any"
ok=0
for j in 1 2; do
sudo timeout 120 apt-get update -y $upd && { ok=1; break; }
done
if [ $ok = 0 ]; then
sudo rm -rf /etc/apt/sources.list.d
sudo cp -a /etc/apt/ra-orig/sources.list.d /etc/apt/
[ ! -f /etc/apt/ra-orig/sources.list ] || sudo cp -a /etc/apt/ra-orig/sources.list /etc/apt/
sudo rm -rf /etc/apt/ra-orig
sudo timeout 120 apt-get update -y $upd || true
fi
done
sudo apt-get install -y \
-o Acquire::Retries=3 -o Acquire::http::Timeout=30 \
$pkgs
- name: Checkout
uses: actions/checkout@v5
- name: Link with lld
run: sh .github/workflows/scripts/use-lld.sh
- name: Build and run joypad_bridge_checked (udev, linuxraw, SDL2 on the host; DirectInput, XInput under Wine)
shell: bash
working-directory: samples/input/joypad_bridge_checked
run: |
set -eu
# The joypad drivers the snapshot bridge serves, held to what
# it assumes of them: over random pads, binds and thresholds,
# what the bridge would read - buttons through get_buttons(),
# hats and axes through button() and axis(), the RetroPad
# mask through the common loop - is what the driver's own
# button(), axis() and state() say.
make clean && make -j$(nproc) all
timeout 120 make check
make clean
- name: gfx/ does not reach into input state
shell: bash
run: |
set -eu
# The video code used to take input_state_get_ptr() and work
# on the input driver's fields itself - freeing the driver
# and the joypads, handing out the addresses of its slots,
# reading and setting its flags. It goes through calls into
# input/ now (input_driver_free_with_video() and the rest).
# This keeps it that way: no file under gfx/ may name
# input_state_get_ptr.
if grep -rn "input_state_get_ptr" --include=*.c --include=*.h \
--include=*.m --include=*.cpp gfx/; then
echo "FAIL: gfx/ takes the input driver's state directly" >&2
exit 1
fi
echo "[pass] gfx/ does not name input_state_get_ptr"
- name: Video drivers do not start the input driver for their window
shell: bash
run: |
set -eu
# The Windows video drivers and contexts, and the X11 and KMS
# contexts, used to call input_driver_init_windows(), _x11()
# or _kms() from their own start-up. They say what kind of
# window they put up (input_driver_video_window()) and
# the frontend starts the input driver for it once the video
# driver is up (video_driver_init_input()). No file under
# gfx/ may call those three again.
if grep -rnE "input_driver_init_(windows|x11|kms)" --include=*.c \
--include=*.h --include=*.m --include=*.cpp gfx/; then
echo "FAIL: a video driver starts the input driver for its window itself" >&2
exit 1
fi
echo "[pass] gfx/ does not call input_driver_init_windows, _x11 or _kms"
- name: input/ does not reach into video state
shell: bash
run: |
set -eu
# The other direction of the step above. The input code used
# to take video_state_get_ptr() and work on the video
# driver's fields - the frame count, the core's geometry, the
# mouse cursor through the poke interface, the overlay
# interface and the driver's data. It goes through calls
# into gfx/ now (video_driver_show_mouse() and the rest).
# The Android input driver is the one file still to do: it
# creates and destroys the window surface on the app's
# lifecycle events, and is allowed here by name until that
# is moved.
if grep -rn "video_state_get_ptr" --include=*.c --include=*.h \
--include=*.m --include=*.cpp input/ \
| grep -v "^input/drivers/android_input.c:"; then
echo "FAIL: input/ takes the video driver's state directly" >&2
exit 1
fi
echo "[pass] input/ does not name video_state_get_ptr (android_input.c excepted)"
- name: Restore ccache
uses: actions/cache/restore@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
restore-keys: |
ccache-${{ github.workflow }}-${{ github.job }}-
- name: Enable ccache
run: |
set -eu
command -v ccache >/dev/null 2>&1 || sudo apt-get install -y -qq ccache
export CCACHE_DIR="$HOME/.ccache"
echo "CCACHE_DIR=$CCACHE_DIR" >> "$GITHUB_ENV"
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
ccache -M 250M
ccache -z
- name: X11 input poll sends no requests (Xvfb, ASan + UBSan, TSan)
shell: bash
working-directory: samples/input/x11_input_poll
run: |
set -eu
# The X input driver's poll runs every frame. Keys, and with
# XInput 2 the pointer, come from events on the driver's own
# connection, drained at the poll, so it sends no request on
# either connection; a query on the shared one waits behind
# whatever the video thread presents through it. XTEST drives
# the keyboard (held before init, auto-repeat, focus changes,
# another client's keyboard grab) and the pointer (a press
# without motion, buttons 1, 3 and 8, the wheel, a drag out of
# the window, a new driver over a held button, and grabbed
# motion across a warp the server holds back behind a server
# grab - where any wait on the server would hang the test).
Xvfb :96 -screen 0 1024x768x24 > /tmp/xvfb96.log 2>&1 &
XVFB_PID=$!
sleep 1
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
DISPLAY=:96 ASAN_OPTIONS=detect_leaks=1 \
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 120 ./x11_input_poll_test
make clean SANITIZER=thread && make -j$(nproc) all SANITIZER=thread
DISPLAY=:96 TSAN_OPTIONS=halt_on_error=1 timeout 120 ./x11_input_poll_test
make clean
kill $XVFB_PID
echo "[pass] x11_input_poll_test (ASan, TSan)"
- name: Build and run illuminance_sensor_test (ASan + UBSan)
shell: bash
working-directory: samples/input/illuminance_sensor
run: |
set -eu
# The Linux IIO illuminance sensor poller, against a fake
# sysfs tree under /tmp. Pins that the poll thread waits on a
# condition between readings rather than sleeping: a raised
# rate applies at once, and close returns without waiting out
# the period.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
test -x illuminance_sensor_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./illuminance_sensor_test
echo "[pass] illuminance_sensor_test (ASan)"
- name: Build and run illuminance_sensor_test (TSan)
shell: bash
working-directory: samples/input/illuminance_sensor
run: |
set -eu
make clean SANITIZER=thread && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 60 ./illuminance_sensor_test
echo "[pass] illuminance_sensor_test (TSan)"
- name: Build and run libusb_hid_test (ASan + UBSan)
shell: bash
working-directory: samples/input/libusb_hid
run: |
set -eu
# The libusb HID driver against a fake libusb: reads and
# commands run on asynchronous transfers completed by the poll
# thread, with no thread per pad. Pins that a command goes out
# at once even while the pad sends nothing, that commands stay
# in order one at a time, that unplugging frees the adapter,
# and that freeing the driver returns at once with a send
# still pending, releasing every transfer and handle.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
test -x libusb_hid_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./libusb_hid_test
echo "[pass] libusb_hid_test (ASan)"
- name: Build and run libusb_hid_test (TSan)
shell: bash
working-directory: samples/input/libusb_hid
run: |
set -eu
make clean SANITIZER=thread && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 60 ./libusb_hid_test
echo "[pass] libusb_hid_test (TSan)"
- name: Build and run winusb_hid_test (mingw + Wine)
shell: bash
working-directory: samples/input/winusb_hid
run: |
set -eu
trap 'wineserver -k >/dev/null 2>&1 || true' EXIT
make clean && make -j$(nproc) all
WINEDEBUG=-all timeout 300 make check
make clean
- name: Build and run connection_gate_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/input/connection_gate
run: |
set -eu
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 ./connection_gate_test
make clean SANITIZER=thread && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 60 ./connection_gate_test
make clean
- name: Build and run hidraw_hid_test (ASan + UBSan)
shell: bash
working-directory: samples/input/hidraw_hid
run: |
set -eu
# The hidraw HID driver with the real pad handlers, against
# stand-ins for /dev and /sys: only handled pads are opened, a
# DualShock 3 is started through hidraw, the newest report
# waiting is the pad's state, and a pad that goes is
# disconnected and its node closed.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
test -x hidraw_hid_test
ASAN_OPTIONS=detect_leaks=1:detect_stack_use_after_return=1 \
UBSAN_OPTIONS=print_stacktrace=1 timeout 60 \
./hidraw_hid_test
echo "[pass] hidraw_hid_test (ASan)"
- name: Build and run wii_handshake_test (ASan + UBSan)
shell: bash
working-directory: samples/input/wii_handshake
run: |
set -eu
# The Wiimote extension handshake in connect_wii.c, fed
# reports directly. Pins that each init write waits for the
# remote's acknowledgement instead of a sleep on the packet
# thread, that a missing acknowledgement is only overtaken by
# a packet after the old 100 ms, and that no packet blocks.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
test -x wii_handshake_test
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./wii_handshake_test
echo "[pass] wii_handshake_test (ASan)"
- name: Build and run android_lifecycle_flush_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/input/android_lifecycle_flush
run: |
set -eu
# The Android background flush handshake, a UI thread against
# an app thread. Pins that onPause() and onStop() return only
# once SRAM, core options and the config are on disk - a
# swiped-away task is killed as soon as they have returned -
# that the save is written once per trip to the background,
# and that the startup pump acknowledges without saving.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./android_lifecycle_flush_test
make clean SANITIZER=thread && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 60 ./android_lifecycle_flush_test
make clean
echo "[pass] android_lifecycle_flush_test (ASan, TSan)"
- name: Build and run android_pad_removed_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/input/android_pad_removed
run: |
set -eu
# A controller Android has removed, from the listener that
# hears of it to the port it comes back to. Pins that no
# removal is lost or delivered twice with three threads
# posting into the mailbox while the input thread polls, that
# a full box refuses and keeps what it holds, and that a
# returning pad gets its old port back - of two identical
# pads, the one that left. Emptying a removed slot's name, as
# the first version of the change did, is put back and
# asserted to be caught: it moved a pad to the next free port
# on every reconnect.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 120 ./android_pad_removed_test
make clean SANITIZER=thread && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 120 ./android_pad_removed_test
make clean
echo "[pass] android_pad_removed_test (ASan, TSan)"
- name: Build and run android_kbd_keys_test (ASan + UBSan)
shell: bash
working-directory: samples/input/android_kbd_keys
run: |
set -eu
# Key events from the Android system keyboard, through the
# native input queue to the text field that owns the menu
# line. Pins that a Backspace the soft keyboard sends as a
# key event is handed back to the field instead of being
# consumed natively - consumed, the field kept the
# characters and the next snapshot put them back on the line.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./android_kbd_keys_test
make clean
echo "[pass] android_kbd_keys_test (ASan)"
- name: Build and run android_cec_remote_test (ASan + UBSan)
shell: bash
working-directory: samples/input/android_cec_remote
run: |
set -eu
# A television's remote over HDMI-CEC. Android delivers its
# keys with no device behind them (id -1, source HDMI), and
# the driver took the event for a new gamepad: the remote
# became an unconfigured pad called "Virtual" on the next
# free port (issue #19249). Pins that such an event registers
# no pad and lands on the keyboard row, that only the HDMI
# source is taken for a remote, that a controller - one
# reporting id -1 included - still gets its pad, and that the
# SHIELD keeps its own CEC mapping. Ignoring the source, as
# the driver did, is put back and asserted to be caught.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./android_cec_remote_test
make clean
echo "[pass] android_cec_remote_test (ASan)"
- name: Build and run android_key_state_test (ASan + UBSan)
shell: bash
working-directory: samples/input/android_key_state
run: |
set -eu
# Key presses and releases, through the code that writes them
# into the Android driver's key state. For nine days a press
# of Back set X on the keyboard row and nothing cleared it; X
# is RetroPad A by default, and the frontend drops all
# controller input after a menu toggle until every button is
# up, so the menu went deaf to the controller while touch
# kept working (issue #19436). Pins that whatever a press
# sets its release clears - every keycode, every source,
# every row, and any interleaving - that keycodes outside the
# rows are dropped, that Center stays keycode 23 on a pad row
# (issue #18819), and that a pad removed while holding Back
# leaves nothing behind. The missing clear is put back and
# asserted to be caught.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./android_key_state_test
make clean
echo "[pass] android_key_state_test (ASan)"
- name: Build and run output_store_test (ASan + UBSan, TSan)
shell: bash
working-directory: samples/input/output_store
run: |
set -eu
# What a core asks of a rumble motor or an LED, between the
# core's call and the frontend's write to the device. Those
# calls used to be driver writes on the core's own stack, as
# many a frame as the core made; they now post into a store
# that the frame loop takes once the core has run. Pins that
# a post writes nothing, that an output set many times in a
# frame is written once with the last value, that one set to
# the value it already had is still written, that a drop
# forgets, and - with three threads posting while the frame
# loop takes - that every output ends on the last value
# posted to it. A take that sees the posts and writes
# nothing, the shape of a stop that never reaches the motor,
# is put back and asserted to be caught.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 120 ./output_store_test
make clean SANITIZER=thread && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 120 ./output_store_test
make clean
echo "[pass] output_store_test (ASan, TSan)"
- name: Build and run window_driver_test (ASan + UBSan)
shell: bash
working-directory: samples/input/window_driver
run: |
set -eu
# Which input driver a window gets
# (input/input_driver_choice.c): the choice the video
# contexts used to have written out each for itself, with
# the drivers' names in it. Runs every branch of the X11
# window choice and the no-window-system choice with
# stand-in drivers that start or fail to: which driver comes
# out, which were tried and in what order, that the joypad
# driver's name is passed through, and that the two results
# are both set or both NULL. The Windows choice is the same
# test built with mingw and run under Wine, in the gfx
# samples workflow; it also has the case of a driver left
# running across a video driver restart, which is handed
# back with none started.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./window_driver_test
# the same built with SDL 1.2 in SDL 3's place, for the SDL
# 1.2 window's choice: a build has one or the other
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./window_driver_test_sdl1
make clean
echo "[pass] window_driver_test (ASan)"
- name: Build and run bind_trigger_axis_test (ASan + UBSan)
shell: bash
working-directory: samples/input/bind_trigger_axis
run: |
set -eu
# Binding L2 or R2 by pressing it: a trigger that is a button
# and an axis at once is bound to its axis, which is analog.
# Which axis that is, is told from where each axis rests and
# whether it has left it (menu/menu_bind_trigger.h): the
# trigger's own, not a stick held over, not noise, not the
# other trigger.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./bind_trigger_axis_test
make clean
echo "[pass] bind_trigger_axis_test (ASan)"
- name: Build and run hotkey_menu_test (ASan + UBSan, mingw + Wine)
shell: bash
run: |
set -eu
make -C samples/input/hotkey_menu clean check SANITIZER=address,undefined
make -C samples/input/hotkey_menu clean check CC=x86_64-w64-mingw32-gcc EXE=.exe RUNNER=wine
make -C samples/input/hotkey_menu clean
- name: Build and run key_lane_test (plain, ASan + UBSan, TSan)
shell: bash
working-directory: samples/input/key_lane
run: |
set -eu
# Keyboard events reported off the frontend's thread wait in
# a lock-free queue for the poll (input/input_key_lane.h).
# The test includes that header and drives it: a writer
# stopped right after claiming a slot with the queue full
# behind it and a release that did not fit (the key must not
# be left held); a kept release never undoing a newer press;
# the counters across their wrap (UBSan); four writers at
# once, every event exactly once and in order (TSan).
make clean && make -j$(nproc) all
timeout 60 ./key_lane_test
make clean SANITIZER=undefined,address && make -j$(nproc) all SANITIZER=undefined,address
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 120 ./key_lane_test
make clean SANITIZER=thread && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 timeout 120 ./key_lane_test
make clean
echo "[pass] key_lane_test"
- name: Build and run keymaps_lut_test (ASan + UBSan)
shell: bash
working-directory: samples/input/keymaps_lut
run: |
set -eu
# The keysym reverse table input/input_keymaps.c builds, with
# memory and with its allocation failed: every mapped code
# translates the same either way, through the forward table
# when there is no reverse one.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./keymaps_lut_test
make clean
echo "[pass] keymaps_lut_test"
- name: Build and run pointer_frame_test (plain, ASan, UBSan)
shell: bash
working-directory: samples/input/pointer_frame
run: |
set -eu
# What the frontend keeps of the mice and touches an input
# driver publishes at its poll (input/input_pointer_frame.h),
# and its answers for the mouse, the pointer and the
# lightgun's aim. The test includes that header with a
# viewport and a translation that count how often they are
# asked: one fetch a poll and one translation a device,
# however many values are read; a wheel notch the same for
# every reader of the frame; real touches and the mouse
# standing for them.
make clean && make -j$(nproc) all
timeout 60 ./pointer_frame_test
make clean SANITIZER=address && make -j$(nproc) all SANITIZER=address
timeout 60 ./pointer_frame_test
make clean SANITIZER=undefined && make -j$(nproc) all SANITIZER=undefined
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./pointer_frame_test
make clean
echo "[pass] pointer_frame_test"
- name: Build and run device_registry_test (ASan + UBSan)
shell: bash
working-directory: samples/input/device_registry
run: |
set -eu
# Which controllers there are, and which of them has been
# here before. A joypad driver knows a controller by its
# slot; the registry gives each one a device id that it keeps
# when it leaves and returns, and a handle that is good for
# one stay. Pins that a returning controller has its id and
# a new handle, that a handle stops resolving when the
# controller leaves, is reported again or loses its slot,
# that identical pads are told apart by where they are
# plugged in, then by slot, then by who left last, that a
# driver starting over costs nobody their id, that a full
# table gives up only a controller that has left, and -
# through 200000 arrivals and departures - that no two
# present controllers share a slot or an id. And that a
# driver which starts over and reports the controllers it
# had, in any order and any slots, has each put back on its
# port - but only then: one missing, a new one, or one
# leaving again, and nothing is moved. A handle that
# outlives its stay, the way a kept slot number does, is put
# back and asserted to be caught.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 120 ./device_registry_test
make clean
echo "[pass] device_registry_test (ASan)"
- name: Build and run device_pool_test (ASan + UBSan)
shell: bash
working-directory: samples/input/device_pool
run: |
set -eu
# The device numbers shared between the joypad driver and the
# sources beside it: the driver's pads keep their slots'
# numbers, pads beside it are given free ones from the top
# down and their own again when they come back, and a driver
# pad arriving on a number one of them holds moves that pad.
# Thousands of mixed arrivals and departures never give a
# number twice.
make clean all SANITIZER=address,undefined
timeout 120 ./device_pool_test
make clean
echo "[pass] device_pool_test (ASan)"
- name: Build and run android_stylus_map_test (ASan + UBSan)
shell: bash
working-directory: samples/input/android_stylus_map
run: |
set -eu
# An Android pen, through the mapping that turns its events
# into pointer and mouse state. Pins that a pen is one touch:
# the tip pressing is pointer 0 pressed and the barrel button
# is the right mouse button, where the first version raised
# the pointer count to 2 and 3 and read as a two- and
# three-finger touch (turbo and reload to the driver's own
# lightgun mapping). Also that a hover does not release a
# finger, that the barrel button is let go with the pen, and
# that the two click settings decide what a press is. The old
# pointer counts are put back and asserted to be caught.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./android_stylus_map_test
make clean
echo "[pass] android_stylus_map_test (ASan)"
- name: Build and run linux_not_joystick_test (ASan + UBSan)
shell: bash
working-directory: samples/input/linux_not_joystick
run: |
set -eu
# Devices Linux tags as joysticks that are not controllers.
# Pins issue #19674: a Microsoft 2.4GHz Transceiver, the
# receiver of a wireless keyboard and mouse, took port 1
# through its "System Control" node and left the real
# controller on port 2. Checks that receiver, the same node
# on unknown devices and the listed ids are dropped, and that
# real controllers - a pad named "Wireless", a pedal set with
# no buttons - are kept.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./linux_not_joystick_test
make clean
echo "[pass] linux_not_joystick_test (ASan)"
- name: Build and run overlay_textures_test (plain, ASan + UBSan, threaded)
shell: bash
working-directory: samples/input/overlay_textures
run: |
set -eu
# input/input_overlay_textures.c as it is, against a stub
# driver that reads every pixel it is handed. Pins every
# route a page takes to the driver: as textures (each page
# gets its own images' textures, a switch uploads nothing,
# the pixels go once the driver has them and the sizes
# stay), and as pixels through load() for a driver that
# declines the textures, has no such path, or fails an
# upload - live pixels on every page. 86fbf34e01 freed the
# pixels before the page lists were matched by them, so
# with threaded video off the fallback showed freed memory;
# under ASan that is a use-after-free here.
make clean && make -j$(nproc) all
timeout 60 ./overlay_textures_test
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./overlay_textures_test
# THREADS=1: the threaded wrapper as a stub whose video
# thread runs when the test says so, so both outcomes of
# the race between the uploads and the poll are lanes. The
# quick thread is 86fbf34e01's bug again under threaded
# video; the slow one must find the pack's pixels alive.
make clean THREADS=1 SANITIZER=address,undefined && make -j$(nproc) all THREADS=1 SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
timeout 60 ./overlay_textures_test
make clean
echo "[pass] overlay_textures_test (plain, ASan, threaded ASan)"
- name: Check WinRaw mouse button publication
working-directory: samples/input/winraw_mouse_buttons
shell: bash
run: |
set -eu
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=halt_on_error=1 ./winraw_mouse_buttons_test
make clean SANITIZER=thread && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 ./winraw_mouse_buttons_test
make clean CC=x86_64-w64-mingw32-gcc LDFLAGS="-static -lpthread" && make -j$(nproc) all CC=x86_64-w64-mingw32-gcc LDFLAGS="-static -lpthread"
WINEDEBUG=-all wine ./winraw_mouse_buttons_test.exe
make clean
- name: Check converted pad handlers against the copying ones
working-directory: samples/input/connect_parity
shell: bash
run: |
set -eu
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=halt_on_error=1 ./connect_parity_test
make clean CC=x86_64-w64-mingw32-gcc LDFLAGS=-static && make -j$(nproc) all CC=x86_64-w64-mingw32-gcc LDFLAGS=-static
WINEDEBUG=-all wine ./connect_parity_test.exe
make clean
- name: Check the sensor snapshot hand-over
working-directory: samples/input/sensor_snap
shell: bash
run: |
set -eu
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=halt_on_error=1 ./sensor_snap_test
make clean SANITIZER=thread && make -j$(nproc) all SANITIZER=thread
TSAN_OPTIONS=halt_on_error=1 ./sensor_snap_test
make clean CC=x86_64-w64-mingw32-gcc LDFLAGS="-static -lpthread" && make -j$(nproc) all CC=x86_64-w64-mingw32-gcc LDFLAGS="-static -lpthread"
WINEDEBUG=-all wine ./sensor_snap_test.exe
make clean
- name: Check WinRaw mouse position-source draining
working-directory: samples/input/winraw_mouse_pending
shell: bash
run: |
set -eu
make clean all check
make clean
make SANITIZER=address,undefined check
make clean
make SANITIZER=thread check
make clean
make CC=x86_64-w64-mingw32-gcc all
WINEDEBUG=-all timeout 60 wine ./winraw_mouse_pending_test.exe
make clean
- name: Build and run winraw_abs_pos_test (mingw + Wine)
shell: bash
working-directory: samples/input/winraw_abs_pos
run: |
set -eu
# input/drivers/winraw_input.c, cross-built with mingw-w64 and
# run under Wine: an absolute pointer report's position is
# kept as one word, and every read must give back a position
# a report carried, including a report that lands during poll.
# mingw-w64 and Wine come from "Install dependencies", whose
# download is bounded and retried; an unbounded install here
# stalled silently until the job timeout. Stop wineserver on
# exit so it cannot hold the step's output open.
trap 'wineserver -k >/dev/null 2>&1 || true' EXIT
make clean && make -j$(nproc) all
WINEDEBUG=-all timeout 300 make check
make clean
echo "[pass] winraw_abs_pos_test (wine)"
- name: Build and run winraw_poll_test (mingw + Wine)
shell: bash
working-directory: samples/input/winraw_poll
run: |
set -eu
# input/drivers/winraw_input.c with its keyboard and mouse
# read in bulk by the poll (the default;
# RETROARCH_RAWINPUT_POLL=0 turns it off). The real
# driver under Wine on a virtual display, with the focused
# window made and pumped by a second thread as the video
# thread does, and the driver started from that thread. With
# the switch off the driver is as it was. With it on: init
# makes no window and the first poll does, on the polling
# thread; six keys injected with SendInput() while nothing
# pumps are read by one bulk read, none as a message, none
# left in the queue, and come out of the poll as six key
# events in order with the modifier held at the time; six
# reports the pump meets first are one from its message and
# five in one bulk read, in order; with nothing waiting a
# poll makes one read and a pump none; a pump that asks for
# the messages below WM_INPUT and above it, as the
# frontend's does on that thread, dispatches the ordinary
# ones and leaves the reports for one bulk read; free takes
# the window down, twenty restarts each do the same; and
# with the window, the pump and the poll all on one thread,
# as without threaded video, the reports are read in bulk
# the same.
trap 'wineserver -k >/dev/null 2>&1 || true' EXIT
make clean && make -j$(nproc) all
WINEDEBUG=-all timeout 300 make check
make clean
echo "[pass] winraw_poll_test (wine)"
- name: Build and run winraw_mouse_hotplug_test (mingw + Wine)
shell: bash
working-directory: samples/input/winraw_mouse_hotplug
run: |
set -eu
# The raw input driver picked up a mouse plugged in while
# running, and a change of the Windows-key setting, only by
# being started again. Read by the poll it does both when
# they come up. The real driver under Wine, with the list of
# raw input devices it asks for replaced by one the test
# controls: a report from a mouse not in the list has the
# list made again at the end of that poll, the new mouse's
# next report moves it, and the mice already there keep
# their position, buttons and device type; a handle that is
# no listed mouse is asked about once, a report with no
# handle never; not more than one refresh a second; and the
# Windows-key setting is registered by the poll after it
# changes.
trap 'wineserver -k >/dev/null 2>&1 || true' EXIT
make clean && make -j$(nproc) all
WINEDEBUG=-all timeout 300 make check
make clean
echo "[pass] winraw_mouse_hotplug_test (wine)"
- name: Build and run sony_pad_output_test
shell: bash
working-directory: samples/input/sony_pad_output
run: |
set -eu
# The rumble reports of the DualShock 4 and the DualSense
# (input/common/sony_pad_output.h, which the raw input joypad
# driver writes to those pads): each has the id, length and
# layout its pad expects, sets no flag but the rumble ones,
# and over Bluetooth ends in the CRC the pad checks.
make clean && make -j$(nproc) all
timeout 60 make check
make clean
echo "[pass] sony_pad_output_test"
- name: Build and run hid_report_desc_test (ASan + UBSan)
shell: bash
working-directory: samples/input/hid_report_desc
run: |
set -eu
# A gamepad's reports read from its HID report descriptor
# (input/common/hid_report_desc.h, which hidraw reads pads
# with no handler through): axes numbered as on the Mac, a
# hat, buttons by usage, reports with IDs, and nothing read
# past a cut descriptor or a short report.
make clean && make -j$(nproc) all SANITIZER=address,undefined
timeout 60 make check
make clean
echo "[pass] hid_report_desc_test"
- name: Build and run winraw_joypad_rumble_test (mingw + Wine)
shell: bash
working-directory: samples/input/winraw_joypad_rumble
run: |
set -eu
# The raw input joypad driver had no rumble. For a DualShock
# 4 or a DualSense it opens the controller for writing and
# writes the rumble report from a thread of its own. The
# real driver under Wine, with files standing in for the
# controllers: the two Sony pads are opened and another
# make is not; set_rumble() writes nothing itself and the
# thread writes the pad's own report, at the length Windows
# wants; a run of changes ends with the last written; an
# unplugged pad is stilled and closed by the thread without
# the driver waiting, fifty quick plug-ins leave no device
# open, and stopping the driver stills the rest. Nothing is
# under a lock: strengths and devices pass through
# retro_atomic. An Xbox pad is rumbled through XInput, which
# is faked here: one such pad and one pad of XInput's are
# the same pad; of two, none is rumbled while nothing tells
# them apart, one is as soon as a button is held on it, and
# the other is then the one left. With "XInput for Xbox
# Controllers" on, XInput's pad is listed and read in the
# XInput driver's layout, triggers on separate axes.
trap 'wineserver -k >/dev/null 2>&1 || true' EXIT
make clean && make -j$(nproc) all
WINEDEBUG=-all timeout 300 make check
make clean
echo "[pass] winraw_joypad_rumble_test (wine)"
- name: Build and run winraw_joypad_sixaxis_test (mingw + Wine)
shell: bash
working-directory: samples/input/winraw_joypad_sixaxis
run: |
set -eu
# A DualShock 3 on Sony's sixaxis.sys, or DsHidMini standing
# in for it, sends no input reports: the raw input joypad
# driver's thread asks for its feature report every few ms
# and the poll takes the newest, laid out as the pad's own
# HID description. Its motors and light go as that driver's
# commands. One on Windows' own HID driver is asked once and
# left alone; one whose reports come is no longer asked.
trap 'wineserver -k >/dev/null 2>&1 || true' EXIT
make clean && make -j$(nproc) all
WINEDEBUG=-all timeout 300 make check
make clean
echo "[pass] winraw_joypad_sixaxis_test (wine)"
- name: Build and run sony_pad_motion_test
shell: bash
working-directory: samples/input/sony_pad_motion
run: |
set -eu
# The motion sensors of a DualShock 4 or a DualSense, read
# out of the pad's input report where its HID description
# says nothing (input/common/sony_pad_motion.h): the six
# values come from where each pad's report has them; a short
# Bluetooth report and another report id are refused; flat
# and still is one g on libretro's Z, and a turn is radians
# a second on the axes the SDL driver gives.
make clean && make -j$(nproc) all
timeout 60 make check
make clean
echo "[pass] sony_pad_motion_test"
- name: Build and run winraw_joypad_motion_test (mingw + Wine)
shell: bash
working-directory: samples/input/winraw_joypad_motion
run: |
set -eu
# The raw input joypad driver gives a core those sensors.
# The real driver under Wine, with reports handed to its
# parser: a request is taken for a Sony pad and refused for
# another make and for an empty port; nothing is given
# before a report has had the sensors, and only the sensor
# asked for; a pad nothing was asked of has none read; a pad
# unplugged and plugged in again goes on giving what was
# asked.
trap 'wineserver -k >/dev/null 2>&1 || true' EXIT
make clean && make -j$(nproc) all
WINEDEBUG=-all timeout 300 make check
make clean
echo "[pass] winraw_joypad_motion_test (wine)"
- name: Build and run net_retropad_repeat_test (Linux and Windows)
shell: bash
working-directory: samples/input/net_retropad_repeat
run: |
set -eu
# The Remote RetroPad core sends a control's state when it
# changes, by UDP. The real core is driven by a frontend of
# a few callbacks and its messages read back over loopback:
# a change is sent again 5, 15 and 30 frames on, and then no
# more; nothing is sent while nothing changes.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=print_stacktrace=1 \
timeout 120 ./net_retropad_repeat_test
make clean
make CC=x86_64-w64-mingw32-gcc
WINE=$(command -v wine64 || command -v wine || echo /usr/lib/wine/wine64)
WINEDEBUG=-all timeout 180 "$WINE" ./net_retropad_repeat_test.exe
make clean
echo "[pass] net_retropad_repeat_test (ASan, and mingw-w64 under Wine)"
- name: Build and run output_writer_test (host sanitizers and mingw + Wine)
shell: bash
working-directory: samples/input/output_writer
run: |
set -eu
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
timeout 30 make check
make clean SANITIZER=thread && make -j$(nproc) all SANITIZER=thread
timeout 30 ./output_writer_test
make clean CC=x86_64-w64-mingw32-gcc && make -j$(nproc) all CC=x86_64-w64-mingw32-gcc
WINE="$(command -v wine || command -v wine64 || echo /usr/lib/wine/wine64)"
WINEDEBUG=-all timeout 60 "$WINE" ./output_writer_test.exe
WINEDEBUG=-all timeout 60 "$WINE" ./output_writer_test_nothreads.exe
make clean
- name: Build and run udev_rumble_test (ASan + UBSan, then TSan)
shell: bash
working-directory: samples/input/udev_rumble
run: |
set -eu
# The udev joypad driver writes rumble from a thread of its
# own. The real driver is given a pad whose descriptor is a
# pipe and an upload that takes 60 ms: the call returns at
# once, the latest strength is the one written, a pad that
# goes is let go of, and stopping the driver ends the
# writer. Built with threads and without.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
timeout 120 ./udev_rumble_test
timeout 120 ./udev_rumble_test_nothreads
make clean SANITIZER=thread && make -j$(nproc) all SANITIZER=thread
timeout 120 ./udev_rumble_test
make clean
echo "[pass] udev_rumble_test"
- name: Build and run udev_ds3_pressure_test (ASan + UBSan)
shell: bash
working-directory: samples/input/udev_ds3_pressure
run: |
set -eu
# A DualShock 3's button pressures, read by the udev joypad
# driver from the pad's hidraw node into the axes after its
# own: the newest input report waiting sets them, reports of
# other IDs are read over, and a node that goes is closed
# with the pressures back at rest.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 timeout 60 ./udev_ds3_pressure_test
make clean
- name: Build and run udev_devices_test (ASan + UBSan)
shell: bash
working-directory: samples/input/udev_devices
run: |
set -eu
# The udev input driver's listing of keyboards and mice, its
# numbering of them and what a port reads went in compiled
# only: it needs devices under /dev/input, which a runner
# has none of. What the driver knows of a device is a
# structure in memory, so the real driver is handed a desk
# of them: a keyboard that is three event devices, a mouse
# that is two, a power button and a second keyboard. Two
# keyboards are listed; the mouse is mouse 1 and the
# keyboard's pointer part is not a mouse; each is told to
# the frontend by its ids; a port reads its own keyboard's
# keys and not the other's, and the mouse it is told to.
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1 \
timeout 60 ./udev_devices_test
make clean
echo "[pass] udev_devices_test (ASan)"
- name: Build and run device_pins_test
shell: bash
working-directory: samples/input/device_pins
run: |
set -eu
# A port keeps its keyboard by what the keyboard is, not by
# its place in a list that changes when keyboards are
# plugged in or out (input/common/input_device_pins.h): two
# pinned ports each read their own in whatever order the
# keyboards are listed; with one unplugged the other is
# still its own port's and the port left without reads none;
# a single port whose keyboard is away reads every keyboard;
# two keyboards of one model are two pins. And the same for
# mice, which have no "every mouse": a pinned port whose
# mouse is away reads none while another port has its own,
# and the mouse its number names otherwise.
make clean && make -j$(nproc) all
timeout 60 make check
make clean
echo "[pass] device_pins_test"
- name: Build and run keyboard_devices_test
shell: bash
working-directory: samples/input/keyboard_devices
run: |
set -eu
# Which of the devices a system reports are the keyboards on
# the desk (input/common/input_keyboard_devices.h, which the
# udev input driver lists its keyboards by): a keyboard in
# three parts is one keyboard; the power button, a headset
# and a mouse whose buttons send keys are none; two of one
# model are two; a keyboard with a pointer built in is one.
make clean && make -j$(nproc) all
timeout 60 make check
make clean
echo "[pass] keyboard_devices_test"
- name: Build and run xinput_rumble_test (mingw + Wine)
shell: bash
working-directory: samples/input/xinput_rumble
run: |
set -eu
# The XInput joypad driver writes rumble from a thread of its
# own. The real driver is given an XInputSetState that takes
# 60 ms: the call returns at once, the latest strength is the
# one written, and with the writer stopped the caller writes
# as it used to.
make clean && make -j$(nproc) all
WINE=$(command -v wine64 || command -v wine || echo /usr/lib/wine/wine64)
WINEDEBUG=-all timeout 180 "$WINE" ./xinput_rumble_test.exe
make clean
echo "[pass] xinput_rumble_test (wine)"
- name: Build and run winraw_keyboards_test (mingw + Wine)
shell: bash
working-directory: samples/input/winraw_keyboards
run: |
set -eu
# The raw input driver reads every keyboard as one; it also
# keeps the list of them and names them for the menu's
# Input Information. The real driver under Wine, with the
# list of raw input devices it asks for replaced by one the
# test controls: the keyboards and only those are listed,
# oldest first; a key from one not in the list has the list
# made again at the end of that poll, an injected key never,
# not more than once a second; a keyboard that was unplugged
# is out of the list at the poll after Windows says devices
# changed; and all of them still feed the one key state.
# And a port can be given one of them (Keyboard Index): two
# ports with a keyboard each read the same bound key each
# from its own, as a bind, in the bind mask and as the
# port's keyboard; hotkeys and the open menu answer to every
# keyboard; a port given a keyboard that is not there reads
# them all; a key held on two keyboards stays down until
# both let go; and a key held on a keyboard when it is
# unplugged is let go with a key-up. And what is listed is
# the keyboards on the desk, not raw input's: the raw
# keyboards that are parts of one device are one keyboard,
# the terminal server's is left out, and so is a mouse
# whose buttons send keys.
trap 'wineserver -k >/dev/null 2>&1 || true' EXIT
make clean && make -j$(nproc) all
WINEDEBUG=-all timeout 300 make check
make clean
echo "[pass] winraw_keyboards_test (wine)"
- name: Build and run winraw_joypad_poll_test (mingw + Wine)
shell: bash
working-directory: samples/input/winraw_joypad_poll
run: |
set -eu
# input/drivers_joypad/winraw_joypad.c with its controllers
# read by the poll. The real driver under Wine, started from
# a second thread as it is from the video thread: with
# RETROARCH_RAWINPUT_POLL=0 init makes the window as it
# always did; otherwise init makes none and the first poll
# does, on the polling thread, marking it as one whose pump
# leaves raw input alone, with one bulk read a poll; a device
# change waiting for the window is taken by the poll;
# destroy from another thread - what a controller plugged in
# causes - has the window gone once its own thread pumps; a
# restart and a poll make a new one.
trap 'wineserver -k >/dev/null 2>&1 || true' EXIT
make clean && make -j$(nproc) all
WINEDEBUG=-all timeout 300 make check
make clean
echo "[pass] winraw_joypad_poll_test (wine)"
- name: Build and run winraw_joypad_newest_test (mingw + Wine)
shell: bash
working-directory: samples/input/winraw_joypad_newest
run: |
set -eu
# winraw_joypad parses only the newest report of each report
# ID per controller out of a bulk read, not every report. The
# driver, with its HID calls routed to a fake controller that
# splits its state across report IDs: twenty thousand random
# bursts of reports - any IDs and values, several reports in
# a record, reports too big to hold, more IDs than are held -
# go to one controller through the holding path and to a
# second one report at a time, and after every burst the two
# must read the same buttons, axes and hats.
trap 'wineserver -k >/dev/null 2>&1 || true' EXIT
make clean && make -j$(nproc) all
WINEDEBUG=-all timeout 300 make check
make clean
echo "[pass] winraw_joypad_newest_test (wine)"
- name: Build and run winraw_joypad_same_model_test (mingw + Wine)
shell: bash
working-directory: samples/input/winraw_joypad_same_model
run: |
set -eu
# winraw_joypad took a second controller of the same model
# for the first one reconnecting, and evicted the first. The
# driver with its HID calls routed to fake controllers that
# share one vendor and product ID: three plugged in at once
# are three slots; one reconnecting, on its port or another,
# with its new handle announced before the old one is
# removed, gets its own slot back and leaves the others
# alone; a reconnect whose old handle still answers is known
# by its device path; with no path, a live handle is another
# controller and a dead one is this one back.
trap 'wineserver -k >/dev/null 2>&1 || true' EXIT
make clean && make -j$(nproc) all
WINEDEBUG=-all timeout 300 make check
make clean
echo "[pass] winraw_joypad_same_model_test (wine)"
- name: ccache statistics
if: ${{ !cancelled() }}
continue-on-error: true
run: ccache -sv
- name: Save ccache
# Only master's pushes keep a cache: pull requests restore
# master's, so one push does not evict the next one's.
if: success() && github.event_name == 'push' && github.ref == 'refs/heads/master'
uses: actions/cache/save@v4
with:
path: ~/.ccache
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}