175 lines
6.8 KiB
Bash
Executable file
175 lines
6.8 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-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.
|
|
#
|
|
# Before the typing, the named keys the Amiga gives a second key for: the
|
|
# keypad's 8, 2, 4, and 6 as the arrows, its Enter as Return, and the right
|
|
# Alt as Alt, each held alone, and Up and the keypad's 8 held together with
|
|
# either let go first, which must leave Up down (scripts/lib/keysGate.sh) --
|
|
# read off KEYS's cells in FS-UAE's screenshots (tests/gate/keysCells.c),
|
|
# the stage found by its still empty verification row
|
|
# (tests/gate/keysRow.c).
|
|
#
|
|
# Usage: scripts/verify-amiga-input.sh
|
|
# Requires: fs-uae, Xvfb, xdotool; build/amiga/bin/Keys (make amiga);
|
|
# the Kickstart (install.sh install emulator:amiga).
|
|
set -euo pipefail
|
|
|
|
repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
|
source "$repo/scripts/lib/joeyEnv.sh"
|
|
joeyNeed FSUAE fsuae
|
|
source "$repo/scripts/lib/amigaGate.sh"
|
|
source "$repo/scripts/lib/keysGate.sh"
|
|
amigaMachine
|
|
bin_dir=$repo/build/amiga/bin
|
|
|
|
target="192.168.1.10:6510"
|
|
shotKey=F11
|
|
|
|
[ -f "$bin_dir/Keys" ] || { echo "verify-amiga-input: build Keys first (make amiga)" >&2; exit 2; }
|
|
|
|
work=$(mktemp -d -t joeylib-amiga-input.XXXXXX)
|
|
display_num=$((RANDOM % 500 + 300))
|
|
cleanup() {
|
|
joeyStop "${fsuae_pid:-}"
|
|
[ -n "${xvfb_pid:-}" ] && kill "$xvfb_pid" 2>/dev/null
|
|
rm -rf "$work"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
mkdir -p "$work/hd/s" "$work/shots"
|
|
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
|
|
|
|
# No keyboard joystick in port 1 and no modifier key: by default FS-UAE
|
|
# takes the cursor keys and the right Ctrl and Alt for a joystick, and the
|
|
# left Alt for its own shortcuts, and the Amiga never sees them.
|
|
# --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" "$FSUAE" \
|
|
"${AMIGA_MACHINE_ARGS[@]}" \
|
|
--fast_memory=2048 \
|
|
--hard_drive_0="$work/hd" \
|
|
--hard_drive_0_label=JOEYLIB \
|
|
--fullscreen=1 \
|
|
--initial_input_grab=1 \
|
|
--floppy_drive_speed=800 \
|
|
--joystick_port_1=none \
|
|
--modifier_key=none \
|
|
--keyboard_key_${shotKey,,}=action_screenshot \
|
|
--screenshots_output_dir="$work/shots" \
|
|
>/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
|
|
|
|
if ! amigaShot ":$display_num" "$shotKey" "$work/shots" "$work/stage.png"; then
|
|
echo "verify-amiga-input: FAIL - FS-UAE took no screenshot" >&2
|
|
exit 1
|
|
fi
|
|
found=$("$(joeyTool keysRow)" "$work/stage.png" "") || true
|
|
if [[ ! "$found" =~ row\ at\ \(([0-9]+),([0-9]+)\)\ at\ ([0-9]+)x ]]; then
|
|
echo "verify-amiga-input: FAIL - KEYS's stage is not on the screen: $found" >&2
|
|
exit 1
|
|
fi
|
|
scale=${BASH_REMATCH[3]}
|
|
stageAt="${BASH_REMATCH[1]},$((BASH_REMATCH[2] - 198 * scale))"
|
|
# X's names for the keys (scripts/lib/keysGate.sh's).
|
|
declare -A xKey=([up]=Up [kp8]=KP_Up [kp2]=KP_Down [kp4]=KP_Left [kp6]=KP_Right [kpenter]=KP_Enter [ralt]=Alt_R)
|
|
KEYS_LABEL=verify-amiga-input
|
|
keysPress() {
|
|
DISPLAY=":$display_num" xdotool keydown "${xKey[$1]}"
|
|
}
|
|
keysRelease() {
|
|
DISPLAY=":$display_num" xdotool keyup "${xKey[$1]}"
|
|
}
|
|
keysRead() {
|
|
if amigaShot ":$display_num" "$shotKey" "$work/shots" "$work/cells.png"; then
|
|
"$(joeyTool keysCells)" "$work/cells.png" --at "$stageAt" --scale "$scale"
|
|
else
|
|
echo "no screenshot"
|
|
fi
|
|
}
|
|
keysRunSteps kp8 kp2 kp4 kp6 kpenter ralt
|
|
if [ -n "$KEYS_FAILS" ]; then
|
|
echo "verify-amiga-input: FAIL - $KEYS_FAILS" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# 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; $KEYS_STEPS named-key steps: the keypad's arrows and Enter, right Alt, Up held with its second key)"
|
|
;;
|
|
*)
|
|
echo "verify-amiga-input: FAIL" >&2
|
|
echo " expected suffix: $expect" >&2
|
|
echo " got: $typedHex" >&2
|
|
exit 1
|
|
;;
|
|
esac
|