tools: reach OPTIONS by the WRAP, not by counting presses

options_draw_capture.sh counted three DOWNs. A dropped press lands the cursor on
TUTORIAL, whose (A) starts the tutorial. My two attempts to avoid counting were
both worse: 'press until the cursor stops moving' is unreachable on a wrapping
menu, and an earlier version of it read the same row twice after a lost press
and pressed (A) on NEW GAME.

The wrap is the landmark. Press down until the row DECREASES -- the cursor is
then on item 1 whatever it started on -- and take three steps, retrying any
press that does not move the cursor, aborting rather than pressing (A) if one
never lands. Needs the row to be monotone in the item, not calibrated.

Also: 1200 s title deadline, and the emulator is killed at the end.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
This commit is contained in:
sylph-decoder
2026-08-31 07:06:49 +00:00
parent 088df913b2
commit 871e80ba85

View File

@@ -1,6 +1,20 @@
#!/usr/bin/env bash
# Boot -> first title -> main menu -> OPTIONS, and capture the UI draw order
# there. OPTIONS is the fourth menu item, so: three d-pad steps down, then (A).
# Boot -> first title -> main menu -> OPTIONS, and capture the UI draw order and
# the BLEND STATE there. OPTIONS is the fourth menu item.
#
# 🔴 It used to say "so: three d-pad steps down, then (A)" and do exactly that.
# Counting presses does not work here -- presses get dropped, and a dropped one
# lands the cursor on TUTORIAL, whose (A) starts the tutorial. Two later attempts
# to avoid counting were worse: "press until the cursor stops moving" is
# unreachable on a menu that WRAPS, and an earlier version of it read the same
# row twice because the first press was lost and pressed (A) on NEW GAME.
#
# What works is to use the wrap as the landmark. Press down until the row
# DECREASES -- that is the wrap, and the cursor is now on item 1 whatever it
# started on -- then take exactly three verified steps, retrying any press that
# does not move the cursor. Geometry-free: it needs the row to be monotone in the
# item, not calibrated, and ring_row.py's ROW0/SPACING are x11grab constants that
# do not fit a `screenshot` grab (METHOD.md).
#
# The recipe for the first two hops is measured, not guessed (see
# docs/re/canary-scripted-input-traps.md): the title that ENDS THE BOOT accepts a
@@ -26,7 +40,7 @@ until xdotool search --name "Xenia-canary" >/dev/null 2>&1; do
done
win="$(xdotool search --name "Xenia-canary" | tail -1)"
deadline=$(( SECONDS + 420 ))
deadline=$(( SECONDS + ${DEADLINE:-1200} ))
while [ $SECONDS -lt $deadline ]; do
s="$(screen)"; echo "t=${SECONDS}s $s"
[ "$s" = "title" ] && break
@@ -40,8 +54,39 @@ for _ in 1 2 3 4 5 6 7 8; do sleep 3; s="$(screen)"; echo " $s"; [ "$s" = "menu
shot "$OUT/menu.png"
[ "$s" = "menu" ] || { echo "NO MENU (screen=$s)"; exit 2; }
echo "-> three d-pad steps down, then A (OPTIONS is the 4th item)"
for i in 1 2 3; do python3 "$SD/pad.py" dpad down 0.08; sleep 1.2; done
row(){ shot /tmp/odc_row.png; python3 - <<'PY'
from PIL import Image
import sys; sys.path.insert(0,"/work/tools/re-capture")
import ring_row
try: print("%.1f" % ring_row.ring_row(Image.open("/tmp/odc_row.png")))
except Exception: print("nan")
PY
}
down(){ python3 "$SD/pad.py" tap DOWN 0.2; sleep 3; }
echo "-> find the wrap, then take three verified steps to OPTIONS"
prev="$(row)"; echo " row $prev"
wrapped=0
for _ in $(seq 1 12); do
down; cur="$(row)"; echo " row $cur"
if [ "$(python3 -c "print(1 if float('$cur') < float('$prev') - 5 else 0)")" = "1" ]; then
wrapped=1; prev="$cur"; break
fi
prev="$cur"
done
[ "$wrapped" = 1 ] || { echo "NEVER SAW THE WRAP -- not pressing (A)"; exit 3; }
echo " wrapped to item 1"
for step in 1 2 3; do
ok=0
for _ in 1 2 3; do
down; cur="$(row)"; echo " step $step row $cur"
if [ "$(python3 -c "print(1 if float('$cur') > float('$prev') + 5 else 0)")" = "1" ]; then
ok=1; prev="$cur"; break
fi
echo " (press dropped, retrying)"
done
[ "$ok" = 1 ] || { echo "STEP $step NEVER LANDED -- not pressing (A)"; exit 3; }
done
shot "$OUT/menu-on-options.png"
python3 "$SD/pad.py" tap A 0.3
sleep 8
@@ -54,4 +99,5 @@ xdotool mousemove 900 400 click 1; sleep 2
shot "$OUT/options-armed.png"
ls -l "$OUT"/xenia_re_ui_draws_*.log 2>/dev/null || echo "NO CAPTURE LOG"
grep -i "UI-CAP" "$OUT/canary.stdout" | tail -3
echo "OPTIONS CAPTURE DONE (emulator left running)"
echo "OPTIONS CAPTURE DONE"
pkill -x xenia_canary 2>/dev/null; sleep 2; echo "emulator killed"