176 lines
7.4 KiB
Bash
Executable file
176 lines
7.4 KiB
Bash
Executable file
#!/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-dvx-joy.sh - Joystick gate for DVX: both sticks, every direction,
|
|
# both buttons and every release, driven through DOSBox Staging's emulated
|
|
# game port and read back from what examples/joy draws; and no joystick at
|
|
# all when the game port is empty, though DVX then offers its keyboard
|
|
# joystick.
|
|
#
|
|
# The port (src/dvx/input.c) reads DVX's joystick library: its first two
|
|
# devices that are real joysticks, each axis -32768..32767 >> 8, clamped to
|
|
# -127..127. DOSBox Staging's joysticktype 4axis puts four axes and four
|
|
# buttons on the game port with no host joystick, which DVX's game port
|
|
# driver (two-stick mode, its default) reads as two sticks, A and B, exactly
|
|
# as a Y cable would give it. A mapper file binds host keys to DOSBox's
|
|
# joystick events (scripts/lib/dosboxJoy.sh, as DVX's own tests do,
|
|
# src/test/dos/joyDrive.py), and xdotool holds them; the raw screenshot is
|
|
# bound to a key of its own, so no Ctrl reaches the program. With no host
|
|
# joystick nothing else moves the stick: it rests in the middle, buttons up.
|
|
#
|
|
# JOY (examples/joy) draws, for each stick, a dot (in the middle at rest,
|
|
# grey; green when moved), two button squares and a patch that says whether
|
|
# the port reports a stick; scripts/lib/joyScreen.py reads the WHOLE state of
|
|
# BOTH sticks off each screenshot (scripts/lib/joyGate.sh's steps: each
|
|
# direction of each stick alone, two diagonals each, each button alone and
|
|
# both together, with a release after every press so a latched line shows
|
|
# up, and a step holding different lines on both sticks at once so
|
|
# crosstalk shows up too). Axes are judged as DVX's own tests judge them,
|
|
# beyond half way: an uncalibrated DVX axis ranges itself as it moves, so a
|
|
# full push reads a little short of the end. Escape then ends JOY, which
|
|
# must leave DVX cleanly ("reaped").
|
|
#
|
|
# Second run, joysticktype disabled: DVX finds no game port stick and falls
|
|
# back to its keyboard joystick (the arrows, LCtrl, Space...), which the
|
|
# port leaves out, as every port reports no joystick then: JOY must show
|
|
# both sticks disconnected at rest while the keyboard joystick's Left and
|
|
# Space are held (the mapper binds them too in that run).
|
|
#
|
|
# Usage: scripts/verify-dvx-joy.sh
|
|
# Env: JOY_SHOTS also keep the screenshots in this folder
|
|
# Requires: DOSBox Staging, Xvfb, xdotool, python3 + PIL, the dvx component;
|
|
# the joy program (make dvx).
|
|
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/dosboxJoy.sh"
|
|
source "$repo/scripts/lib/dvxGate.sh"
|
|
joeyNeed DOSBOX dosbox
|
|
joeyNeed DVX_ROOT dvx
|
|
|
|
JOY_LABEL=verify-dvx-joy
|
|
program=joy
|
|
wall=240 # hard cap on each DOSBox run, whatever happens to this script
|
|
readySeconds=60 # DVX boot until its shell reports ready
|
|
settleSeconds=3 # then JOY opening its window and taking the focus
|
|
exitSeconds=10 # Escape until DVX reaps JOY
|
|
# DVX.LOG when the game port gives two sticks, and when it has none and the
|
|
# keyboard joystick stands in.
|
|
twoSticksLog="Joystick: 2 device(s) found"
|
|
keyboardLog="Joystick: keyboard0"
|
|
reapedLog="Shell: reaped app 'Joy'"
|
|
# DVX's keyboard joystick keys the second run holds (xdotool's names), and
|
|
# their mapper bindings: Left and Space (SDL scancodes 80 and 44).
|
|
keyboardKeys=(Left space)
|
|
keyboardBinds='key_left "key 80"
|
|
key_space "key 44"'
|
|
|
|
dvxNeedBuild "$program"
|
|
|
|
JOY_WORK=$(mktemp -d -t joeylib-dvx-joy.XXXXXX)
|
|
guard=""
|
|
dosbox=""
|
|
xvfb=""
|
|
# 2>/dev/null: bash reports the SIGKILLed timeout wrapper as "Killed".
|
|
cleanup() {
|
|
joeyStop "$dosbox" "$guard" "$xvfb" 2> /dev/null
|
|
rm -rf "$JOY_WORK"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
|
|
# boot RUN JOYTYPE [BINDS] -- DVX staged in $JOY_WORK/RUN with JOY its
|
|
# desktop, DOSBox's joysticktype JOYTYPE and the joystick mapper (with BINDS
|
|
# appended); sets guard, dosbox and DOSBOX_JOY_WINDOW.
|
|
boot() {
|
|
local dir="$JOY_WORK/$1"
|
|
local waited
|
|
dvxStage "$dir/c" "$(dvxAppDir "$program")"
|
|
dvxDosboxConf "$dir/dosbox.conf" "$dir/c"
|
|
mkdir -p "$dir/xdg" "$dir/shots"
|
|
dosboxJoyMapper "$dir/mapper.txt"
|
|
[ -z "${3:-}" ] || printf '%s\n' "$3" >> "$dir/mapper.txt"
|
|
DOSBOX_JOY_SHOTS="$dir/shots"
|
|
printf '\n[capture]\ncapture_dir = %s\n' "$dir/shots" >> "$dir/dosbox.conf"
|
|
printf '\n[joystick]\njoysticktype = %s\n' "$2" >> "$dir/dosbox.conf"
|
|
printf '\n[sdl]\nmapperfile = %s\n' "$dir/mapper.txt" >> "$dir/dosbox.conf"
|
|
XDG_CONFIG_HOME="$dir/xdg" DISPLAY="$DOSBOX_JOY_DISPLAY" SDL_AUDIODRIVER=dummy \
|
|
timeout -s KILL "$wall" "$DOSBOX" "${JOEY_DOSBOX_ISOLATE[@]}" \
|
|
--conf "$dir/dosbox.conf" > "$dir/dosbox.log" 2>&1 &
|
|
guard=$!
|
|
dosbox=$(joeyChild "$guard")
|
|
for ((waited = 0; waited < readySeconds; waited++)); do
|
|
if dvxDvxLog "$dir/c" 200 | grep -q "DVX Shell ready"; then
|
|
sleep "$settleSeconds"
|
|
DOSBOX_JOY_WINDOW=$(joeyFindWindow "$DOSBOX_JOY_DISPLAY" "$dosbox")
|
|
[ -n "$DOSBOX_JOY_WINDOW" ] || return 1
|
|
DISPLAY="$DOSBOX_JOY_DISPLAY" xdotool windowactivate --sync "$DOSBOX_JOY_WINDOW" 2> /dev/null || true
|
|
return 0
|
|
fi
|
|
joeyAlive "$guard" || return 1
|
|
sleep 1
|
|
done
|
|
return 1
|
|
}
|
|
|
|
|
|
# keyboardJoystick keydown|keyup -- hold or let go of DVX's keyboard
|
|
# joystick keys.
|
|
keyboardJoystick() {
|
|
local k
|
|
for k in "${keyboardKeys[@]}"; do
|
|
DISPLAY="$DOSBOX_JOY_DISPLAY" xdotool "$1" --window "$DOSBOX_JOY_WINDOW" "$k"
|
|
done
|
|
}
|
|
|
|
|
|
# stop -- end the DOSBox run.
|
|
stop() {
|
|
joeyStop "$dosbox" "$guard" 2> /dev/null
|
|
dosbox=""
|
|
guard=""
|
|
}
|
|
|
|
|
|
DOSBOX_JOY_DISPLAY=":$((RANDOM % 400 + 4300))"
|
|
Xvfb "$DOSBOX_JOY_DISPLAY" -screen 0 1024x768x24 -nolisten tcp > /dev/null 2>&1 &
|
|
xvfb=$!
|
|
sleep 1
|
|
|
|
# 1. Both sticks on the game port, moved through the mapper.
|
|
if ! boot sticks 4axis; then
|
|
echo "$JOY_LABEL: FAIL - DVX with JOY did not come up (DVX.LOG follows)" >&2
|
|
dvxDvxLog "$JOY_WORK/sticks/c" >&2
|
|
exit 1
|
|
fi
|
|
dvxDvxLog "$JOY_WORK/sticks/c" 400 | grep -q "$twoSticksLog" || joyFail "DVX.LOG has no \"$twoSticksLog\": $(dvxDvxLog "$JOY_WORK/sticks/c" 400 | grep 'Joystick:' | tr '\n' ' ')"
|
|
joyCheck "rest" "A=$JOY_REST B=$JOY_REST"
|
|
joyRunSteps "${JOY_STEPS_TWO_STICKS[@]}"
|
|
dosboxJoyTap escape
|
|
for ((waited = 0; waited < exitSeconds; waited++)); do
|
|
dvxDvxLog "$JOY_WORK/sticks/c" 400 | grep -qF "$reapedLog" && break
|
|
sleep 1
|
|
done
|
|
dvxDvxLog "$JOY_WORK/sticks/c" 400 | grep -qF "$reapedLog" || joyFail "Escape did not end JOY (no \"$reapedLog\" in DVX.LOG)"
|
|
stop
|
|
|
|
# 2. No stick on the game port: DVX's keyboard joystick stands in, and the
|
|
# port must leave it out.
|
|
if ! boot none disabled "$keyboardBinds"; then
|
|
echo "$JOY_LABEL: FAIL - DVX with JOY and no joystick did not come up (DVX.LOG follows)" >&2
|
|
dvxDvxLog "$JOY_WORK/none/c" >&2
|
|
exit 1
|
|
fi
|
|
dvxDvxLog "$JOY_WORK/none/c" 400 | grep -q "$keyboardLog" || joyFail "DVX.LOG has no \"$keyboardLog\" (the keyboard joystick): $(dvxDvxLog "$JOY_WORK/none/c" 400 | grep 'Joystick:' | tr '\n' ' ')"
|
|
joyCheck "no joystick" "A=$JOY_ABSENT B=$JOY_ABSENT"
|
|
keyboardJoystick keydown
|
|
sleep "$JOY_PRESS_SECONDS"
|
|
joyCheck "no joystick, keyboard joystick held" "A=$JOY_ABSENT B=$JOY_ABSENT"
|
|
keyboardJoystick keyup
|
|
stop
|
|
|
|
joyResult "$JOY_LABEL" "both sticks, every direction, both buttons and every release; no joystick without one, the keyboard joystick left out"
|