input-pad-read-path.md says of the word the C_PAD_DECODER reads: "There is no shift and no remap on the way in -- the bit positions are XINPUT's own." That is wrong. sub_8220D500 rebuilds the word out of XINPUT_GAMEPAD before anything else sees it, into the game's own numbering. bits 0-3 A B X Y bits 4-7 left stick UP DOWN LEFT RIGHT (+/-20000 of 32767) bits 8-11 right stick UP DOWN LEFT RIGHT bits 12-15 D-pad UP DOWN LEFT RIGHT bits 16-17 START, BACK bits 18-19 LB, RB bits 20-21 LT, RT -- digital, threshold >220 of 255 bits 22-23 L3, R3 Extracted mechanically from the image, no row typed by hand. The control is the shape of the result: the 24 assignments land on bits 0..23, each used exactly once, none repeated. A misdecode does not produce a bijection over a contiguous range, and coincidence does not put the stick and D-pad directions in the same order in two aligned nibbles. So every mask in that page's tables names the wrong button. The 0xE000 x18 site, read there as "B | X | Y", is "D-pad DOWN | LEFT | RIGHT" -- eighteen sites testing a menu cursor, which is what 18 sites should be. And its headline negative is REFUTED: "LB and RB are not menu inputs" is false. They are bound at config fields this+0x70 and this+0x84, LT/RT at +0x74/+0x80. The negative was searched for 0x0100/0x0200 -- LB and RB in XINPUT's numbering -- in a word where they live at 0x40000/0x80000. Right function, right buttons, wrong bit positions, so it could only come back empty. A negative is only as good as the numbering it was searched in. Also decodes the ring record: +12 HELD, +16 PRESSED, +20 RELEASED, +28/+32 raw trigger bytes. Edge and level are one struct four bytes apart, which displaces that page's guess that press-vs-hold was split between GetState and the XamInputGetKeystrokeEx queue. The superset claim in that page survives and is untouched: sub_82457038 really does compare every XINPUT_GAMEPAD field, and it really is XINPUT-layout. This page depends on it. Not decoded: which output bit means which ACTION, and per-screen sets. 5 of 18 output-bit sites did not resolve to a pad guard, so the output map is a lower bound -- in particular "START is not tested" is NOT claimed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
33 lines
1.5 KiB
Plaintext
33 lines
1.5 KiB
Plaintext
# C_PAD_RINGBUF output record -- the tail of sub_8220D500, read from
|
|
# /image/sylpheed.pe. r3 = the ringbuf; r9 = the XINPUT_GAMEPAD source.
|
|
# This is where a menu gets edge-vs-level, and it is one struct, not two paths.
|
|
|
|
8220D7C0 7D0A582E
|
|
8220D7C4 9103000C +12 <- cur : HELD (level)
|
|
8220D7C8 7D0A582E
|
|
8220D7CC 80E3000C
|
|
8220D7D0 7D083278 r8 = cur XOR prev : CHANGED
|
|
8220D7D4 91030010 +16 <- changed : (overwritten below)
|
|
8220D7D8 5508003E
|
|
8220D7DC 7CCA582E
|
|
8220D7E0 7D063078 r6 = changed ANDC cur : RELEASED this frame
|
|
8220D7E4 90C30014 +20 <- released : FALLING EDGE
|
|
8220D7E8 7D6A582E
|
|
8220D7EC 90E30018 +24 <- cur : HELD (second copy)
|
|
8220D7F0 7D0B5838 r11 = changed AND cur : PRESSED this frame
|
|
8220D7F4 91630010 +16 <- pressed : RISING EDGE (final value)
|
|
8220D7F8 8969002A
|
|
8220D7FC 9163001C +28 <- bLeftTrigger : RAW ANALOG byte
|
|
8220D800 8969002B
|
|
8220D804 91630020 +32 <- bRightTrigger : RAW ANALOG byte
|
|
8220D808 A169002C
|
|
8220D80C 7D6B0734
|
|
|
|
# So the ring record is:
|
|
# +12 buttons HELD (level) -- a menu that repeats on hold reads this
|
|
# +16 buttons PRESSED (rising) -- a menu that fires once per press reads this
|
|
# +20 buttons RELEASED (falling)
|
|
# +24 buttons HELD (copy)
|
|
# +28 bLeftTrigger raw 0..255, analog value preserved alongside the bit
|
|
# +32 bRightTrigger raw 0..255
|