diff --git a/changelog.txt b/changelog.txt index 41730f3..d1d8b1b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -188,6 +188,8 @@ chg: the client requires SDL 2 - the following things are handled by it: add: m_relative <0|1> (default: 1) enables SDL's relative mouse mode you might want to set it to 0 if you have a messed up input driver +add: in_focusDelay <0..100> (default: 5) is the time in ms keypresses are ignored after the window gets the focus + add: minimize command to minimize the client's window add: automatic dedicated server process restarts for crashes and timed reboots (sv_minRebootDelayMins) diff --git a/code/linux/sdl_core.cpp b/code/linux/sdl_core.cpp index abb9085..591e573 100644 --- a/code/linux/sdl_core.cpp +++ b/code/linux/sdl_core.cpp @@ -1,20 +1,31 @@ #include "linux_local.h" #include +#include #include "sdl_local.h" #include -static qbool sdl_inputActive = qfalse; +// About in_focusDelay: +// Suppose you have the game focused in windowed mode with the console down, +// open the command window (alt+F2), then press return or escape. +// On my machine, SDL will first send the X11 FocusIn event and *after that* +// the keypress event for escape or return. For oj, it's the reverse... +// In my scenario, clearing key states after reception of the FocusIn event +// won't prevent the application from receiving the undesired keypresses. +static cvar_t* in_noGrab; +static cvar_t* in_focusDelay; +static cvar_t* m_relative; -static cvar_t* in_noGrab; -static cvar_t* m_relative; - -static qbool sdl_forceUnmute = qfalse; // overrides s_autoMute +static qbool sdl_inputActive = qfalse; +static qbool sdl_forceUnmute = qfalse; // overrides s_autoMute +static int sdl_focusTime = INT_MIN; // timestamp of last X11 FocusIn event +static qbool sdl_focused = qtrue; // does the X11 window have the focus? static const cvarTableItem_t in_cvars[] = { { &in_noGrab, "in_noGrab", "0", 0, CVART_BOOL, NULL, NULL, "disables input grabbing" }, + { &in_focusDelay, "in_focusDelay", "5", CVAR_ARCHIVE, CVART_INTEGER, "0", "100", "milli-seconds keypresses are off after window focus" }, { &m_relative, "m_relative", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "enables SDL's relative mouse mode" } }; @@ -296,6 +307,33 @@ static void sdl_Window( const SDL_WindowEvent* event ) } +static void sdl_X11( const XEvent* event ) +{ + switch (event->type) { + case FocusIn: + // see in_focusDelay explanation at the top + sdl_focusTime = Sys_Milliseconds(); + sdl_focused = qtrue; + break; + + case FocusOut: + // set modifier keys as released to prevent + // accidental combos such alt+enter right after + // getting focus + // e.g. alt gets "stuck", pressing only enter + // does a video restart as if pressing alt+enter + Lin_QueEvent(0, SE_KEY, K_ALT, qfalse, 0, NULL); + Lin_QueEvent(0, SE_KEY, K_CTRL, qfalse, 0, NULL); + Lin_QueEvent(0, SE_KEY, K_SHIFT, qfalse, 0, NULL); + sdl_focused = qfalse; + break; + + default: + break; + } +} + + static void sdl_Event( const SDL_Event* event ) { switch (event->type) { @@ -304,37 +342,52 @@ static void sdl_Event( const SDL_Event* event ) break; case SDL_KEYDOWN: - sdl_Key(&event->key, qtrue); + if (sdl_focused && Sys_Milliseconds() - sdl_focusTime >= in_focusDelay->integer) + sdl_Key(&event->key, qtrue); break; case SDL_KEYUP: + // always forward releases sdl_Key(&event->key, qfalse); break; case SDL_TEXTINPUT: - sdl_Text(&event->text); + if (sdl_focused) + sdl_Text(&event->text); break; case SDL_MOUSEMOTION: - sdl_MouseMotion(&event->motion); + if (sdl_focused) + sdl_MouseMotion(&event->motion); break; case SDL_MOUSEBUTTONDOWN: - sdl_MouseButton(&event->button, qtrue); + if (sdl_focused) + sdl_MouseButton(&event->button, qtrue); break; case SDL_MOUSEBUTTONUP: + // always forward releases sdl_MouseButton(&event->button, qfalse); break; case SDL_MOUSEWHEEL: - sdl_MouseWheel(&event->wheel); + if (sdl_focused) + sdl_MouseWheel(&event->wheel); break; case SDL_WINDOWEVENT: sdl_Window(&event->window); break; + case SDL_SYSWMEVENT: + { + const SDL_SysWMmsg* msg = event->syswm.msg; + if (msg->subsystem == SDL_SYSWM_X11) + sdl_X11(&msg->msg.x11.event); + } + break; + default: break; } @@ -361,7 +414,8 @@ qbool sdl_Init() SDL_SetHintWithPriority(SDL_HINT_NO_SIGNAL_HANDLERS, "1", SDL_HINT_OVERRIDE); #endif SDL_LogSetAllPriority(SDL_LOG_PRIORITY_CRITICAL); - SDL_StartTextInput(); + SDL_StartTextInput(); // enables SDL_TEXTINPUT events + SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); return qtrue; }