This repository has been archived on 2026-09-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Syplheed-Reborn/docs/re/canary-scripted-input-traps.md
Sylpheed RE agent de038c54c0 docs/re: why a scripted run cannot get past the title — three traps and a blocker
Each of these presents as "the pad is dead", and each has a different cause.

1. **F10 opens the emulator's menu bar.** It is the RE capture hotkey AND the
   toolkit's menu key. With that menu open — or any Xenia UI window, the
   Profiles Menu included — `IsUIActive()` is true, so XamInputGetKeystrokeEx
   returns SUCCESS with a ZEROED keystroke before the pad driver is asked. The
   guest polls, gets nothing, and does nothing, with no error anywhere. Escape
   does not close it; a click on the game surface does. This cost most of an
   iteration.

2. **The file-pad was never the problem.** It delivers (vk=5800 down/up per tap)
   and A skips movies in the same runs.

3. **(A) at the title needs a signed-in profile.** Without one the guest calls
   XamShowSigninUI and Xenia's dialog appears — which is also the proof the
   guest reads the button. That dialog cannot be completed here: the gamertag is
   an ImGui text field and synthetic X key events never reach it. Hence Canary's
   new --create_profile_if_none.

And the blocker, stated as measured rather than as a theory: with the profile
signed in, (A) still does not advance the title across four boots. The
reproducible failure is next door — with the default --mem_watch=true the guest
crashes in the boot content path (read of 0x10000000C at 0x82307128, thread 9,
after a guest C++ throw), and with --mem_watch=false it does not. That is a
second, far cheaper reproduction of the Ready-Room crash the canary handoff
blames on the mem_watch probe: 40 s from a cold boot instead of after a mission.

One observation kept because it did not reproduce: a single (A) once crashed the
guest at a DIFFERENT PC (0x824578A0, thread 6). Two attempts to reproduce it
gave neither a crash nor a transition.

Next step named: those two PCs in xenia-rs/sylpheed.db, and the content exports
around the press.
2026-08-18 20:16:27 +00:00

6.9 KiB

Getting past the title screen in the container — three traps and one blocker

Status: CONFIRMED for the three traps (each reproduced, and two of them fixed in the toolkit). 🔴 blocked on reaching the main menu: the guest reads Ⓐ at the title, and the step behind Ⓐ either crashes it or stalls it.

Written down because each of these presents as "the pad is dead" or "the game ignores input", and each has a completely different cause.

1. F10 opens the emulator's menu bar, and that swallows every guest keystroke

F10 is the RE hotkey (ship capture, and now log_ui_draws). It is also the toolkit key that opens the application menu bar, and it does both. With that menu open, XamState::IsUIActive() is true, so XamInputGetKeystrokeEx returns X_ERROR_SUCCESS with a zeroed keystroke before the driver is ever asked (xam_input.cc). The guest polls, gets an empty event, and does nothing — forever, and with no error anywhere.

This cost most of an iteration. Symptom: a run presses F10 to arm a capture, then every later Ⓐ does nothing; the title sits there while the pad log happily prints [file-pad] keystroke vk=5800 down. Screenshot captures/title-with-emulator-menu-open.png shows the giveaway — Open… / Open Recent / Install Content… / Exit over the title art. It is easy to miss because the menu is at the far left of the window and the game is still animating behind it.

Fix: after any F10, click once on the game surface to dismiss the menu. Escape does not close it. ui_draw_capture.sh now does this.

2. The pad is fine — the driver was never the problem

Worth stating because the file-pad's own history (--hid=file, GetKeystroke implemented specifically so "PRESS Ⓐ BUTTON" would work) makes it the natural suspect. It delivers: the log shows vk=5800 down/up per tap, and Ⓐ during a movie skips the movie, every time. When the title ignores Ⓐ, the pad is not why.

3. Ⓐ at the title needs a signed-in profile — and this container cannot type one in

With no profile, Ⓐ is handled: the guest calls XamShowSigninUI and Xenia pops its Sign In dialog (captures/title-signin-dialog.png), ProfileManager: Found 0 Profiles. That dialog is the proof the guest reads the button.

