acdream/docs/research/2026-08-26-retail-keyboard-routing-audit.md
Erik f6fe0f2a4f
All checks were successful
CI / linux-portable (push) Successful in 3m27s
CI / windows-gate (push) Successful in 6m42s
CI / release (push) Successful in 2m12s
fix(client): restore retail interaction parity
Harden keyboard and camera routing, inventory and vendor interactions, chat/emotes, relog portal flow, and paperdoll rendering. Add retail research, connected gate coverage, and release-gate validation.
2026-08-26 20:45:11 +02:00

6.3 KiB
Raw Blame History

Retail keyboard defaults and routing audit — 2026-08-26

Verdict

The code gate for #446 now covers all 306 user-bindable rows in the installed Sept-2013 EoR ActionMap. Each row has a distinct InputAction, appears enabled in Configure Keyboard, persists through retail-compatible named .keymap profiles, and reaches a concrete subsystem consumer. The exact installed-DAT default chord set has zero exceptions. The remaining gate is a connected visual/behavior pass and a fresh-process persistence check.

The approved acdream extension is deliberately retained: mouse-wheel chase zoom may pull back to 40 m. It does not change the retail keyboard defaults or the keypad camera actions.

Oracles

  • docs/research/named-retail/retail-default.keymap.txt and installed client_portal.dat ActionMap DID 0x26000000: the 306 rows, default chords, activation types, input contexts, and ConflictingMaps relationships.
  • Installed MasterInputMaps 0x14000000 and 0x14000002: non-bindable system and mouse commands.
  • ClientUISystem::OnAction @0x00564B90: Escape priority.
  • CInputManager_WIN32::GetNameFromKey_Internal @0x00687800 and ControlNameMapper::LoadSemantics: displayed keyboard/mouse names.
  • ACCmdInterp::InitializeEmoteInputActionHash @0x0058B510: all 87 emote action-to-motion mappings.
  • CPlayerSystem::SelectNext @0x0055F9A0: selection-cycle filtering and opened-corpse behavior.

Exact ActionMap coverage

Retail input map Rows Consumer
Movement 14 Runtime movement owner, including four postures
Camera + alternate camera 22 Held camera input, presets, alternate-scope modifier, instant mouse look
Combat + melee + missile + magic 32 Runtime combat attack owner and spellcasting controller, including spell slots 112
Emotes 87 Exact retail raw-motion table and Runtime ExecuteMotion
Item selection 26 Selection controller/query and canonical inventory interaction state
UI 42 Retained panels, screenshot, help/plugin result, logout, and selection commands
Chat + chat-entry toggle 7 Retained chat entry/reply/command routes
Quickslots 28 Toolbar use/select/create routes, including slots 1018
Character settings 48 Exact CharacterOptionId bit toggle through Runtime
Total 306 306 distinct live identities

The low MasterInputMap entries such as bare Escape and raw mouse event commands are intentionally not Configure Keyboard rows in retail and are not counted among the 306. Unknown rows from a future DAT can still round-trip in the compatibility sibling store, but the installed EoR DAT has no such row and shows no dimmed/store-only keyboard entry.

Behavior completed

  • Defaults are an exact installed-DAT transcription, including bare LeftShift; device, modifier, activation, and scope all match.
  • Primary and alternate camera maps remain distinct rebind targets even where retail reuses an action id. The alternate modifier changes the active camera scope without aliasing saved bindings.
  • Same physical chord may fire each distinct retail action allowed by the ActionMap. In particular, the authored Alt+1..4 chat/UI and quickslot rows multicast instead of one silently replacing the other.
  • Rebind conflicts use the DAT ConflictingMaps table. The shared melee, missile, and magic key cluster remains legal; true conflicts still prompt.
  • Capture accepts keyboard keys, modifier-only bindings, and mouse buttons. Physical modifier self-bits are normalized, so binding LeftShift does not accidentally become Shift+LeftShift. Mouse button names use retail's DIMOFS_BUTTON0..7 semantics table. Unsupported joystick and left/right mouse inputs keep the instruction dialog open and re-arm capture.
  • Setting the chord already present on the same row is a no-op. New chords use retail's dense two-slot insertion rule, and conflicts use priority dialogs with the exact installed-DAT singular/plural and non-bindable text.
  • Apply/OK, Revert, Defaults, Cancel, explicit unbinding, schema migration, and startup persistence are covered. Revert is enabled only while dirty; OK avoids rewriting an unchanged file.
  • Load File and Save As use retail's type-7 menu/type-5 text-entry dialogs, PFile bracket-text grammar, filename normalization, overwrite/read-only handling, Documents\Asheron's Call\*.keymap directory, selected-profile preference, startup load, and graceful-shutdown rewrite. The portable JSON file remains only as an acdream-host-command compatibility mirror.
  • Escape follows retail's priority: finish jump charge, release focused UI, stop movement/repeat attack, cancel target mode, clear selection, then toggle the authored Gameplay Options page. It never exits player mode or exposes the orbit/developer camera. Shift+Escape reaches the normal logout gate.
  • Selection cycling applies retail's containment, cloaking, radar, attackable, fellow, vendor, environment, combat-mode, and opened-corpse rules. Opened-corpse history lives for the session and retires on object deletion.
  • Screenshot, help, and plugin actions are consumed. Missing separately shipped retail help/plugin surfaces report an honest chat/system result rather than doing nothing.

Automated verification

  • App: 6,413/6,413 passed.
  • Core: 4,713/4,713 passed.
  • Runtime: 1,849/1,849 passed.
  • UI.Abstractions: 879/879 passed.
  • Installed-DAT identity/default conformance and the authored Configure Keyboard mount pin all 306 rows.

The .keymap codec parses the committed real retail file and round-trips all 306 user-bindable identities, including low-bit Shift/Ctrl/Alt/Win modifiers, DirectInput controls, fixed Escape/system/edit/pointer maps, and the 48 CharacterOption action names. AP-202 is retired. The connected gate could not be run because no local ACE endpoint was listening on UDP port 9000.

Connected acceptance gate

Use the installed EoR DATs and the normal owner-gate pak. In Configure Keyboard, verify that all rows are enabled and that a key, modifier-only chord, and mouse button can each be rebound. Exercise representative movement, camera, melee/missile/magic, emote, selection, panel, chat, quickslot, and character-option actions. Verify conflict prompt, Cancel, Revert, Defaults, Apply, and OK, then restart the process and confirm the applied bindings remain.