joeylib2/scripts/verify-iigs-mouse.sh
2026-10-19 15:46:47 -05:00

161 lines
6.2 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-iigs-mouse.sh - Headless gate for the IIgs's mouse buttons. Every
# port has two, and the IIgs's ADB mouse has one: a left click made with
# Ctrl held is the right button (src/core/input.c, mouseCtrlClick), read
# through the asm snapshot and predicates (joeyDraw.s). Boots GS/OS under
# MAME and launches the KEYS example off joey.2mg, which stamps the mouse's
# state on its stage row 199: the sentinel 5A5A, then present, left,
# right, and a zero nibble. Presses the emulated mouse button and Ctrl in
# turn and reads the row straight out of SHR memory after each:
#
# start present, no button
# click left
# click let go none
# Ctrl-click right, not left
# Ctrl let go first still right (until the button is let go)
# Ctrl-click let go none
# click, then Ctrl left: Ctrl after the press changes nothing
# both let go none
#
# Then Escape: KEYS must quit to the Finder.
#
# Usage: scripts/verify-iigs-mouse.sh
# Requires: ./install.sh install iigs; build/iigs/bin/joey.2mg built
# with the current KEYS (make iigs-disk).
set -euo pipefail
repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
source "$repo/scripts/lib/joeyEnv.sh"
joeyNeed MAME mame
joeyNeed IIGS_ROMPATH iigsFirmware
joeyNeed GSOS_SYSTEM_DISK iigsFirmware
label=verify-iigs-mouse
sys_disk=$GSOS_SYSTEM_DISK
data_disk=$repo/build/iigs/bin/joey.2mg
for f in "$sys_disk" "$data_disk"; do
[ -f "$f" ] || { echo "$label: missing $f (run 'make iigs-disk')" >&2; exit 2; }
done
work=$(mktemp -d -t joeylib-mouse-verify.XXXXXX)
trap 'rm -rf "$work"' EXIT
cp "$sys_disk" "$work/boot.po"
cp "$data_disk" "$work/joey.2mg"
# Finder keystroke timeline as in verify-iigs-keys.sh. KEYS' mouse row is
# stage row 199, the SHR bytes from $E1/2000 + 199*160 = $E1/9C60, two
# nibble pixels a byte: 5A 5A, then the flags word (present 1000, left
# 0100, right 0010). SCB 0 is $E1/9D00. Each step waits 90 frames (1.5 s)
# before the row is read: KEYS restamps it at its next frame.
cat > "$work/verify.lua" <<'LUA'
local cpu = manager.machine.devices[":maincpu"]
local mem = cpu.spaces["program"]
local nat = manager.machine.natkeyboard
local frame = 0
local idx = 1
local function field(port, name)
local p = manager.machine.ioport.ports[port]
if p == nil then return nil end
return p.fields[name]
end
local key_cmd = field(":macadb:KEY3", "Command / Open Apple")
local key_ctrl = field(":macadb:KEY3", "Control")
local key_esc = field(":macadb:KEY3", "Esc")
local button = field(":macadb:MOUSE0", "Mouse Button")
local function press(f) if f then f:set_value(1) end end
local function release(f) if f then f:set_value(0) end end
local function report(tag)
local row = ""
for i = 0, 3 do
row = row .. string.format("%02X", mem:read_u8(0xE19C60 + i))
end
io.write(string.format("VERIFY-IIGS-MOUSE %s scb0=%02X row=%s\n", tag, mem:read_u8(0xE19D00), row))
io.flush()
end
local steps = {
{3000, function() nat:post("J") end},
{3120, function() press(key_cmd) end},
{3126, function() nat:post("o") end},
{3180, function() release(key_cmd) end},
{3540, function() nat:post("KEYS") end},
{3660, function() press(key_cmd) end},
{3666, function() nat:post("o") end},
{3720, function() release(key_cmd) end},
{6600, function() report("start") end},
{6610, function() press(button) end},
{6700, function() report("click") end},
{6710, function() release(button) end},
{6800, function() report("clickLetGo") end},
{6810, function() press(key_ctrl) end},
{6840, function() press(button) end},
{6930, function() report("ctrlClick") end},
{6940, function() release(key_ctrl) end},
{7030, function() report("ctrlLetGoFirst") end},
{7040, function() release(button) end},
{7130, function() report("ctrlClickLetGo") end},
{7140, function() press(button) end},
{7170, function() press(key_ctrl) end},
{7260, function() report("clickThenCtrl") end},
{7270, function() release(button) end},
{7280, function() release(key_ctrl) end},
{7370, function() report("bothLetGo") end},
{7380, function() press(key_esc) end},
{7400, function() release(key_esc) end},
{9600, function() report("escape"); manager.machine:exit() end},
}
emu.register_frame_done(function()
frame = frame + 1
while idx <= #steps and frame >= steps[idx][1] do
steps[idx][2]()
idx = idx + 1
end
end)
LUA
cd "$work"
out=$(QT_QPA_PLATFORM=offscreen SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy \
timeout 300 "$MAME" apple2gs \
-rompath "$IIGS_ROMPATH" \
-flop3 "$work/boot.po" -flop4 "$work/joey.2mg" \
-video none -sound none -nothrottle \
-autoboot_script "$work/verify.lua" </dev/null 2>&1) || true
report=$(echo "$out" | grep -E '^VERIFY-IIGS-MOUSE ' || true)
echo "$report"
value() {
echo "$report" | grep " $1 " | sed -E "s/.*$2=([0-9A-Fa-f]+).*/\1/"
}
fails=()
[ "$(value start scb0)" = "00" ] || fails+=("KEYS never launched (SCB 0 $(value start scb0))")
# step, the row it must show, what that means
for check in "start 5A5A1000 present, no button" \
"click 5A5A1100 the left button" \
"clickLetGo 5A5A1000 no button" \
"ctrlClick 5A5A1010 the right button" \
"ctrlLetGoFirst 5A5A1010 the right button" \
"ctrlClickLetGo 5A5A1000 no button" \
"clickThenCtrl 5A5A1100 the left button" \
"bothLetGo 5A5A1000 no button"; do
read -r step want meaning <<< "$check"
got=$(value "$step" row)
[ "$got" = "$want" ] || fails+=("$step: row ${got:-none}, want $want ($meaning)")
done
scb=$(value escape scb0)
[ -n "$scb" ] && [ $((16#$scb)) -ge 128 ] || fails+=("Escape did not quit KEYS (SCB 0 ${scb:-none})")
if [ ${#fails[@]} -eq 0 ]; then
echo "$label: PASS (the mouse button is left, and right when Ctrl is held as it goes down, until it is let go; Escape quit KEYS)"
exit 0
fi
for f in "${fails[@]}"; do
echo "$label: FAIL - $f" >&2
done
exit 1