#!/usr/bin/env bash # Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License. # See LICENSE.md for license information. # SPDX-License-Identifier: MIT # # verify-sdl3-joy.sh - Joystick gate for the SDL3 port: both sticks, every # direction, both buttons and every release, driven through two virtual # gamepads and read back from what examples/joy draws; then the pads # unplugged while JOY runs. Twice: once with gamepads SDL has a mapping for, # once with plain joysticks it has none for. # # The port (src/hosted/sdl3/sdl3Backend.c) opens the first two gamepads or # joysticks SDL offers as JL_JOYSTICK_0 and JL_JOYSTICK_1, plugged and # unplugged as they come and go: a gamepad's left stick, its south button as # button 0 and its east as button 1; a joystick SDL cannot map, its first # two axes, its first hat, and its first two buttons. The pads are Linux # uinput devices (scripts/lib/padGate.sh), laid out as Xbox 360 pads in the # first pass and as two-button joysticks in the second, the only ones SDL is # let see; JOY runs on a private Xvfb display through SDL's X11 driver at # one window pixel per stage pixel, and window grabs go through # scripts/lib/joyScreen.py (scripts/lib/joyGate.sh). Removing the pads must # leave both sticks disconnected, and Escape must then end JOY. # # Usage: scripts/verify-sdl3-joy.sh # Env: JOY_SHOTS also keep the screenshots in this folder # Requires: write access to /dev/uinput, Xvfb, xdotool, ImageMagick, # python3 + PIL; build/sdl3/bin/JOY (make sdl3). set -uo pipefail repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) source "$repo/scripts/lib/joeyEnv.sh" source "$repo/scripts/lib/joyGate.sh" source "$repo/scripts/lib/padGate.sh" JOY_LABEL=verify-sdl3-joy JOY_SCALE=1 program=$(joeyExampleProgram joy sdl3) wall=120 # hard cap on JOY, whatever happens to this script readySeconds=10 # JOY's window up and drawn, with both pads open exitSeconds=5 # Escape until JOY has gone [ -f "$program" ] || { echo "$JOY_LABEL: build JOY first (make sdl3)" >&2; exit 2; } JOY_WORK=$(mktemp -d -t joeylib-sdl3-joy.XXXXXX) guard="" xvfb="" display="" win="" cleanup() { padStop joeyStop "$guard" "$xvfb" 2> /dev/null rm -rf "$JOY_WORK" } trap cleanup EXIT joyShot() { DISPLAY="$display" import -window "$win" "$1" 2> /dev/null } # joyPass KIND -- the whole run with KIND's pads ("" for Xbox 360 pads, # generic for plain joysticks): a fresh JOY, every step, the pads # unplugged, and Escape. joyPass() { local waited JOY_PASS="${1:-gamepad}" win="" mkdir -p "$JOY_WORK/$JOY_PASS" padStart "$JOY_WORK/$JOY_PASS" "$1" (cd "$(dirname "$program")" && exec env DISPLAY="$display" SDL_VIDEO_DRIVER=x11 SDL_AUDIO_DRIVER=dummy \ JOEYLIB_SCALE=1 JOEYLIB_ASPECT=square "${PAD_ONLY_ENV[@]}" timeout -s KILL "$wall" "$program") \ > "$JOY_WORK/$JOY_PASS/joy.log" 2>&1 & guard=$! for ((waited = 0; waited < readySeconds; waited++)); do sleep 1 win=$(joeyFindWindow "$display" "$(joeyChild "$guard")") && break done if [ -z "$win" ]; then echo "$JOY_LABEL: FAIL - $JOY_PASS: JOY's window did not come up" >&2 cat "$JOY_WORK/$JOY_PASS/joy.log" >&2 exit 1 fi DISPLAY="$display" xdotool windowfocus --sync "$win" 2> /dev/null || true sleep 1 echo "$JOY_LABEL: $JOY_PASS pass" padOrder joyCheck "rest" "A=$JOY_REST B=$JOY_REST" joyRunSteps "${JOY_STEPS_TWO_STICKS[@]}" padStop sleep "$JOY_PRESS_SECONDS" joyCheck "pads unplugged" "A=$JOY_ABSENT B=$JOY_ABSENT" DISPLAY="$display" xdotool key Escape for ((waited = 0; waited < exitSeconds; waited++)); do joeyAlive "$guard" || break sleep 1 done joeyAlive "$guard" && joyFail "Escape did not end JOY" joeyStop "$guard" 2> /dev/null guard="" } display=":$((RANDOM % 400 + 5900))" Xvfb "$display" -screen 0 1024x768x24 -nolisten tcp > /dev/null 2>&1 & xvfb=$! sleep 1 joyPass "" joyPass generic JOY_PASS="" joyResult "$JOY_LABEL" "gamepads and unmapped joysticks: both sticks, every direction, both buttons and every release; unplugged, both sticks gone; Escape ends JOY"