[client] input: fix focus capture startup

Capture-on-focus could consume the initial focus event before an input
provider became available. The focused state then suppressed any later
attempt to establish capture.

Treat explicit capture as local window state, refresh keyboard ownership
on focus and input-policy changes, and preserve pre-ungrab availability
for key release. Fall back to the window center when guest cursor
geometry is not ready.
This commit is contained in:
Geoffrey McRae
2026-08-21 04:23:42 +10:00
parent 82c59cecf2
commit 1a5bdc14aa
4 changed files with 36 additions and 20 deletions

View File

@@ -271,7 +271,7 @@ void app_handleFocusEvent(bool focused)
g_state.focused = focused; g_state.focused = focused;
g_cursor.motionValid = false; g_cursor.motionValid = false;
const bool inputEnabled = core_inputEnabled(); const bool inputWasEnabled = core_inputEnabled();
// release any imgui buttons/keys if we lost focus // release any imgui buttons/keys if we lost focus
if (!focused && app_isOverlayMode()) if (!focused && app_isOverlayMode())
@@ -285,6 +285,15 @@ void app_handleFocusEvent(bool focused)
core_setGrabQuiet(false); core_setGrabQuiet(false);
core_setCursorInView(false); core_setCursorInView(false);
} }
else
{
if (g_params.captureOnFocus && !g_state.ignoreInput)
core_setGrab(true);
core_updateKeyboardGrab();
}
const bool inputEnabled = focused ?
core_inputEnabled() : inputWasEnabled;
if (!inputEnabled) if (!inputEnabled)
{ {
@@ -304,10 +313,6 @@ void app_handleFocusEvent(bool focused)
if (g_params.minimizeOnFocusLoss) if (g_params.minimizeOnFocusLoss)
g_state.ds->minimize(); g_state.ds->minimize();
} }
else
if (g_params.captureOnFocus)
core_setGrab(true);
g_cursor.realign = true; g_cursor.realign = true;
g_state.ds->realignPointer(); g_state.ds->realignPointer();
} }
@@ -518,7 +523,8 @@ void app_handleKeyReleaseInternal(int sc)
{ {
if (g_state.escapeAction == -1) if (g_state.escapeAction == -1)
{ {
if (!g_state.escapeHelp && lgInput_available() && if (!g_state.escapeHelp &&
(g_cursor.grab || lgInput_available()) &&
!app_isOverlayMode()) !app_isOverlayMode())
core_setGrab(!g_cursor.grab); core_setGrab(!g_cursor.grab);
} }

View File

@@ -137,14 +137,18 @@ bool core_inputEnabled(void)
((g_cursor.grab && g_params.captureInputOnly) || !g_params.captureInputOnly); ((g_cursor.grab && g_params.captureInputOnly) || !g_params.captureInputOnly);
} }
static void updateKeyboardGrab(void) void core_updateKeyboardGrab(void)
{ {
const bool capture = g_cursor.grab && g_params.grabKeyboard; const bool inputEnabled = core_inputEnabled();
/* Explicit capture is local window state and must survive an input provider
* becoming unavailable or changing during startup. */
const bool capture = g_cursor.grab && g_params.grabKeyboard &&
!g_state.ignoreInput;
const bool view = g_cursor.inView && g_params.grabKeyboardOnFocus; const bool view = g_cursor.inView && g_params.grabKeyboardOnFocus;
const bool automatic = !g_cursor.grab && const bool automatic = !g_cursor.grab &&
g_cursor.autoCaptureActive && !g_params.captureInputOnly; g_cursor.autoCaptureActive && !g_params.captureInputOnly;
const bool active = g_state.focused && core_inputEnabled() && const bool active = g_state.focused && !app_isOverlayMode() &&
!app_isOverlayMode() && (capture || view || automatic); (capture || (inputEnabled && (view || automatic)));
if (active) if (active)
g_state.ds->grabKeyboard(); g_state.ds->grabKeyboard();
@@ -162,7 +166,7 @@ static void setAutoCapture(bool active)
MTRACE("auto capture active=%d old=%d", active, MTRACE("auto capture active=%d old=%d", active,
g_cursor.autoCaptureActive); g_cursor.autoCaptureActive);
g_cursor.autoCaptureActive = active; g_cursor.autoCaptureActive = active;
updateKeyboardGrab(); core_updateKeyboardGrab();
} }
static void applyView(bool active, bool force) static void applyView(bool active, bool force)
@@ -175,7 +179,7 @@ static void applyView(bool active, bool force)
if (!force && g_cursor.inView == active) if (!force && g_cursor.inView == active)
{ {
updateKeyboardGrab(); core_updateKeyboardGrab();
return; return;
} }
@@ -204,7 +208,7 @@ static void applyView(bool active, bool force)
g_state.ds->setPointer(LG_POINTER_SQUARE); g_state.ds->setPointer(LG_POINTER_SQUARE);
} }
updateKeyboardGrab(); core_updateKeyboardGrab();
g_cursor.warpState = WARP_STATE_ON; g_cursor.warpState = WARP_STATE_ON;
} }
@@ -323,7 +327,7 @@ void core_setGrabQuiet(bool enable)
g_state.ignoreInput = false; g_state.ignoreInput = false;
g_cursor.grab = true; g_cursor.grab = true;
g_cursor.autoCaptureActive = false; g_cursor.autoCaptureActive = false;
updateKeyboardGrab(); core_updateKeyboardGrab();
core_setCursorInView(true); core_setCursorInView(true);
/* ensure the local mouse is inside the window before we capture, this fixes /* ensure the local mouse is inside the window before we capture, this fixes
@@ -331,7 +335,11 @@ void core_setGrabQuiet(bool enable)
* was focused without the cursor being in window already */ * was focused without the cursor being in window already */
if (warpSupport != LG_DS_WARP_NONE) if (warpSupport != LG_DS_WARP_NONE)
{ {
struct DoublePoint local; struct DoublePoint local =
{
.x = g_state.windowCX,
.y = g_state.windowCY,
};
const bool valid = util_guestCurToLocal(&local); const bool valid = util_guestCurToLocal(&local);
MTRACE("grab align valid=%d", valid); MTRACE("grab align valid=%d", valid);
core_warpPointer(local.x, local.y, true); core_warpPointer(local.x, local.y, true);
@@ -345,7 +353,7 @@ void core_setGrabQuiet(bool enable)
g_cursor.grab = false; g_cursor.grab = false;
g_cursor.autoCaptureActive = g_params.autoCapture && g_cursor.autoCaptureActive = g_params.autoCapture &&
g_cursor.inView && !g_params.captureInputOnly; g_cursor.inView && !g_params.captureInputOnly;
updateKeyboardGrab(); core_updateKeyboardGrab();
if (warpSupport == LG_DS_WARP_NONE) if (warpSupport == LG_DS_WARP_NONE)
core_handleMouseAbsolute(); core_handleMouseAbsolute();

View File

@@ -24,6 +24,7 @@
#include <stdbool.h> #include <stdbool.h>
bool core_inputEnabled(void); bool core_inputEnabled(void);
void core_updateKeyboardGrab(void);
void core_invalidatePointer(bool detectInView); void core_invalidatePointer(bool detectInView);
void core_setCursorInView(bool enable); void core_setCursorInView(bool enable);
void core_handleGrabEvent(bool active); void core_handleGrabEvent(bool active);

View File

@@ -63,6 +63,7 @@ static void bind_input(int sc, void * opaque)
core_setCursorInView(false); core_setCursorInView(false);
else else
g_state.ds->realignPointer(); g_state.ds->realignPointer();
core_updateKeyboardGrab();
app_alert( app_alert(
LG_ALERT_INFO, LG_ALERT_INFO,