#!/usr/bin/env bash # verify-amiga-input.sh - Typed-character acceptance gate for the Amiga # port. Boots the Keys example off a directory hard drive in FS-UAE # under Xvfb, types the RetroNet definition-of-done string with xdotool # (real X key events, so ':' goes through the emulated shift and # keymap.library's MapRawKey), then presses Escape. On exit Keys logs # its full received-character history as hex to joeylog.txt on the boot # volume -- which is the staged host directory -- and the harness # compares that against the typed ASCII. # # Usage: scripts/verify-amiga-input.sh # Requires: fs-uae, Xvfb, xdotool; build/amiga/bin/Keys (make amiga); # toolchains/emulators/support/kickstart.rom. set -euo pipefail repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) bin_dir=$repo/build/amiga/bin kickstart=$repo/toolchains/emulators/support/kickstart.rom target="192.168.1.10:6510" [ -f "$bin_dir/Keys" ] || { echo "verify-amiga-input: build Keys first (make amiga)" >&2; exit 2; } [ -f "$kickstart" ] || { echo "verify-amiga-input: missing $kickstart" >&2; exit 2; } work=$(mktemp -d -t joeylib-amiga-input.XXXXXX) display_num=$((RANDOM % 500 + 300)) cleanup() { [ -n "${fsuae_pid:-}" ] && kill "$fsuae_pid" 2>/dev/null [ -n "${xvfb_pid:-}" ] && kill "$xvfb_pid" 2>/dev/null rm -rf "$work" } trap cleanup EXIT mkdir -p "$work/hd/s" cp "$bin_dir/Keys" "$work/hd/" echo ":Keys" > "$work/hd/s/startup-sequence" Xvfb ":$display_num" -screen 0 1024x768x24 >/dev/null 2>&1 & xvfb_pid=$! sleep 1 # --fullscreen=1 is REQUIRED under a WM-less Xvfb: SDL only accepts # keyboard input once its window has input focus, no window manager # ever grants it to a plain window, and xdotool's windowfocus/ # XSendEvent routes are ignored by SDL. A fullscreen SDL window takes # focus itself, after which plain XTEST typing (xdotool without # --window) lands in the emulated Amiga. DISPLAY=":$display_num" fs-uae \ --amiga_model=A500 \ --fast_memory=2048 \ --kickstart_file="$kickstart" \ --hard_drive_0="$work/hd" \ --hard_drive_0_label=JOEYLIB \ --fullscreen=1 \ --initial_input_grab=1 \ --floppy_drive_speed=800 \ >/dev/null 2>&1 & fsuae_pid=$! # Boot AmigaDOS off the directory HD and let startup-sequence launch # Keys. No sentinel channel here, so give it a generous fixed wait. sleep 28 # XTEST keyboard events land in whatever window HAS focus, and under # a WM-less Xvfb the fullscreen SDL window latches it on its own # schedule -- so wait until getwindowfocus actually reports the FS-UAE # window before typing, nudging with windowfocus while waiting. win=$(DISPLAY=":$display_num" xdotool search --name -- "FS-UAE" | head -1) for i in $(seq 1 30); do focus=$(DISPLAY=":$display_num" xdotool getwindowfocus 2>/dev/null || true) [ -n "$win" ] && [ "$focus" = "$win" ] && break [ -n "$win" ] && DISPLAY=":$display_num" xdotool windowfocus --sync "$win" 2>/dev/null || true sleep 1 [ -z "$win" ] && win=$(DISPLAY=":$display_num" xdotool search --name -- "FS-UAE" | head -1) done # Up to three attempts: type, press Escape, then look for the typed= # line Keys logs on exit. The verdict compares the history's SUFFIX # against the target, so a partially-delivered early attempt can't # poison a complete later one -- the proof is that the final 17 # characters arrived in order through the queue. log="$work/hd/joeylog.txt" delivered="" for attempt in 1 2 3; do DISPLAY=":$display_num" xdotool type --delay 200 -- "$target" sleep 2 # Hold Escape across several emulated frames: an instantaneous # down+up can land inside ONE drainMessages pass, where set-then- # clear in the same poll is invisible to the edge predicate. DISPLAY=":$display_num" xdotool keydown Escape sleep 0.5 DISPLAY=":$display_num" xdotool keyup Escape for i in $(seq 1 10); do if [ -f "$log" ] && grep -q "typed=" "$log"; then delivered=1 break 2 fi sleep 1 done done if [ -z "$delivered" ]; then echo "verify-amiga-input: FAIL - no typed= line in joeylog.txt (keystrokes never landed?)" >&2 ls -la "$work/hd" >&2 exit 1 fi typedHex=$(grep -o "typed=[0-9A-Fa-f]*" "$log" | tail -1 | cut -d= -f2) expect=$(printf '%s' "$target" | od -A n -t x1 | tr -d ' \n' | tr 'a-f' 'A-F') echo "VERIFY-AMIGA-INPUT typed=$typedHex" case "$typedHex" in *"$expect") echo "verify-amiga-input: PASS (typed \"$target\", all ${#target} chars arrived via jlInputGetChar)" ;; *) echo "verify-amiga-input: FAIL" >&2 echo " expected suffix: $expect" >&2 echo " got: $typedHex" >&2 exit 1 ;; esac