From 035375f4135c21aa585a9320434a08437e8a918f Mon Sep 17 00:00:00 2001 From: sylph-decoder Date: Mon, 31 Aug 2026 07:06:49 +0000 Subject: [PATCH] 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) Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v --- tools/re-capture/options_draw_capture.sh | 58 +++++++++++++++++++++--- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/tools/re-capture/options_draw_capture.sh b/tools/re-capture/options_draw_capture.sh index 97bff30f..5de24757 100755 --- a/tools/re-capture/options_draw_capture.sh +++ b/tools/re-capture/options_draw_capture.sh @@ -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"