From e2dcc4a39256092747a1906aa57954962f3b7602 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Thu, 3 Sep 2026 16:29:07 -0400 Subject: [PATCH] The keyboard was read through a symbol SDL never published Every key's character came from X11_KeyToUnicode: a function of SDL 1.2's X11 driver that appears in no public header, declared in x86UNIXInputManager.cc as a bare extern and called three times per key to fill AsciiTable with the unshifted, shifted and AltGr character. It linked only because SDL 1.2 was built without symbol visibility control. Distributions no longer ship that SDL. What they call SDL 1.2 is sdl12-compat, a shim over SDL2/3, and the interesting part is that it does not fail to link: it exports an X11_KeyToUnicode of its own. That one is a US-layout toupper() stub. Measured against a hand-built genuine SDL 1.2 on the same machine and the same us layout, shift-1 answered "1" instead of "!", shift-; answered ";" instead of ":", shift-/ answered "/" instead of "?", shift-- answered "-" instead of "_", and the AltGr row was a copy of the unshifted one. So building against a distribution package linked cleanly and then mistyped every shifted punctuation character, which is a worse failure than a missing symbol. The table is now read from the X keymap through public Xlib, which is where SDL was reading it from: SDLKeyToXKeySym names the X keysym for each SDL one, and XLookupString against a synthetic XKeyEvent asks the server what that key types with no modifier, with Shift, and with Mod5 for AltGr. The display comes from the existing DisplayPtrManager, so it also works when SDL has not stored one, and a missing display now says so instead of silently zeroing the table. Checked by running the identical translation code beside genuine SDL 1.2 over all 113 keys InitKeyMaps maps: no differences on a us layout. On a de layout the unshifted and shifted rows are also identical, and the AltGr row now holds what AltGr actually produces (AltGr-q is '@') rather than repeating the unshifted character -- the "goofy (i18n) case" finally being the i18n case. One trap worth recording. The keypad entries name the numlock-OFF keysyms (XK_KP_Delete, XK_KP_Insert and friends) rather than XK_KP_Decimal and XK_KP_0. A keyboard binds both spellings, and XKeysymToKeycode resolves them to different keycodes: XK_KP_Decimal landed on a separate layout-defined separator key (129) instead of the physical numpad period (91). Naming the numlock-off spelling is what SDL 1.2 effectively did, and it was the single mismatch until it was fixed. Fixing the link exposed a second, unrelated wall. InitSDL takes the engine's Display, screen and locking out of SDL_GetWMInfo's x11 union, and sdl12-compat picks the Wayland video driver on a Wayland desktop, where that call answers "No SysWM support available" -- so the engine stopped at "Unable to initialize SDL" before it ever got to a keymap. It now asks for SDL's x11 driver with a non-overriding setenv and runs through Xwayland; an explicit SDL_VIDEODRIVER still wins. Verified on Arch against sdl12-compat 1.2.68 with no vendored SDL in the configure: readelf -d reports no RUNPATH at all, nm -u shows X11_KeyToUnicode is not referenced, the editor boots and loads PlanetX, and typing ! : ? _ " ( into the in-engine console produces exactly those characters where the stub would have produced 1 ; / - ' 9. Also here: EmscriptenInputManager.cpp carried a vestigial extern for the same symbol that nothing called. The linux-x64 CI job loses its ubuntu-22.04 pin, which existed only for this; the 32-bit job keeps its pin, but for the :i386 dev packages, which is the reason that actually still applies. CMakeLists, BUILD-PLATFORM-NOTES and build-linux.sh all claimed the shim lacks the symbol, which measurement says is not what goes wrong. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01CnwJvxtXJ6Vb1BHEVgUm6o --- .github/workflows/PR-builds.yml | 17 +- CHANGELOG.md | 2 + CMakeLists.txt | 6 +- build-linux.sh | 5 +- cmake/BUILD-PLATFORM-NOTES.md | 24 ++- .../EmscriptenInputManager.cpp | 7 +- .../platformX86UNIX/x86UNIXInputManager.cc | 171 ++++++++++++++++-- .../source/platformX86UNIX/x86UNIXWindow.cc | 10 + 8 files changed, 200 insertions(+), 42 deletions(-) diff --git a/.github/workflows/PR-builds.yml b/.github/workflows/PR-builds.yml index bef8435d1..d18dab020 100644 --- a/.github/workflows/PR-builds.yml +++ b/.github/workflows/PR-builds.yml @@ -52,11 +52,10 @@ jobs: # =========================================================================== linux-x64: name: Linux x86_64 - # Pinned to 22.04: the engine's X11 back-end needs GENUINE SDL 1.2 (it links - # the SDL-1.2 X11 driver symbol X11_KeyToUnicode and calls 1.2-only APIs). - # On 24.04, libsdl1.2-dev is the SDL2-based sdl12-compat shim, which does NOT - # export those symbols, so the link fails. - runs-on: ubuntu-22.04 + # Not pinned: libsdl1.2-dev on 24.04 is the SDL2-backed sdl12-compat shim, + # which the back-end is happy with now that the ascii key table is read from + # the X keymap rather than from SDL's private X11_KeyToUnicode. + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: lukka/get-cmake@latest @@ -88,9 +87,11 @@ jobs: linux-x86: name: Linux x86 (32-bit) - # Pinned to 22.04 for genuine SDL 1.2 (see the linux-x64 job). The 32-bit - # build additionally needs NASM: platform/platformCPUInfo.asm (detectX86CPUInfo) - # is compiled only on 32-bit (it is x86-only and is skipped on 64-bit via + # Still pinned to 22.04, but for the :i386 dev packages rather than for SDL: + # newer Debian/Ubuntu drop the 32-bit dev symlinks the configure step needs + # (see the multilib gotchas in cmake/BUILD-PLATFORM-NOTES.md). The 32-bit build + # additionally needs NASM: platform/platformCPUInfo.asm (detectX86CPUInfo) is + # compiled only on 32-bit (it is x86-only and is skipped on 64-bit via # TORQUE_64). runs-on: ubuntu-22.04 steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f98bebc8..68b16916c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,6 +103,8 @@ and makes CMake the only build system. - The engine reported its version as 1.0. `TORQUE_GAME_ENGINE` had never been raised past `1000`, so `getVersionNumber()` answered `1000` where 4.0 is `4000`, and the server-query compatibility check compared every build as 1.0. `getVersionString()` returned `"Open Source"`, which is not a version at all; it now returns `"4.0 Early Access 4"`, which is also what Linux prints at start-up. - On Linux, per-user files were written next to the executable. `getUserDataDirectory()`, `getUserHomeDirectory()` and the temporary directory all answered `"~/"`, which only a shell expands -- so the engine read it as a relative path and resolved it against the working directory, putting the editor's preferences in a folder literally named `~` inside whatever project was running, and scratch files from `getTemporaryFileName()` beside them. They now follow the XDG Base Directory specification, as the equivalents on Windows and macOS have always followed theirs: `$XDG_DATA_HOME` or `~/.local/share` for user data, `$HOME` for the home directory, and `$TMPDIR` or `/tmp` for temporaries. A project's preferences move to `~/.local/share///`; anything under an old `~` folder can be moved there or discarded. - On Linux, a relative path was resolved against the directory the process was launched from rather than the one the game runs in. The Unix back-end carried a "pref dir" redirect, meant to route created files under the user's home on the assumption that the game's own folder is not writable. It was never switched on -- it was gated on a `USE_FILE_REDIRECT` macro that nothing ever defined -- so the pref dir was only ever the working directory, but it was cached at the first file open, which happens before the engine changes directory to the folder holding `main.cs`. Launching `/path/to/Torque2D /path/to/main.cs` from anywhere else therefore wrote `console.log` into the folder you happened to be standing in, and read a relative name from there in preference to the game's own copy. A relative path is now resolved against the working directory as it stands at the call, which is what Windows and macOS have always done. The `-nohomedir` command-line switch, which turned off a redirect that was already off, is gone. +- On Linux, the engine can be built and run against the SDL 1.2 that distributions actually ship. It used to call `X11_KeyToUnicode`, a private symbol of SDL 1.2's X11 driver that was never in a public header, to find out which character each key types; the ascii table is now read from the X keymap through Xlib instead. That symbol is missing or wrong everywhere except a hand-built genuine SDL 1.2 -- the `sdl12-compat` shim now shipped as SDL 1.2 by Ubuntu 24.04+ and Arch does export one, but it is a US-layout `toupper()` stub that answers `1` for shift-`1` and `;` for shift-`;`, so building against a distribution package used to link and then mistype every shifted punctuation character. The table is unchanged on a US layout; on an international layout the AltGr row now holds the characters AltGr actually produces (on a German keyboard AltGr-q is `@`) rather than repeating the unshifted ones. +- On Linux, the engine no longer stops at "Unable to initialize SDL" on a Wayland desktop. The X11 back-end takes its display, screen and locking from `SDL_GetWMInfo`, and the SDL2/3-backed `sdl12-compat` defaults to the Wayland video driver, where that call has nothing to hand back. The back-end now asks for SDL's X11 video driver, so it runs through Xwayland; setting `SDL_VIDEODRIVER` yourself still overrides it. ### Removed diff --git a/CMakeLists.txt b/CMakeLists.txt index 408507c15..a15837aa4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -452,8 +452,10 @@ if(UNIX AND NOT APPLE AND NOT ANDROID AND NOT EMSCRIPTEN) # Linux / X11 desktop build (platformX86UNIX). NOTES for the on-platform # (WSL/Linux) session: # * SDL 1.2 is REQUIRED, not optional: the platform back-end calls 1.2-only - # APIs (SDL_GetVideoSurface, SDL_WM_*, SDL_*GammaRamp, SDL_GL_SwapBuffers) - # and pulls X11_KeyToUnicode out of libSDL. This is NOT SDL2. + # APIs (SDL_GetVideoSurface, SDL_WM_*, SDL_*GammaRamp, SDL_GL_SwapBuffers). + # This is NOT SDL2. The SDL2-backed sdl12-compat shim (Ubuntu 24.04+, Arch) + # is fine: the back-end no longer reaches into libSDL for the private + # X11_KeyToUnicode symbol, it reads the keymap through Xlib. # * `rt` is a no-op on modern glibc but harmless. # * OpenGL/FreeType are resolved via find_package (more robust than the old # hard-coded /usr/include/freetype2 paths). Install dev packages, e.g. on diff --git a/build-linux.sh b/build-linux.sh index 471c1b258..448d6235f 100755 --- a/build-linux.sh +++ b/build-linux.sh @@ -17,8 +17,9 @@ # sudo apt install build-essential cmake \ # libsdl1.2-dev libx11-dev libxft-dev libfreetype6-dev \ # libopenal-dev libgl1-mesa-dev -# Note: GENUINE SDL 1.2 is required (NOT the SDL2-based sdl12-compat shim that -# ships on Ubuntu 24.04+). For a 32-bit build see cmake/BUILD-PLATFORM-NOTES.md. +# Note: that is SDL *1.2*, not SDL2. The SDL2-backed sdl12-compat shim that +# ships on Ubuntu 24.04+ and Arch works too. +# For a 32-bit build see cmake/BUILD-PLATFORM-NOTES.md. # --------------------------------------------------------------------------- set -e diff --git a/cmake/BUILD-PLATFORM-NOTES.md b/cmake/BUILD-PLATFORM-NOTES.md index 11356ee48..5f28d6cb8 100644 --- a/cmake/BUILD-PLATFORM-NOTES.md +++ b/cmake/BUILD-PLATFORM-NOTES.md @@ -370,10 +370,15 @@ codesign — `rm -rf Torque2D_DEBUG.app` when switching platforms. and rebuild whichever bitness you want at the root. 3. Resolved issues (the original scaffold's wrong assumptions): - **SDL 1.2 is REQUIRED, not optional.** The back-end calls 1.2-only APIs - (`SDL_GetVideoSurface`, `SDL_WM_*`, `SDL_*GammaRamp`, `SDL_GL_SwapBuffers`) - and pulls `X11_KeyToUnicode` out of `libSDL`. This is **NOT SDL2** — and NOT - the SDL2-based `sdl12-compat` shim, which lacks `X11_KeyToUnicode` (so CI is - pinned to ubuntu-22.04, which still ships genuine SDL 1.2.15). + (`SDL_GetVideoSurface`, `SDL_WM_*`, `SDL_*GammaRamp`, `SDL_GL_SwapBuffers`). + This is **NOT SDL2**. The SDL2-backed `sdl12-compat` shim (Ubuntu 24.04+, + Arch) *is* supported: the ascii key table used to be built by calling + `X11_KeyToUnicode`, a private symbol of SDL 1.2's X11 driver that was never + in a public header, and it is now read from the X keymap through Xlib. + `sdl12-compat` does export an `X11_KeyToUnicode`, but it is a US-layout + `toupper()` stub — it answers `1` for shift-`1` and `;` for shift-`;` — so + linking against it used to succeed and then mistype every shifted + punctuation character. - **`detectX86CPUInfo`** comes from `platform/platformCPUInfo.asm`, 32-bit-only NASM (does not assemble for elf64). It's referenced only `#ifndef TORQUE_64`, so 64-bit defines `TORQUE_64` (asm unneeded); 32-bit assembles it via NASM. @@ -386,9 +391,8 @@ codesign — `rm -rf Torque2D_DEBUG.app` when switching platforms. up (`DISPLAY=:0`, `WAYLAND_DISPLAY=wayland-0`, `/mnt/wslg/.X11-unix/X0`), `./Torque2D_DEBUG` launches the Project Manager GUI: OpenGL initializes through WSLg's GL stack (`Renderer: D3D12 (...) Mesa`), screen mode sets, editor modules - load, and it exits 0 on close. The `X11_KeyToUnicode()` warning at startup is - expected (the genuine-SDL-1.2 symbol, see above) and harmless. Without WSLg/an X - server the build/link still verifies but the window won't appear. + load, and it exits 0 on close. Without WSLg/an X server the build/link still + verifies but the window won't appear. **32-bit also boots under WSLg**, but falls back to **llvmpipe (software GL)** — `Renderer: llvmpipe (...)` rather than the 64-bit `D3D12 (NVIDIA ...)`, because WSLg's hardware-GL passthrough (the d3d12 Mesa driver) is 64-bit only. It still @@ -748,9 +752,9 @@ keyboard input). Four fixes: (`string/stringTable.cc`) — a latent CROSS-PLATFORM bug; fixes all high-bit/accented input. - **Phantom glyphs from modifier keys.** `EmscriptenInputManager::MapKey` assigned the raw SDL keysym as each key's `ascii`, so modifiers/function/arrow/keypad keys all carried a bogus - non-zero ascii and got inserted as (unrenderable) characters. Desktop x86UNIX avoids this via - `X11_KeyToUnicode()` (returns 0 for non-character keys), but emscripten's SDL1 port has no - working `X11_KeyToUnicode`. Filtered the default assignment: only printable ASCII (0x20-0x7E) + non-zero ascii and got inserted as (unrenderable) characters. Desktop x86UNIX avoids this by + reading the X keymap (which yields nothing for a non-character key), but a browser canvas has + no keymap to read. Filtered the default assignment: only printable ASCII (0x20-0x7E) carries a character ascii; SDL specials (≥0x100), 0x7F-0xFF, and control keys (<0x20) map to 0 and stay handled by keycode (`EmscriptenInputManager.cpp`). - **Event-list re-entrancy OOB.** `ProcessMessages()` cached the size of the shared diff --git a/engine/source/platformEmscripten/EmscriptenInputManager.cpp b/engine/source/platformEmscripten/EmscriptenInputManager.cpp index b15b2c981..b927f7556 100644 --- a/engine/source/platformEmscripten/EmscriptenInputManager.cpp +++ b/engine/source/platformEmscripten/EmscriptenInputManager.cpp @@ -53,9 +53,6 @@ static const U32 JoystickMask = SDL_JOYAXISMOTION | SDL_JOYBUTTONUP;//SDL_JOYEVE static const U32 AllInputEvents = MouseMask | KeyboardMask | JoystickMask; -// defined in SDL -extern "C" Uint16 X11_KeyToUnicode( SDLKey keysym, SDLMod modifiers ); - //============================================================================== // Static helper functions //============================================================================== @@ -68,8 +65,8 @@ static void MapKey(Uint16 SDLkey, U8 tkey) // >= 0x100) and the 0x7F-0xFF range must map to ascii 0; otherwise they're // treated as character input and insert phantom glyphs into text fields (e.g. // pressing Ctrl typed a stray "box" character). The desktop x86UNIX back-end - // gets this for free via X11_KeyToUnicode (which returns 0 for non-character - // keys), but emscripten's SDL1 port has no working X11_KeyToUnicode, hence this + // gets this for free by reading the X keymap (which yields nothing for a + // non-character key), but a browser canvas has no keymap to read, hence this // explicit filter. Control keys (< 0x20: Tab/Enter/Backspace/Esc) also map to 0 // here and are handled by keycode, not by character input. Shifted variants of // the printable keys are still set by the switch below. diff --git a/engine/source/platformX86UNIX/x86UNIXInputManager.cc b/engine/source/platformX86UNIX/x86UNIXInputManager.cc index c7e498e41..f53626e46 100755 --- a/engine/source/platformX86UNIX/x86UNIXInputManager.cc +++ b/engine/source/platformX86UNIX/x86UNIXInputManager.cc @@ -28,6 +28,10 @@ #include "platformX86UNIX/x86UNIXInputManager.h" #include "math/mMathFn.h" +#include +#include +#include + #include // ascii table @@ -54,30 +58,157 @@ static const U32 JoystickMask = SDL_JOYEVENTMASK; static const U32 AllInputEvents = MouseMask | KeyboardMask | JoystickMask; -// defined in SDL -extern "C" Uint16 X11_KeyToUnicode( SDLKey keysym, SDLMod modifiers ); +// The display InitKeyMaps() builds the ascii table against. Only valid for the +// duration of that call; MapKey() reads it rather than taking it as an argument +// so that the (long) list of MapKey() calls below stays readable. +static Display* sgKeymapDisplay = NULL; //============================================================================== // Static helper functions //============================================================================== +// Translate an SDL 1.2 keysym to the X keysym naming the same key. +// +// SDL numbered its keysyms after the X ones it was built on, so the printable +// range needs no table: SDLK_SPACE..SDLK_z and the Latin-1 SDLK_WORLD_* range +// already are the X keysym of the same character. Everything else -- the +// control keys (whose SDL value is the ASCII code, not the keysym), the keypad, +// navigation, function and modifier keys -- has to be named explicitly. +static KeySym SDLKeyToXKeySym(SDLKey key) +{ + switch (key) + { + // Control keys. SDL numbered these after their ASCII code. + case SDLK_BACKSPACE: return XK_BackSpace; + case SDLK_TAB: return XK_Tab; + case SDLK_CLEAR: return XK_Clear; + case SDLK_RETURN: return XK_Return; + case SDLK_PAUSE: return XK_Pause; + case SDLK_ESCAPE: return XK_Escape; + case SDLK_DELETE: return XK_Delete; + + // Keypad. These are deliberately the numlock-OFF spellings: a keyboard + // binds both spellings of each numpad key and XKeysymToKeycode can resolve + // them to *different* keycodes -- XK_KP_Decimal commonly lands on a + // separate layout-defined separator key rather than the physical numpad + // period. The numlock-off spelling is the one SDL 1.2 resolved to. + case SDLK_KP0: return XK_KP_Insert; + case SDLK_KP1: return XK_KP_End; + case SDLK_KP2: return XK_KP_Down; + case SDLK_KP3: return XK_KP_Page_Down; + case SDLK_KP4: return XK_KP_Left; + case SDLK_KP5: return XK_KP_Begin; + case SDLK_KP6: return XK_KP_Right; + case SDLK_KP7: return XK_KP_Home; + case SDLK_KP8: return XK_KP_Up; + case SDLK_KP9: return XK_KP_Page_Up; + case SDLK_KP_PERIOD: return XK_KP_Delete; + case SDLK_KP_DIVIDE: return XK_KP_Divide; + case SDLK_KP_MULTIPLY: return XK_KP_Multiply; + case SDLK_KP_MINUS: return XK_KP_Subtract; + case SDLK_KP_PLUS: return XK_KP_Add; + case SDLK_KP_ENTER: return XK_KP_Enter; + case SDLK_KP_EQUALS: return XK_KP_Equal; + + // Navigation. + case SDLK_UP: return XK_Up; + case SDLK_DOWN: return XK_Down; + case SDLK_RIGHT: return XK_Right; + case SDLK_LEFT: return XK_Left; + case SDLK_INSERT: return XK_Insert; + case SDLK_HOME: return XK_Home; + case SDLK_END: return XK_End; + case SDLK_PAGEUP: return XK_Page_Up; + case SDLK_PAGEDOWN: return XK_Page_Down; + + // Function keys. + case SDLK_F1: return XK_F1; + case SDLK_F2: return XK_F2; + case SDLK_F3: return XK_F3; + case SDLK_F4: return XK_F4; + case SDLK_F5: return XK_F5; + case SDLK_F6: return XK_F6; + case SDLK_F7: return XK_F7; + case SDLK_F8: return XK_F8; + case SDLK_F9: return XK_F9; + case SDLK_F10: return XK_F10; + case SDLK_F11: return XK_F11; + case SDLK_F12: return XK_F12; + case SDLK_F13: return XK_F13; + case SDLK_F14: return XK_F14; + case SDLK_F15: return XK_F15; + + // Locks and modifiers. + case SDLK_NUMLOCK: return XK_Num_Lock; + case SDLK_CAPSLOCK: return XK_Caps_Lock; + case SDLK_SCROLLOCK: return XK_Scroll_Lock; + case SDLK_RSHIFT: return XK_Shift_R; + case SDLK_LSHIFT: return XK_Shift_L; + case SDLK_RCTRL: return XK_Control_R; + case SDLK_LCTRL: return XK_Control_L; + case SDLK_RALT: return XK_Alt_R; + case SDLK_LALT: return XK_Alt_L; + case SDLK_RMETA: return XK_Meta_R; + case SDLK_LMETA: return XK_Meta_L; + case SDLK_LSUPER: return XK_Super_L; + case SDLK_RSUPER: return XK_Super_R; + case SDLK_MODE: return XK_Mode_switch; + case SDLK_COMPOSE: return XK_Multi_key; + + // Misc. + case SDLK_HELP: return XK_Help; + case SDLK_PRINT: return XK_Print; + case SDLK_SYSREQ: return XK_Sys_Req; + case SDLK_BREAK: return XK_Break; + case SDLK_MENU: return XK_Menu; + + default: + if ((key >= 0x20 && key < 0x7F) || (key >= 0xA0 && key <= 0xFF)) + return static_cast(key); + return NoSymbol; + } +} + +// The character the given key produces with the given modifiers held, according +// to the keymap the X server is currently using. Asking X rather than assuming +// a layout is the whole point: on a German keyboard shift-7 is '/' and AltGr-q +// is '@', and a hardcoded US table would get both wrong. +static U16 KeySymToAscii(KeySym sym, unsigned int state) +{ + XKeyEvent xkey; + char keybuf[32]; + + if (sgKeymapDisplay == NULL || sym == NoSymbol) + return 0; + + dMemset(&xkey, 0, sizeof(xkey)); + xkey.type = KeyPress; + xkey.display = sgKeymapDisplay; + xkey.keycode = XKeysymToKeycode(sgKeymapDisplay, sym); + xkey.state = state; + + // The key isn't on this keymap at all. + if (xkey.keycode == 0) + return 0; + + if (XLookupString(&xkey, keybuf, sizeof(keybuf), NULL, NULL) > 0) + return static_cast(static_cast(keybuf[0])); + + return 0; +} + +//------------------------------------------------------------------------------ static void MapKey(Uint16 SDLkey, U8 tkey) { SDLtoTKeyMap[SDLkey] = tkey; - Uint16 key = 0; - SDLKey skey = (SDLKey)SDLkey; - SDLMod mod = KMOD_NONE; + KeySym sym = SDLKeyToXKeySym(static_cast(SDLkey)); + // lower case - key = X11_KeyToUnicode( skey, mod ); - AsciiTable[tkey].lower.ascii = key; + AsciiTable[tkey].lower.ascii = KeySymToAscii(sym, 0); // upper case - mod = KMOD_LSHIFT; - key = X11_KeyToUnicode( skey, mod ); - AsciiTable[tkey].upper.ascii = key; - // goofy (i18n) case - mod = KMOD_MODE; - key = X11_KeyToUnicode( skey, mod ); - AsciiTable[tkey].goofy.ascii = key; + AsciiTable[tkey].upper.ascii = KeySymToAscii(sym, ShiftMask); + // goofy (i18n) case -- AltGr, which X keymaps reach through Mod5. + AsciiTable[tkey].goofy.ascii = KeySymToAscii(sym, Mod5Mask); } //------------------------------------------------------------------------------ @@ -85,7 +216,16 @@ void InitKeyMaps() { dMemset( &AsciiTable, 0, sizeof( AsciiTable ) ); dMemset(SDLtoTKeyMap, KEY_NULL, SDLtoTKeyMapSize); - + + // The ascii half of the table is read off the X keymap, so it is only as + // good as the layout in effect right now. If there is no display to ask, + // every key still maps to its Torque keycode; only the ascii stays zero. + DisplayPtrManager xdisplay; + sgKeymapDisplay = xdisplay.getDisplayPointer(); + if (sgKeymapDisplay == NULL) + Con::warnf("Input: no X display to read the keymap from; " + "keys will report no ascii character."); + // set up the X to Torque key map // stuff MapKey(SDLK_BACKSPACE, KEY_BACKSPACE); @@ -167,6 +307,7 @@ void InitKeyMaps() MapKey(SDLK_MENU, KEY_WIN_APPS); MapKey(SDLK_MODE, KEY_OEM_102); + sgKeymapDisplay = NULL; keyMapsInitialized = true; }; diff --git a/engine/source/platformX86UNIX/x86UNIXWindow.cc b/engine/source/platformX86UNIX/x86UNIXWindow.cc index 6440ee4e8..9b2d733d1 100755 --- a/engine/source/platformX86UNIX/x86UNIXWindow.cc +++ b/engine/source/platformX86UNIX/x86UNIXWindow.cc @@ -152,6 +152,16 @@ static void InitWindow(const Point2I &initialSize, const char *name) //------------------------------------------------------------------------------ static bool InitSDL() { + // Ask for the X11 video driver unless the user named one. This back-end is + // an X11 back-end: it takes its Display, screen and display lock functions + // straight out of SDL_GetWMInfo's x11 union below, and everything from the + // keymap to the clipboard is built on them. Genuine SDL 1.2 only ever had + // X11 to offer, but the SDL2/3-backed sdl12-compat shim that distributions + // now ship as SDL 1.2 defaults to Wayland on a Wayland desktop, where + // SDL_GetWMInfo answers "No SysWM support available" and the engine used to + // stop at "Unable to initialize SDL". Xwayland serves us fine. + setenv("SDL_VIDEODRIVER", "x11", 0); + if (SDL_Init(SDL_INIT_VIDEO) != 0) return false;