#!/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-dos-mouse.sh - Headless mouse acceptance gate for the DOS port. # The port has the mouse driver call it on every move and button change # (INT 33h function 0Ch, a DPMI real-mode callback, src/dos/input.c); a # callback that never runs leaves the pointer where it started. Runs # KEYS.EXE in DOSBox Staging under Xvfb with the mouse captured from the # start, moves it with xdotool (real X pointer motion), and decodes KEYS's # mouse verification scanline (row 199: 5A5A, the button flags, X, Y as # nibble pixels) from a raw screenshot after each step. Covered: the start # at the stage's middle, a move each way on both axes, clamping at all # four edges, an odd column, and press and release of the left and right # buttons. # DOSBox scales host motion into mickeys its own way, so a move is checked # by its direction and only the clamps by position, and a one-pixel nudge # by landing on an odd column: in mode 13h the driver steps X by 2 in a # 640-wide virtual screen, which the port halves, so every column counts. # # Usage: scripts/verify-dos-mouse.sh # Requires: DOSBox Staging (install.sh install emulator:dos), Xvfb, xdotool; # build/dos/bin/KEYS.EXE (make dos). set -uo pipefail repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) source "$repo/scripts/lib/joeyEnv.sh" source "$repo/scripts/lib/dosboxKeys.sh" joeyNeed DOSBOX dosbox bin_dir=$repo/build/dos/bin conf=$repo/scripts/dosbox-386sx16.conf label=verify-dos-mouse [ -f "$bin_dir/KEYS.EXE" ] || { echo "$label: build KEYS.EXE first (make dos)" >&2; exit 2; } work=$(mktemp -d -t joeylib-dos-mouse.XXXXXX) display_num=$((RANDOM % 500 + 300)) cleanup() { joeyStop "${dosbox_pid:-}" [ -n "${xvfb_pid:-}" ] && kill "$xvfb_pid" 2>/dev/null rm -rf "$work" } trap cleanup EXIT mkdir -p "$work/shots" dosboxKeysMapper "$work/mapper.txt" Xvfb ":$display_num" -screen 0 1024x768x24 >/dev/null 2>&1 & xvfb_pid=$! sleep 1 XDG_CONFIG_HOME="$work/xdg" DISPLAY=":$display_num" "$DOSBOX" "${JOEY_DOSBOX_ISOLATE[@]}" \ --conf "$conf" \ --set "capture_dir=$work/shots" \ --set "mapperfile=$work/mapper.txt" \ --set "mouse_capture=onstart" \ -c "MOUNT C $bin_dir" -c "C:" -c "KEYS.EXE" \ >"$work/dosbox.log" 2>&1 & dosbox_pid=$! # Let DOS boot and KEYS reach its poll loop on the simulated 386SX-16. sleep 12 win=$(joeyFindWindow ":$display_num" "$dosbox_pid") if [ -z "$win" ]; then echo "$label: FAIL - DOSBox window not found" >&2 exit 1 fi DISPLAY=":$display_num" xdotool windowactivate --sync "$win" 2>/dev/null || true # The mouse row of a fresh screenshot as "flags x y" (hex flags). readRow() { local png="$work/$1.png" dosboxShot ":$display_num" "$win" "$work/shots" "$png" || return 1 "$(joeyTool dosRow)" mouse "$png" } fails=() step() { local tag="$1" local row shift if [ $# -gt 0 ]; then DISPLAY=":$display_num" xdotool "$@" sleep 1 fi if ! row=$(readRow "$tag"); then fails+=("$tag: no mouse row in the screenshot") row="---- -1 -1" fi read -r flags mx my <<< "$row" echo " $tag: flags=$flags x=$mx y=$my" } step start [ "$flags $mx $my" = "1000 160 100" ] || fails+=("start: expected flags 1000 at 160,100") step upLeft mousemove_relative -- -60 -40 [ "$flags" = "1000" ] && [ "$mx" -lt 160 ] && [ "$my" -lt 100 ] || fails+=("a move up and left did not arrive") lastX=$mx lastY=$my step downRight mousemove_relative -- 120 80 [ "$flags" = "1000" ] && [ "$mx" -gt "$lastX" ] && [ "$my" -gt "$lastY" ] || fails+=("a move down and right did not arrive") step topLeft mousemove_relative -- -2000 -2000 [ "$flags $mx $my" = "1000 0 0" ] || fails+=("not held at the top left (0,0)") step nudge mousemove_relative -- 1 0 [ "$flags" = "1000" ] && [ $((mx % 2)) -eq 1 ] || fails+=("a one-pixel nudge did not reach an odd column") step bottomRight mousemove_relative -- 2000 2000 [ "$flags $mx $my" = "1000 319 199" ] || fails+=("not held at the bottom right (319,199)") step leftDown mousedown 1 [ "$flags" = "1100" ] || fails+=("the left button down not seen") step leftUp mouseup 1 [ "$flags" = "1000" ] || fails+=("the left button up not seen") step rightDown mousedown 3 [ "$flags" = "1010" ] || fails+=("the right button down not seen") step rightUp mouseup 3 [ "$flags" = "1000" ] || fails+=("the right button up not seen") if [ ${#fails[@]} -eq 0 ]; then echo "$label: PASS (moves both ways, all four edges, every column, both buttons down and up)" exit 0 fi for f in "${fails[@]}"; do echo "$label: FAIL - $f" >&2 done exit 1