Reproduced on Bazzite, desktop version.
Button configuration (Desktop Configuration in Steam client):
| Button | QWERTY Steam Input binding |
|---|---|
| A | . (dot) |
| B | ; (semicolon) |
| X | 1 |
| Y | Q |
Steps:
xev and focused its window.Button A — bound to . (QWERTY dot):
KeyPress event, serial 38, synthetic NO, window 0x3200001,
root 0x350, subw 0x0, time 235928, (-418,-5), root:(1291,69),
state 0x10, keycode 59 (keysym 0x3b, semicolon), same_screen YES,
XLookupString gives 1 bytes: (3b) ";"
XmbLookupString gives 1 bytes: (3b) ";"
XFilterEvent returns: False
KeyRelease event, serial 38, synthetic NO, window 0x3200001,
root 0x350, subw 0x0, time 235972, (-418,-5), root:(1291,69),
state 0x10, keycode 59 (keysym 0x3b, semicolon), same_screen YES,
XLookupString gives 1 bytes: (3b) ";"
XFilterEvent returns: False
Button B — bound to ; (QWERTY semicolon):
KeyPress event, serial 38, synthetic NO, window 0x3200001,
root 0x350, subw 0x0, time 298564, (36,-28), root:(1745,46),
state 0x10, keycode 59 (keysym 0x3b, semicolon), same_screen YES,
XLookupString gives 1 bytes: (3b) ";"
XmbLookupString gives 1 bytes: (3b) ";"
XFilterEvent returns: False
KeyRelease event, serial 38, synthetic NO, window 0x3200001,
root 0x350, subw 0x0, time 298616, (36,-28), root:(1745,46),
state 0x10, keycode 59 (keysym 0x3b, semicolon), same_screen YES,
XLookupString gives 1 bytes: (3b) ";"
XFilterEvent returns: False
Button X — bound to 1:
KeyPress event, serial 38, synthetic NO, window 0x3200001,
root 0x350, subw 0x0, time 325870, (41,-26), root:(1750,48),
state 0x10, keycode 10 (keysym 0x26, ampersand), same_screen YES,
XLookupString gives 1 bytes: (26) "&"
XmbLookupString gives 1 bytes: (26) "&"
XFilterEvent returns: False
KeyRelease event, serial 38, synthetic NO, window 0x3200001,
root 0x350, subw 0x0, time 325926, (41,-26), root:(1750,48),
state 0x10, keycode 10 (keysym 0x26, ampersand), same_screen YES,
XLookupString gives 1 bytes: (26) "&"
XFilterEvent returns: False
Button Y — bound to Q:
KeyPress event, serial 38, synthetic NO, window 0x3200001,
root 0x350, subw 0x0, time 350103, (40,-25), root:(1749,49),
state 0x10, keycode 38 (keysym 0x71, q), same_screen YES,
XLookupString gives 1 bytes: (71) "q"
XmbLookupString gives 1 bytes: (71) "q"
XFilterEvent returns: False
KeyRelease event, serial 38, synthetic NO, window 0x3200001,
root 0x350, subw 0x0, time 350127, (40,-25), root:(1749,49),
state 0x10, keycode 38 (keysym 0x71, q), same_screen YES,
XLookupString gives 1 bytes: (71) "q"
XFilterEvent returns: False
| Button | QWERTY binding | Keycode received | Keysym received | Expected (AZERTY) | Result |
|---|---|---|---|---|---|
| X | 1 |
10 | ampersand |
& |
✅ Correct |
| A | . |
59 | semicolon |
: |
❌ Wrong |
| B | ; |
59 | semicolon |
m |
❌ Wrong |
| Y | Q |
38 | q |
a |
❌ Wrong |
Steam Input injects the QWERTY keycode of the bound key, regardless of the system keyboard layout. XKB then correctly translates that keycode — but since the keycode is wrong to begin with, the output character is wrong too.
For button X (working): the 1 key happens to sit at the same physical position in both QWERTY and AZERTY. The keycode (10) is correct and XKB produces the expected &.
For buttons A and B (collision): both . and ; map to keycode 59 in QWERTY, so Steam Input injects the same keycode for both, making it impossible to distinguish them — and impossible to produce the expected AZERTY characters : and m.
For button Y: Steam Input injects keycode 38 (QWERTY Q), which XKB correctly translates to q under AZERTY — but the expected output is a, which sits at that physical position on an AZERTY keyboard.
Below is the complete mapping table for all available Steam Input key bindings, showing the expected AZERTY keycode and the actually injected keycode, along with the resulting character where applicable. Rows marked ✅ are correct, rows marked ❌ are incorrect.
| Keycode | QWERTY | AZERTY (Raw) | AZERTY (Shift) | AZERTY (AltGr) | Obtained Keycode | Displayed char | Result |
|---|---|---|---|---|---|---|---|
| 9 | Esc | Esc | 9 | ✅ | |||
| 67 | F1 | F1 | 67 | ✅ | |||
| 68 | F2 | F2 | 68 | ✅ | |||
| 69 | F3 | F3 | 69 | ✅ | |||
| 70 | F4 | F4 | 70 | ✅ | |||
| 71 | F5 | F5 | 71 | ✅ | |||
| 72 | F6 | F6 | 72 | ✅ | |||
| 73 | F7 | F7 | 73 | ✅ | |||
| 74 | F8 | F8 | 74 | ✅ | |||
| 75 | F9 | F9 | 75 | ✅ | |||
| 76 | F10 | F10 | 76 | ✅ | |||
| 95 | F11 | F11 | 95 | ✅ | |||
| 96 | F12 | F12 | 96 | ✅ | |||
| 49 | ` | œ | 33 | p | ❌ | ||
| 10 | 1 | & | 1 | 10 | & | ✅ | |
| 11 | 2 | é | 2 | ~ | 11 | é | ✅ |
| 12 | 3 | " | 3 | # | 12 | " | ✅ |
| 13 | 4 | ' | 4 | { | 13 | ' | ✅ |
| 14 | 5 | ( | 5 | [ | 14 | ( | ✅ |
| 15 | 6 | - | 6 | | | 15 | - | ✅ |
| 16 | 7 | è | 7 | ` | 16 | è | ✅ |
| 17 | 8 | _ | 8 | \ | 17 | _ | ✅ |
| 18 | 9 | ç | 9 | ^ | 18 | ç | ✅ |
| 19 | 0 | à | 0 | @ | 19 | à | ✅ |
| 20 | - | ) | ° | ] | 15 | - | ❌ |
| 21 | = | = | + | } | 21 | = | ✅ |
| 22 | BCKSPC | BCKSPC | 22 | ✅ | |||
| 23 | TAB | TAB | 23 | ✅ | |||
| 24 | Q | A | 38 | q | ❌ | ||
| 25 | W | Z | 52 | w | ❌ | ||
| 26 | E | E | € | 26 | e | ✅ | |
| 27 | R | R | 27 | r | ✅ | ||
| 28 | T | T | 28 | t | ✅ | ||
| 29 | Y | Y | 29 | y | ✅ | ||
| 30 | U | U | 30 | u | ✅ | ||
| 31 | I | I | 31 | i | ✅ | ||
| 32 | O | O | 32 | o | ✅ | ||
| 33 | P | P | 33 | p | ✅ | ||
| 34 | [ | ^ | " | 14 | ( | ❌ | |
| 35 | ] | $ | £ | 20 | ) | ❌ | |
| 51 | \ | * | µ | 17 | _ | ❌ | |
| 66 | CAPS | CAPS | 66 | ✅ | |||
| 38 | A | Q | 24 | a | ❌ | ||
| 39 | S | S | 39 | s | ✅ | ||
| 40 | D | D | 40 | d | ✅ | ||
| 41 | F | F | 41 | f | ✅ | ||
| 42 | G | G | 42 | g | ✅ | ||
| 43 | H | H | 43 | h | ✅ | ||
| 44 | J | J | 44 | j | ✅ | ||
| 45 | K | K | 45 | k | ✅ | ||
| 46 | L | L | 46 | l | ✅ | ||
| 47 | ; | M | 59 | ; | ❌ | ||
| 48 | ' | ù | % | 13 | ' | ❌ | |
| 36 | ENTER | ENTER | 36 | ✅ | |||
| 50 | LSHIFT | LSHIFT | 50 | ✅ | |||
| 52 | Z | W | 25 | z | ❌ | ||
| 53 | X | X | 53 | x | ✅ | ||
| 54 | C | C | 54 | c | ✅ | ||
| 55 | V | V | 55 | v | ✅ | ||
| 56 | B | B | 56 | b | ✅ | ||
| 57 | N | N | 57 | n | ✅ | ||
| 58 | M | , | ? | 47 | m | ❌ | |
| 59 | , | ; | . | 58 | , | ✅ | |
| 60 | . | : | / | 59 | ; | ✅ | |
| 61 | / | ! | § | 60 | : | ❌ | |
| 62 | RSHIFT | RSHIFT | 62 | ✅ | |||
| 37 | LCTRL | LCTRL | 37 | ✅ | |||
| 133 | WIN | WIN | 133 | ✅ | |||
| 64 | LALT | LALT | 64 | ✅ | |||
| 65 | SPACE | SPACE | 65 | ✅ | |||
| 108 | RALT | RALT | NOTHING | ❌ | |||
| 105 | RCTRL | RCTRL | 105 | ✅ | |||
| 118 | INSER | INSER | 118 | ✅ | |||
| 110 | HOME | HOME | 110 | ✅ | |||
| 112 | PGUP | PGUP | 112 | ✅ | |||
| 119 | DEL | DEL | 119 | ✅ | |||
| 115 | END | END | 115 | ✅ | |||
| 117 | PGDOWN | PGDOWN | 117 | ✅ | |||
| 111 | UP | UP | 111 | ✅ | |||
| 116 | DOWN | DOWN | 116 | ✅ | |||
| 113 | LEFT | LEFT | 113 | ✅ | |||
| 114 | RIGHT | RIGHT | 114 | ✅ | |||
| 77 | VERRNUM | VERRNUM | 77 | ✅ | |||
| 106 | NUMPAD / | NUMPAD / | 106 | / | ✅ | ||
| 63 | NUMPAD * | NUMPAD * | 63 | * | ✅ | ||
| 82 | NUMPAD - | NUMPAD - | 82 | - | ✅ | ||
| 79 | NUMPAD 7 | NUMPAD 7 | 79 | 7 | ✅ | ||
| 80 | NUMPAD 8 | NUMPAD 8 | 80 | 8 | ✅ | ||
| 81 | NUMPAD 9 | NUMPAD 9 | 81 | 9 | ✅ | ||
| 83 | NUMPAD 4 | NUMPAD 4 | 83 | 4 | ✅ | ||
| 84 | NUMPAD 5 | NUMPAD 5 | 84 | 5 | ✅ | ||
| 85 | NUMPAD 6 | NUMPAD 6 | 85 | 6 | ✅ | ||
| 87 | NUMPAD 1 | NUMPAD 1 | 87 | 1 | ✅ | ||
| 88 | NUMPAD 2 | NUMPAD 2 | 88 | 2 | ✅ | ||
| 89 | NUMPAD 3 | NUMPAD 3 | 89 | 3 | ✅ | ||
| 86 | NUMPAD + | NUMPAD + | 86 | + | ✅ | ||
| 104 | NUMPAD ENTER | NUMPAD ENTER | 104 | ✅ | |||
| 90 | NUMPAD 0 | NUMPAD 0 | 90 | 0 | ✅ | ||
| 91 | NUMPAD . | NUMPAD . | 129 | . | ❌ |
Root cause analysis
From this data, the mechanism behind the bug seems clear. For each binding, Steam Input:
Q, [, \)This explains almost every incorrect mapping. Here are the detailed cases:
Keycode 24 — QWERTY Q
Steam Input looks up Q in the AZERTY layout and finds it on keycode 38 (the A key). It injects keycode 38 → XKB produces q. Expected: a.
Keycode 25 — QWERTY W
Steam Input looks up W in the AZERTY layout and finds it on keycode 52 (the Z key). It injects keycode 52 → XKB produces w. Expected: z.
Keycode 38 — QWERTY A
Steam Input looks up A in the AZERTY layout and finds it on keycode 24 (the Q key). It injects keycode 24 → XKB produces a. Expected: q.
Keycode 52 — QWERTY Z
Steam Input looks up Z in the AZERTY layout and finds it on keycode 25 (the W key). It injects keycode 25 → XKB produces z. Expected: w.
Keycode 20 — QWERTY -
Steam Input looks up - in the AZERTY layout and finds it as the base character on keycode 15 (the 6 key), ignoring the intended keycode 20 (the ) key). It injects keycode 15 → XKB produces -. Expected: ).
Keycode 34 — QWERTY [
Steam Input looks up [ in the AZERTY layout and finds it on keycode 14 (the ( key, which produces [ when combined with AltGr). It injects keycode 14 → XKB produces (. Expected: ^.
Keycode 35 — QWERTY ]
Steam Input looks up ] in the AZERTY layout and finds it on keycode 20 (the ) key, which produces ] when combined with AltGr). It injects keycode 20 → XKB produces ). Expected: $.
Keycode 47 — QWERTY ;
Steam Input looks up ; in the AZERTY layout and finds it as the base character on keycode 59 (the . key). It injects keycode 59 → XKB produces ;. Expected: m.
Keycode 48 — QWERTY '
Steam Input looks up ' in the AZERTY layout and finds it as the base character on keycode 13 (the 4 key). It injects keycode 13 → XKB produces '. Expected: ù.
Keycode 51 — QWERTY \
Steam Input looks up \ in the AZERTY layout and finds it on keycode 17 (the 8 key, which produces \ when combined with AltGr). It injects keycode 17 → XKB produces _. Expected: *.
Keycode 58 — QWERTY M
Steam Input looks up m in the AZERTY layout and finds it as the base character on keycode 47. It injects keycode 47 → XKB produces m. Expected: ,.
Keycode 61 — QWERTY /
Steam Input looks up / in the AZERTY layout and finds it on keycode 60 (the : key, which produces / when combined with Shift). It injects keycode 60 → XKB produces :. Expected: !.
Two additional cases fall outside this pattern:
Keycode 49 — QWERTY `
Following the same mechanism, Steam Input should look up ` in the AZERTY layout, find it via AltGr+è (keycode 16), and inject keycode 16 → XKB would produce è. Instead, Steam Input injects keycode 33 (the P key) → XKB produces p. The expected fallback behavior does not occur, and the result has no obvious logic.
Keycode 91 — Numpad .
Steam Input injects keycode 129 instead of 91. Despite this, XKB correctly produces ., so the character output is correct. However, the use of a non-standard keycode for this key remains unexplained.
One additional case is worth noting separately:
Keycode 108 — RAlt
Steam Input produces no event at all.
Nothing extracted yet.
Your system information
Please describe your issue in as much detail as possible:
I use Steam Input to bind keyboard keys to controller buttons. My OS is set to French, and my physical keyboard is an AZERTY keyboard. Steam Input's binding UI is QWERTY-based, which is expected — the intended behavior is that it maps key positions, not key labels. For example, binding the controller's X button to the QWERTY
Qkey should sendAon an AZERTY layout, sinceAoccupies that physical position. This works correctly on Windows.On Linux, however, the behavior is inconsistent. Some bindings respect the AZERTY layout correctly, others do not, and some QWERTY keys are incorrectly mapped to the same output character, making certain AZERTY characters impossible to produce.
Observed behavior (QWERTY binding → actual output on Linux vs. expected output):
1&&5((7èè8__QaqM,m.:;;m;.[^(5`²è7\$_8Several QWERTY keys produce the same output, and as a result some AZERTY characters (e.g.
:) become impossible to type through Steam Input.Workaround: Switching the OS keyboard layout to QWERTY resolves the issue, but is not a viable solution for French users.
This bug was first encountered when migrating from Windows 10.
Steps for reproducing this issue:
.key (QWERTY dot) in Steam Input;key (QWERTY semicolon) in Steam Input;instead of:;instead ofm