Root cause, with evidence — this is SDL3's Steam Deck screen-keyboard integration
I hit the same thing and traced it end to end on 2.1.12 (build 87038, linux64). It also explains the sibling reports where the UI becomes completely unclickable —
134815 and
134941 are the same bug seen from the other side, and 134941 was closed as "update SteamOS" but still reproduces on a fully up-to-date Deck (SteamOS rolling, kernel 6.16.12-valve24.4, Mesa 25.3).
What did you do?
Launched Factorio from Steam on a Steam Deck (Game Mode, gamescope, X11 video driver), with a physical keyboard and mouse attached. Clicked into any text field — train interrupt name, train group name, a logistic request amount, or the blueprint string import box.
What happened?
The Steam on-screen keyboard opens even though a physical keyboard is connected. While it is open, no mouse click reaches the game at all: buttons, list entries and even the window's close button are dead. Typing still works and Tab still moves between fields, so the game is clearly alive — only pointer input is gone. Unfocusing the text field restores clicking.
What did you expect to happen instead?
With a physical keyboard connected, the on-screen keyboard should not open at all, and the mouse should keep working normally while a text field is focused.
Does it happen always, once, or sometimes?
Always. Every text field, every session, both handheld and docked. Reproduced on 2.1.11 and 2.1.12.
Root cause
Factorio statically links SDL3. Inside SDL_StartTextInputWithProperties, SDL resolves the screen-keyboard hint like this (disassembly of the shipped binary at 0x3a7fc25; the binary is not stripped and carries .debug_info):
Code: Select all
lea "SDL_ENABLE_SCREEN_KEYBOARD" ; call SDL_GetHint
test rax,rax ; jne <use it>
lea "SteamDeck" ; call SDL_GetHint
test rax,rax ; je <fall back to !SDL_HasKeyboard()>
matching upstream:
Code: Select all
const char *hint = SDL_GetHint(SDL_HINT_ENABLE_SCREEN_KEYBOARD);
if (!hint) {
hint = SDL_GetHint("SteamDeck");
}
if (((!hint || SDL_strcasecmp(hint, "auto") == 0) && !SDL_HasKeyboard()) ||
SDL_GetStringBoolean(hint, false)) {
/* show the screen keyboard */
}
Steam exports SteamDeck=1 into every game's environment. "1" is neither NULL nor "auto", so it satisfies the second disjunct through SDL_GetStringBoolean —
and the !SDL_HasKeyboard() check is skipped entirely. That is exactly why the keyboard appears despite a physical keyboard: SDL never asks.
X11_ShowScreenKeyboard then calls SDL_OpenURL with
Code: Select all
steam://open/keyboard?XPosition=%i&YPosition=%i&Width=%i&Height=%i&Mode=%d
and X11_HideScreenKeyboard calls
steam://close/keyboard.
This is directly visible in ~/.local/share/Steam/logs/console_log.txt (attached). The SDL-issued URLs are distinguishable from Steam's own by the absence of an AppID= parameter:
Code: Select all
[20:30:25] Game process added : AppID 2335477982 ... /factorio/bin/x64/factorio
[20:31:49] ExecuteSteamURL: "steam://open/keyboard?XPosition=530&YPosition=651&Width=51&Height=15&Mode=0"
[20:31:59] ExecuteSteamURL: "steam://close/keyboard"
[20:32:17] ExecuteSteamURL: "steam://open/keyboard?XPosition=530&YPosition=651&Width=51&Height=15&Mode=0"
Width=51&Height=15 is the geometry of the focused text field. Every pair lines up with a field gaining and losing focus.
The unclickable-UI half follows from this: while Steam's OSK is up, it holds pointer focus in gamescope, and Steam forwards key events to the game but not pointer events. That is precisely the observed "typing and Tab work, clicks do not" signature.
Note: Steam also exports SDL_ENABLE_STEAM_SCREEN_KEYBOARD=1, an SDL2-era hint name. That string does not exist anywhere in the binary — SDL3 does not read it, so it cannot be used as a knob.
Workaround for players
Steam -> Factorio -> Properties -> Launch Options:
Code: Select all
SDL_ENABLE_SCREEN_KEYBOARD=0 %command%
Verified: the
steam://open/keyboard calls stop and clicking works normally. Trade-off is that handheld text entry then needs STEAM+X manually. =auto is the softer variant, but under gamescope a virtual keyboard device is usually present, so in practice it may behave the same as 0.
Suggested fix
The hint is read
inside SDL_StartTextInput*, not cached at init, so it can be set per focus event from the player's current input method:
Code: Select all
const bool wantsOSK = (player.getInputMethod() == PlayerInputMethod::GameController)
|| !SDL_HasKeyboard();
SDL_SetHint(SDL_HINT_ENABLE_SCREEN_KEYBOARD, wantsOSK ? "1" : "0");
SDL_StartTextInputWithProperties(window, props);
Handling SDL_EVENT_KEYBOARD_ADDED / SDL_EVENT_KEYBOARD_REMOVED would keep it correct across docking and undocking mid-session. Upstream, treating SteamDeck=1 as "auto" rather than as a boolean true would be the more general fix — worth filing at libsdl-org/SDL either way.
Minor logging request
The "Environment:" line in factorio-current.log does not include SteamDeck, SteamGamepadUI or SDL_ENABLE_SCREEN_KEYBOARD, and nothing logs when text input starts or when the screen keyboard is requested. Adding those would make this class of report diagnosable from the game log alone — right now the decisive evidence only exists in Steam's log.
Attachments
Three Factorio logs from sessions where it reproduced (2.1.11 and 2.1.12, before the workaround was applied) and the Steam console_log excerpt showing the OSK calls appearing and then stopping once the launch option is applied.