211 lines
7.6 KiB
Bash
Executable file
211 lines
7.6 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-input.sh - Typed-character and present gate for DVX. Runs KEYS
|
|
# (examples/keys) as the desktop of a scratch DVX in DOSBox Staging under
|
|
# Xvfb and types the RetroNet definition-of-done string with xdotool (real X
|
|
# key events: ':' needs Shift, which DVX's keyboard layout applies before the
|
|
# window's onKey hands the character to jlInputGetChar). Three checks:
|
|
# 1. DVX's reserved chord: Ctrl+Esc (the Task Manager) must not reach KEYS
|
|
# as Esc, which would end it (its typed line appears in its log); the
|
|
# Task Manager's Switch To gives KEYS the focus back;
|
|
# 2. the present: a raw screenshot of the desktop must show KEYS's
|
|
# verification scanline (row 198: sentinel, count, every received
|
|
# character as two pixel nibbles) somewhere -- the window's content,
|
|
# expanded from the stage through the port's palette tables into the
|
|
# desktop's pixel format at the window's scale -- decoding to exactly
|
|
# the typed bytes, every stage pixel a whole scale x scale block
|
|
# (tests/gate/keysRow.c);
|
|
# 3. the typed history: after Escape, KEYS logs every received character
|
|
# as hex to its joeylog.txt (in its user folder), which must equal
|
|
# the typed ASCII.
|
|
# Each desktop given (default 640x480 at 16 bits, where the window is 1x) is
|
|
# a run of its own, the window 4:3 or (":square") with square pixels;
|
|
# DVX.LOG must show KEYS's window on that desktop at the scale and in the
|
|
# shape given.
|
|
#
|
|
# Usage: scripts/verify-dvx-input.sh [WxHxBPP:SCALE[:square]]...
|
|
# e.g. scripts/verify-dvx-input.sh 800x600x8:2 1024x768x32:3
|
|
# Requires: DOSBox Staging, Xvfb, xdotool, the dvx component;
|
|
# the keys program (make dvx).
|
|
set -uo pipefail
|
|
|
|
repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
|
source "$repo/scripts/lib/joeyEnv.sh"
|
|
source "$repo/scripts/lib/dvxGate.sh"
|
|
joeyNeed DOSBOX dosbox
|
|
joeyNeed DVX_ROOT dvx
|
|
|
|
program=keys
|
|
target="192.168.1.10:6510"
|
|
stageWidth=320
|
|
stageHeight=200
|
|
shape43Height=240 # a 4:3 window's rows a scale for the stage's 200
|
|
wall=180 # hard cap on DOSBox, whatever happens to this script
|
|
readySeconds=60 # DVX boot until its shell reports ready
|
|
settleSeconds=3 # then KEYS opening its window and taking the focus
|
|
stepSeconds=2 # a key, then DVX and KEYS acting on it
|
|
holdSeconds=0.3 # a key held that long: a quick tap can fall between two polls
|
|
logSeconds=30 # Escape until KEYS's typed line is in its log
|
|
specs=("$@")
|
|
[ ${#specs[@]} -gt 0 ] || specs=(640x480x16:1)
|
|
|
|
dvxNeedBuild "$program"
|
|
|
|
work=$(mktemp -d -t joeylib-dvx-input.XXXXXX)
|
|
guard=""
|
|
dosbox=""
|
|
xvfb=""
|
|
win=""
|
|
fails=""
|
|
# 2>/dev/null: bash reports the SIGKILLed timeout wrapper as "Killed".
|
|
cleanup() {
|
|
joeyStop "$dosbox" "$guard" "$xvfb" 2> /dev/null
|
|
rm -rf "$work"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
|
|
# fail SPEC WHAT -- note a failed check; the gate goes on to report the rest.
|
|
fail() {
|
|
echo "verify-dvx-input: FAIL - $1: $2"
|
|
fails="${fails:+$fails; }$1: $2"
|
|
}
|
|
|
|
|
|
# hold KEY... -- press the keys in order, each held holdSeconds before the
|
|
# next (a chord's modifier goes down first), release them in reverse, then
|
|
# give DVX and KEYS time to act.
|
|
hold() {
|
|
local k
|
|
local i
|
|
for k in "$@"; do
|
|
DISPLAY="$display" xdotool keydown --window "$win" "$k"
|
|
sleep "$holdSeconds"
|
|
done
|
|
for ((i = $#; i >= 1; i--)); do
|
|
DISPLAY="$display" xdotool keyup --window "$win" "${!i}"
|
|
done
|
|
sleep "$stepSeconds"
|
|
}
|
|
|
|
|
|
# run SPEC -- one desktop: boot, type, Ctrl+Esc, screenshot, Escape, judge.
|
|
run() {
|
|
local spec="$1"
|
|
local dir="$work/$1"
|
|
local w
|
|
local h
|
|
local bpp
|
|
local scale
|
|
local shape
|
|
local rows
|
|
local ready=""
|
|
local waited
|
|
local log
|
|
local png
|
|
|
|
if ! [[ "$spec" =~ ^([0-9]+)x([0-9]+)x([0-9]+):([0-9]+)(:square)?$ ]]; then
|
|
echo "verify-dvx-input: bad desktop \"$spec\" (WxHxBPP:SCALE[:square])" >&2
|
|
exit 2
|
|
fi
|
|
w=${BASH_REMATCH[1]}
|
|
h=${BASH_REMATCH[2]}
|
|
bpp=${BASH_REMATCH[3]}
|
|
scale=${BASH_REMATCH[4]}
|
|
DVX_VIDEO_W=$w DVX_VIDEO_H=$h DVX_VIDEO_BPP=$bpp dvxStage "$dir/c" "$(dvxAppDir "$program")"
|
|
if [ -n "${BASH_REMATCH[5]}" ]; then
|
|
shape=square
|
|
rows=$((stageHeight * scale))
|
|
dvxSettings "$dir/c" "$program" "$DVX_SETTINGS_SQUARE"
|
|
else
|
|
shape=4:3
|
|
rows=$((shape43Height * scale))
|
|
fi
|
|
dvxDosboxConf "$dir/dosbox.conf" "$dir/c"
|
|
printf '\n[capture]\ncapture_dir = %s\ndefault_image_capture_formats = raw\n' "$dir/shots" >> "$dir/dosbox.conf"
|
|
mkdir -p "$dir/xdg" "$dir/shots"
|
|
|
|
XDG_CONFIG_HOME="$dir/xdg" DISPLAY="$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
|
|
ready=1
|
|
break
|
|
fi
|
|
joeyAlive "$guard" || break
|
|
sleep 1
|
|
done
|
|
if [ -z "$ready" ]; then
|
|
fail "$spec" "DVX did not come up within ${readySeconds}s (DVX.LOG follows)"
|
|
dvxDvxLog "$dir/c" >&2
|
|
joeyStop "$dosbox" "$guard" 2> /dev/null
|
|
return
|
|
fi
|
|
sleep "$settleSeconds"
|
|
|
|
win=$(joeyFindWindow "$display" "$dosbox")
|
|
if [ -z "$win" ]; then
|
|
fail "$spec" "DOSBox window not found"
|
|
joeyStop "$dosbox" "$guard" 2> /dev/null
|
|
return
|
|
fi
|
|
DISPLAY="$display" xdotool windowactivate --sync "$win" 2> /dev/null || true
|
|
DISPLAY="$display" xdotool type --window "$win" --delay 150 -- "$target"
|
|
sleep "$stepSeconds"
|
|
# DVX's Task Manager chord, then its Switch To back to KEYS.
|
|
hold ctrl Escape
|
|
log=$(dvxProgramLog "$dir/c" "$program")
|
|
if [ -n "$log" ] && tr -d '\r' < "$log" | grep -q '^typed='; then
|
|
fail "$spec" "Ctrl+Esc reached KEYS as Esc (it ended)"
|
|
fi
|
|
hold alt s
|
|
# Ctrl+F5 = DOSBox screenshot hotkey.
|
|
DISPLAY="$display" xdotool key --window "$win" ctrl+F5
|
|
sleep "$stepSeconds"
|
|
DISPLAY="$display" xdotool key --window "$win" Escape
|
|
|
|
log=$(dvxAwaitLog "$dir/c" "$program" '^typed=' "$logSeconds" "$guard")
|
|
cp "$log" "$dir/joeylog.txt" 2> /dev/null
|
|
joeyStop "$dosbox" "$guard" 2> /dev/null
|
|
dosbox=""
|
|
guard=""
|
|
|
|
if ! dvxDvxLog "$dir/c" 400 | grep -qF "JoeyLib: Keys: $((stageWidth * scale))x$rows at ${scale}x, $shape, on a ${w}x${h} ${bpp}-bit desktop"; then
|
|
fail "$spec" "DVX.LOG does not show KEYS at ${scale}x, $shape, on a ${w}x${h} ${bpp}-bit desktop: $(dvxDvxLog "$dir/c" 400 | grep -F 'JoeyLib: Keys:')"
|
|
fi
|
|
png=$(ls "$dir"/shots/*.png 2> /dev/null | head -1)
|
|
if [ -z "$png" ]; then
|
|
fail "$spec" "no screenshot captured"
|
|
else
|
|
"$(joeyTool keysRow)" "$png" "$target" --scale "$scale" || fail "$spec" "the present"
|
|
fi
|
|
if [ -z "$log" ]; then
|
|
fail "$spec" "KEYS logged no typed line within ${logSeconds}s of Escape"
|
|
else
|
|
dvxKeysTyped "$dir/joeylog.txt" "$target" || fail "$spec" "the log"
|
|
fi
|
|
}
|
|
|
|
|
|
display=":$((RANDOM % 400 + 2500))"
|
|
Xvfb "$display" -screen 0 1024x768x24 -nolisten tcp > /dev/null 2>&1 &
|
|
xvfb=$!
|
|
sleep 1
|
|
|
|
for spec in "${specs[@]}"; do
|
|
echo "verify-dvx-input: $spec"
|
|
run "$spec"
|
|
done
|
|
|
|
if [ -n "$fails" ]; then
|
|
echo "verify-dvx-input: FAIL - $fails"
|
|
exit 1
|
|
fi
|
|
echo "verify-dvx-input: PASS (${specs[*]}: typed \"$target\", all ${#target} chars reached jlInputGetChar, Ctrl+Esc did not end KEYS, and the present shows them)"
|