#!/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-win16-joy.sh - Joystick gate for the Win16 port: both sticks, # every direction, both buttons and every release, driven through DOSBox # Staging's emulated game port, read by Windows through KPJOY.DRV (the # joystick driver JoeyLib's Windows runs with, component kpjoy) and read # back from what examples/joy draws; and no joystick at all when the game # port is empty. # # The port (src/hosted/win16) reads the first two sticks through MMSYSTEM's # joyGetPos, scaled by joyGetDevCaps's ranges. DOSBox Staging's joysticktype # 4axis puts four axes and four buttons on the game port with no host # joystick, which KPJOY reads as two sticks, A and B, as a Y cable gives # them; it takes each axis's rest from its first readings and reports # readings near the rest as the rest, so the dots sit exactly in the middle # through the jitter interrupts give the counts. KPJOY counts reads of the # port, so the emulated CPU runs at a fixed speed, as a real PC's does: at # DOSBox's max cycles (how joey-run runs Windows) the speed follows this # machine's load, and the counts with it. A mapper file binds host keys to # DOSBox's joystick events (scripts/lib/dosboxJoy.sh) and xdotool holds # them; the raw screenshot is on a key of its own, so no Ctrl reaches # Windows. The mapper also leaves out any joystick plugged into this # machine, so nothing else moves the sticks: they rest in the middle, # buttons up. # # JOY (examples/joy) is Windows' shell, at one window pixel per stage pixel; # tests/gate/joyScreen.c reads both sticks' whole state off each # screenshot of the 800x600 screen (scripts/lib/joyGate.sh's steps). Escape # then ends JOY, and with it Windows and DOSBox. # # Second run, joysticktype disabled: no game port, so JOY must show both # sticks disconnected. # # Usage: scripts/verify-win16-joy.sh # Env: JOY_SHOTS also keep the screenshots in this folder # Requires: DOSBox Staging, Xvfb, xdotool, the win311 and # kpjoy components; JOY.EXE (make win16). 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/win16Gate.sh" win16Need JOY_LABEL=verify-win16-joy JOY_SCALE=1 program=$(joeyExampleProgram joy win16) [ -f "$program" ] || { echo "$JOY_LABEL: build JOY.EXE first (make win16)" >&2; exit 2; } upSeconds=60 # Windows booting until JOY's screen is there exitSeconds=20 # Escape until Windows and DOSBox have ended fixedCycles=60000 # the emulated CPU's speed (DOSBox cycles per ms) JOY_WORK=$(mktemp -d -t joeylib-win16-joy.XXXXXX) cleanup() { win16Stop rm -rf "$JOY_WORK" } trap cleanup EXIT # boot RUN JOYTYPE -- Windows staged in $JOY_WORK/RUN with JOY its shell, # DOSBox's joysticktype JOYTYPE and the joystick mapper; waits for JOY's # screen. boot() { local dir="$JOY_WORK/$1" local waited mkdir -p "$dir/program" "$dir/shots" cp "$program" "$dir/program/JOY.EXE" win16Stage "$dir" "$dir/program" JOY.EXE dosboxJoyMapper "$dir/mapper.txt" DOSBOX_JOY_SHOTS="$dir/shots" WIN16_DOSBOX_ARGS=(--set "capture_dir=$dir/shots" --set "default_image_capture_formats=raw" --set "joysticktype=$2" "${DOSBOX_JOY_SET_ARGS[@]}" --set "mapperfile=$dir/mapper.txt" --set "cpu_cycles=$fixedCycles" --set "cpu_cycles_protected=$fixedCycles") win16Start "$dir" JOEYLIB_SCALE=1 JOEYLIB_ASPECT=square DOSBOX_JOY_DISPLAY="$WIN16_DISPLAY" for ((waited = 0; waited < upSeconds; waited++)); do joeyAlive "$WIN16_PID" || return 1 DOSBOX_JOY_WINDOW=$(win16Window) && break sleep 1 done [ -n "$DOSBOX_JOY_WINDOW" ] || return 1 DISPLAY="$DOSBOX_JOY_DISPLAY" xdotool windowactivate --sync "$DOSBOX_JOY_WINDOW" 2> /dev/null || true for ((; waited < upSeconds; waited++)); do joyShot "$dir/up.png" && "$(joeyTool joyScreen)" "$dir/up.png" --scale "$JOY_SCALE" > /dev/null 2>&1 && return 0 joeyAlive "$WIN16_PID" || return 1 sleep 1 done return 1 } # 1. Both sticks on the game port, moved through the mapper. boot sticks 4axis || { echo "$JOY_LABEL: FAIL - Windows with JOY did not come up within ${upSeconds} s" >&2; exit 1; } joyCheck "rest" "A=$JOY_REST B=$JOY_REST" joyRunSteps "${JOY_STEPS_TWO_STICKS[@]}" dosboxJoyTap escape for ((waited = 0; waited < exitSeconds; waited++)); do joeyAlive "$WIN16_PID" || break sleep 1 done joeyAlive "$WIN16_PID" && joyFail "Escape did not end JOY, and Windows with it, within ${exitSeconds} s" win16Stop # 2. No game port: no stick. boot none disabled || { echo "$JOY_LABEL: FAIL - Windows with JOY and no game port did not come up within ${upSeconds} s" >&2; exit 1; } joyCheck "no joystick" "A=$JOY_ABSENT B=$JOY_ABSENT" win16Stop joyResult "$JOY_LABEL" "both sticks through KPJOY.DRV, every direction, both buttons and every release; no stick without a game port"