The dialog cannot be completed from here: "Create Profile" opens an ImGui text field for a gamertag, and synthetic X key events do not reach it. Tried, all with the window focused (xdotool getwindowfocus = the game window): xdotool type --window, xdotool type via XTEST, single xdotool key presses, clicking the field first. The field stays empty; Create with an empty gamertag is refused. Mouse clicks do work (they opened the dialog and the sub-panel), so it is text entry specifically.

Xenia's own Profile ▸ Show Profile Menu panel does have a working Create Profile button, and mouse clicks reach it — but the gamertag it then asks for is the same ImGui field, so the UI route dead-ends in the same place.

Fix, landed in Canary (auto/re-ui-draw-order): a --create_profile_if_none=<gamertag> cvar that calls ProfileManager::CreateProfile(tag, autologin, default_xuid) at startup when no profile exists. default_xuid is fixed at B13EBABEBABEBABE, so a script can then pass --logged_profile_slot_0_xuid=B13EBABEBABEBABE and be deterministic. Verified: ProfileManager: RE bootstrap profile 'SylphRE' -> created, then on the next boot Found 1 Profiles / Loaded SylphRE (GUID: B13EBABEBABEBABE) to slot 0, and the Profiles Menu panel shows the user (captures/xenia-profile-panel-signed-in.png). The profile persists on disk, so later runs need only --logged_profile_slot_0_xuid=B13EBABEBABEBABE.

The blocker: what happens after

With the profile created and signed in — Xenia's own Profile ▸ Show Profile Menu confirms it, User: SylphRE / XUID: B13EBABEBABEBABE / Assigned to slot: 1 (the panel counts from 1; the log says slot 0) — Ⓐ at the title still does not advance the screen. Measured across four boots, including one that was allowed to play the whole intro untouched, with holds of 10 s and bursts of five taps.

What is not the explanation, each checked:

  • the emulator menu bar being open (trap 1) — the grabs are clean;
  • the pad (trap 2) — Ⓐ skips movies in the same runs;
  • the profile being absent (trap 3) — it is present, signed in, and the Sign In dialog no longer appears;
  • an ImGui window being open — but note this generalises trap 1: any Xenia UI window makes IsUIActive() true, the Profiles Menu included, so a panel left open silently disables the guest's input for as long as it is up.

One observation that did not reproduce, recorded rather than dropped. In the run where the Profiles Menu had just been closed, a single Ⓐ crashed the guest — PC 0x824578A0, guest thread 6, distinct from the boot-path crash below. Two later attempts to reproduce it (open the panel, close it, press Ⓐ) produced neither a crash nor a transition. So it is one data point that Ⓐ can reach code the title does not otherwise run, and nothing more.

The reproducible crash is the boot-time content path. With the default --mem_watch=true, in two independent runs, the guest dies with an access violation reading 0x00000001_0000000C at PC 0x82307128 on guest thread 9, right after HostPathDevice::ResolvePath(\aab216c3\5\c10eae6) and a RtlRaiseException(E06D7363) (a C++ throw). Xenia pauses itself and stacks up crash dialogs — 991 in one run. With --mem_watch=false that crash does not happen at all.

That pairing — crash with the memory-probe thread on, none with it off, both in a save/content path — matches the suspect ranked #1 in xenia-canary/HANDOFF-crash-oracle-2026-07-16.md, whose crash was also a guest C++ exception in a cache/save path. This is a second, far cheaper reproduction of it: at the title screen, ~40 s from a cold boot, instead of in the Ready Room after a mission.

Next step, for whoever picks this up. Two threads to pull, in this order:

  1. 0x82307128 and 0x824578A0 in xenia-rs/sylpheed.db (the container has it) — what function is the title's Ⓐ path in, and what is at +0xC of the structure it dereferences;
  2. the content exports this title imports — XamContentCreateEnumerator, XamContentGetDeviceState, XamUserReadProfileSettings — logged around the press, to see whether the guest is handed a bad enumerator or a device state it does not accept. \aab216c3\5\… is the content directory in question.

What this blocks: every dynamic experiment past the title — a second UI screen's paint order, the main menu, mission captures. Everything up to and including the title screen is unaffected, which is why the paint-order result above could still be measured.