#!/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-be-input.sh - Typed-character acceptance gate for a Be API port # (haiku, haiku32, beos). Runs KEYS in the port's VM under QEMU # (scripts/lib/beGate.sh) at one window pixel per stage pixel # (JOEYLIB_SCALE=1, JOEYLIB_ASPECT=square), types the RetroNet # definition-of-done string through QEMU's PS/2 keyboard (QMP send-key, # shift and all: the keys go through the system's input server and keymap # as a person's would), takes QEMU's screen and decodes the example's # verification scanline (row 198) with scripts/lib/keysRow.py, wherever the # desktop put the window. Typing starts once the screen shows KEYS's empty # row (the window is up); the screen is read until the row is whole or time # runs out. Then the named keys a second key gives (scripts/lib/keysGate.sh): # the keypad's arrows and Enter, and the right Ctrl and Alt, held through # QMP and read off KEYS's cells (scripts/lib/keysCells.py). Escape then ends # KEYS, and the VM. # # Usage: scripts/verify-be-input.sh [haiku|haiku32|beos] (default haiku) # Env: BE_INPUT_KEEP keep the last screen as build/PORT/be-input.png # when the gate fails # Requires: QEMU and the port's VM (./install.sh install emulator:PORT), # python3 + PIL; build/PORT/bin/KEYS (make PORT). set -uo pipefail repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) source "$repo/scripts/lib/joeyEnv.sh" source "$repo/scripts/lib/beGate.sh" source "$repo/scripts/lib/keysGate.sh" port=${1:-haiku} label="verify-be-input ($port)" target="192.168.1.10:6510" beNeed "$port" program=$(joeyExampleProgram keys "$port") [ -x "$program" ] || { echo "$label: build KEYS first (make $port)" >&2; exit 2; } bootSeconds=120 runSeconds=120 rowSeconds=30 escapeHoldMs=400 work=$(mktemp -d -t joeylib-be-input.XXXXXX) cleanup() { beStop rm -rf "$work" } trap cleanup EXIT # rowShown TEXT -- the screen shows KEYS's row holding TEXT, read once a # second for up to rowSeconds; the last read's verdict is printed. rowShown() { local tries for ((tries = 0; tries < rowSeconds; tries++)); do beQmp "$work" screendump "$work/keys.png" if python3 "$repo/scripts/lib/keysRow.py" "$work/keys.png" "$1" --scale 1 > "$work/row.txt"; then cat "$work/row.txt" return 0 fi sleep 1 done cat "$work/row.txt" return 1 } mkdir -p "$work/job/KEYS" cp "$program" "$work/job/KEYS/KEYS" beJobScript KEYS KEYS "" "$runSeconds" JOEYLIB_SCALE=1 JOEYLIB_ASPECT=square > "$work/job/job.sh" beJobDisk "$work/job.img" "$work/job" beStart "$work" "$work/job.img" if ! beWaitJob "$work" "$bootSeconds"; then echo "$label: FAIL - the VM did not start the job within ${bootSeconds} s" >&2 exit 1 fi if ! rowShown "" > /dev/null; then echo "$label: FAIL - KEYS's window did not come up within ${rowSeconds} s" >&2 exit 1 fi beQmp "$work" type "$target" # The stage at one pixel a pixel, wherever the window is. if rowShown "$target"; then passed=1 else passed=0 fi if [ "$passed" = 1 ] && [[ "$(cat "$work/row.txt")" =~ row\ at\ \(([0-9]+),([0-9]+)\) ]]; then stageAt="${BASH_REMATCH[1]},$((BASH_REMATCH[2] - 198))" # QEMU's names for the keys (scripts/lib/keysGate.sh's). declare -A qcode=([up]=up [kp8]=kp_8 [kp2]=kp_2 [kp4]=kp_4 [kp6]=kp_6 [kpenter]=kp_enter [rctrl]=ctrl_r [ralt]=alt_r) KEYS_LABEL=$label keysPress() { beQmp "$work" down "${qcode[$1]}" } keysRelease() { beQmp "$work" up "${qcode[$1]}" } keysRead() { beQmp "$work" screendump "$work/cells.png" python3 "$repo/scripts/lib/keysCells.py" "$work/cells.png" --at "$stageAt" } keysRunSteps kp8 kp2 kp4 kp6 kpenter rctrl ralt [ -z "$KEYS_FAILS" ] || passed=0 fi beQmp "$work" hold esc "$escapeHoldMs" beWaitExit "$work" "$runSeconds" || true if [ "$passed" = 1 ]; then echo "$label: PASS (typed \"$target\", all ${#target} chars arrived via jlInputGetChar; $KEYS_STEPS named-key steps: the keypad's arrows and Enter, right Ctrl and Alt, Up held with its second key)" else echo "$label: FAIL${KEYS_FAILS:+ - $KEYS_FAILS}" >&2 if [ -n "${BE_INPUT_KEEP:-}" ]; then cp "$work/keys.png" "$repo/build/$port/be-input.png" fi exit 1 fi