Zum Hauptinhalt springen
Inoffizieller Guild Wars Reforged App — ein Fan-Projekt, nicht mit ArenaNet oder NCSoft verbunden

UR-08: every printable key is labelled one position too high

The Controls panel names the next character in ASCII order. A control bound to K reads L. Input is correct; only the label is wrong.

The Controls panel and the in-game menus name the wrong key for every binding that uses a printable character. The label shows the next character in ASCII order: a control bound to K reads L, a control bound to 1 reads 2.

Input itself is correct — the key that works is the right key and matches the Windows client, and the bindings on the account are fine. The defect is in the code that renders a key id as text. Keys that have a name — Up Arrow, Escape, Tab, the function keys — are labelled correctly.

Fix: low effort once the render function is found — with symbols that should take minutes. Small blast radius: display text only, input handling doesn't change.

Build used for the measurements below: 38797, 3229678d3fd7d2f0e309530086a614d97f02e7eeb3ca12650ababfd2eb360817.

What the player sees

Observed with default bindings, in Options → Control:

ActionKey that worksLabel shown
Panel: Open HeroHI
Panel: Open InventoryIJ
Panel: Open Skills and AttributesKL
Panel: Open Quest LogLM
Panel: Open World MapMN
Action: Use Skill 112
Movement: Move ForwardWX

A player reads the menu, presses the key it names, and gets the adjacent action. "Hero (I)" opens the Inventory, because I is the Inventory key, and the Inventory label reads J.

The measurement that isolates the defect

One row of the Controls panel, with two keys bound to the same action:

ActionBound keyRendered
Movement: Move ForwardUp ArrowUp Arrow
Movement: Move ForwardWX

Same action, same binding record, same panel, same draw — and one of the two labels is correct. That rules out the binding data, the stored configuration, the keyboard layout, and any web-vs-Windows binding difference, because none of those can differ between two keys inside one record.

The defect sits after the binding read, in the render step, and only for keys that render as a character.

Scope

  • Letters and digits are both affected, by the same one position.
  • Named keys are not affected. Those names come from the localized text, so a number cannot produce them.
  • The defect is independent of the keyboard layout. We reproduced it on US QWERTY and on German QWERTZ, identically.
  • The defect is independent of the host. Our host forwards key events unchanged, and it does not participate in the label draw.

The key descriptor table

The table sits at 0x1456c0 in the data segment. The records are 20 bytes:

c
{ int32 id; char name[16] }

id  0..43   Alt Control Shift CapsLock Escape NumLock ... ArrowUp F1..F12
id 48..57   0..9   plus a parallel table of shifted names  ) ! @ # $ % ^ & * (
id 65..90   A..Z   plus a parallel table of lowercase names  a..z

The names are DOM KeyboardEvent.key values — ArrowUp, PageDown, HangulMode, with Unidentified as the fallback. This is the table that turns a browser key event into an internal id.

The contents and the order of this table are correct. The defect is not in this data.

What we could not determine

We did not locate the function that renders the label. Two readings of the table stay consistent with every observation above, and they need different corrections, so we state both.

Reading 1 — the ids are ASCII+1 and the label casts the id
Frame the records from 0x1456c4, with the name first and the id at +16. The printable ids are then one above ASCII: A = 66, H = 73, 0 = 49. A cast to a character gives the observed labels exactly.
Reading 2 — the ids are ASCII and the render indexes one record too far
Frame the records from 0x1456c0, with the id first. The ids are then exactly ASCII. A read of name from the following record gives the observed labels exactly.

Both readings explain every case in this report, including why Up Arrow stays correct. With symbols and source this question is immediate; from a stripped module it isn't.

We did establish that function #9718 converts a key id to a character with no offset: 75 gives K, 76 gives L, 48 gives 0. Many functions in the module do that identical conversion as a generic one-character string helper, so the conversion is not where the extra one enters.

Expected behaviour

The Controls panel and the in-game menus name the key that actually triggers the action — for printable keys, the way it already works for named keys.

Acceptance criteria

  • "Panel: Open Hero" shows H, and H opens the Hero panel.
  • "Action: Use Skill 1" shows 1, and 1 uses skill 1.
  • "Movement: Move Forward" shows Up Arrow and W.
  • The result is the same on US QWERTY and on German QWERTZ.
  • A rebind to any printable key shows that key.
  • Named keys keep their current correct labels.

How to reproduce

Open the panel

Log in and open Options → Control.

Read a row

Select Movement: Move Forward. It shows Up Arrow and X.

Press the labelled key

Press X in the game. The character does not move.

Press the real key

Press W. The character moves forward.

Check a digit

Select Action: Use Skill 1. It shows 2. Skill 1 fires on 1.

No configuration change is needed. The defect is present with default bindings.

Method, and its limit

For the file-system reports we called the functions and measured the results. We couldn't do that here: the label render depends on an initialised UI and text subsystem, so there's no way to call it from a cold instance.

What we observe directly: the rendered labels, the keys that work, and the contents of the descriptor table. What we infer: which of the two readings is the real one.

Our workaround today

None. A correction would need a second permanent transform, re-derived for every client build — too high a price for a wrong letter on a label. We report the defect and wait.

GWonMac

Spiele Guild Wars auf deinem Mac. GWonMac führt ArenaNets offiziellen Client nativ auf Apple Silicon aus — kostenlos, Open Source, signiert und notarisiert.

© GWonMac. Alle Rechte vorbehalten.