Files
Sylpheed/tools/re-capture/options_draw_capture.sh
sylph-decoder 035375f413 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
2026-08-31 07:06:49 +00:00

104 lines
4.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# 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
# single (A); the one the attract loop returns to accepts nothing. So never tap
# during the boot, and take the first title.
set -u
export HOME=/sylph-home/re SDL_AUDIODRIVER=dummy DISPLAY=:98
SD="$(cd "$(dirname "$0")" && pwd)"
OUT="${1:-/sylph-home/re/optcap}"
mkdir -p "$OUT"; rm -f "$OUT"/xenia_re_ui_draws_*.log
shot(){ screenshot "$1" >/dev/null 2>&1; }
screen(){ shot /tmp/odc.png; python3 "$SD/screen_id.py" /tmp/odc.png | awk '{print $1}'; }
alive(){ ps -o pid=,stat= -C xenia_canary 2>/dev/null | awk '$2 !~ /^Z/ {print $1}'; }
# No capture flags at launch: F10 arms the capture unconditionally now, and
# launching with --log_ui_draws correlated (0 of 7) with the title refusing (A).
( cd "$OUT" && nohup run-canary --mem_watch=false \
--logged_profile_slot_0_xuid=B13EBABEBABEBABE \
>"$OUT/canary.stdout" 2>"$OUT/canary.stderr" & )
sleep 8
until xdotool search --name "Xenia-canary" >/dev/null 2>&1; do
[ -n "$(alive)" ] || { echo "EMULATOR GONE"; exit 4; }; sleep 1
done
win="$(xdotool search --name "Xenia-canary" | tail -1)"
deadline=$(( SECONDS + ${DEADLINE:-1200} ))
while [ $SECONDS -lt $deadline ]; do
s="$(screen)"; echo "t=${SECONDS}s $s"
[ "$s" = "title" ] && break
sleep 1
done
[ "$s" = "title" ] || { echo "NO BOOT TITLE"; exit 1; }
echo "-> A on the boot title"
python3 "$SD/pad.py" tap A 0.3
for _ in 1 2 3 4 5 6 7 8; do sleep 3; s="$(screen)"; echo " $s"; [ "$s" = "menu" ] && break; done
shot "$OUT/menu.png"
[ "$s" = "menu" ] || { echo "NO MENU (screen=$s)"; exit 2; }
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
shot "$OUT/options.png"
echo "screen after A: $(screen)"
xdotool windowactivate --sync "$win"; sleep 1
xdotool key F10; sleep 3
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"
pkill -x xenia_canary 2>/dev/null; sleep 2; echo "emulator killed"