mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-25 00:12:44 +00:00
[client] input: synchronize host lock state over LGMP
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
Cache native keyboard lock state across input-provider transitions and reconcile it with HID LED feedback over LGMP. Project raw and corrective lock-key transitions through the reliable input FIFO, defer correction until outstanding transitions settle, and recover from delayed or missing feedback without double toggling.
This commit is contained in:
@@ -655,9 +655,6 @@ void app_handleKeyboardLEDs(bool numLock, bool capsLock, bool scrollLock)
|
||||
if (evdev_isExclusive())
|
||||
return;
|
||||
|
||||
if (!core_inputEnabled())
|
||||
return;
|
||||
|
||||
if (!lgInput_keyboardLEDs(numLock, capsLock, scrollLock))
|
||||
DEBUG_ERROR("app_handleKeyboardLEDs: failed to send message");
|
||||
}
|
||||
|
||||
@@ -132,10 +132,22 @@ static bool moveExit(double ex, double ey)
|
||||
return inside;
|
||||
}
|
||||
|
||||
static bool inputPolicyEnabled(void)
|
||||
{
|
||||
return !g_state.ignoreInput &&
|
||||
((g_cursor.grab && g_params.captureInputOnly) ||
|
||||
!g_params.captureInputOnly);
|
||||
}
|
||||
|
||||
bool core_inputEnabled(void)
|
||||
{
|
||||
return lgInput_available() && !g_state.ignoreInput &&
|
||||
((g_cursor.grab && g_params.captureInputOnly) || !g_params.captureInputOnly);
|
||||
return lgInput_available() && inputPolicyEnabled();
|
||||
}
|
||||
|
||||
void core_updateKeyboardLEDsSync(void)
|
||||
{
|
||||
lgInput_setKeyboardLEDsSync(
|
||||
inputPolicyEnabled() && !evdev_isExclusive());
|
||||
}
|
||||
|
||||
void core_updateKeyboardGrab(void)
|
||||
@@ -154,6 +166,7 @@ void core_updateKeyboardGrab(void)
|
||||
(capture || (inputEnabled && (view || automatic)));
|
||||
|
||||
evdev_setGrab(active, localActive && g_cursor.grab);
|
||||
core_updateKeyboardLEDsSync();
|
||||
if (active)
|
||||
g_state.ds->grabKeyboard();
|
||||
else
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
bool core_inputEnabled(void);
|
||||
void core_updateKeyboardLEDsSync(void);
|
||||
void core_updateKeyboardGrab(void);
|
||||
void core_invalidatePointer(bool detectInView);
|
||||
void core_setCursorInView(bool enable);
|
||||
|
||||
@@ -2096,6 +2096,8 @@ void evdev_dispatch(void * opaque)
|
||||
evdev_barrierMatches(&output.barrier, desiredState))
|
||||
{
|
||||
evdev_dispatchReset(output.barrier.lanes);
|
||||
if (output.barrier.activate & EVDEV_GRAB_KEYBOARD)
|
||||
lgInput_setKeyboardLEDsSync(false);
|
||||
evdev_publishActive(output.barrier.deactivate, false);
|
||||
evdev_publishActive(output.barrier.activate, true);
|
||||
const uint64_t currentState = atomic_load_explicit(
|
||||
@@ -2103,6 +2105,7 @@ void evdev_dispatch(void * opaque)
|
||||
if (output.barrier.activate &&
|
||||
!evdev_barrierMatches(&output.barrier, currentState))
|
||||
evdev_publishActive(output.barrier.activate, false);
|
||||
core_updateKeyboardLEDsSync();
|
||||
}
|
||||
atomic_store_explicit(&state.barrierAck,
|
||||
output.barrier.serial, memory_order_release);
|
||||
|
||||
@@ -35,6 +35,7 @@ struct InputBinding
|
||||
bool keyboardLEDsValid;
|
||||
uint8_t keyboardLEDs;
|
||||
uint32_t epoch;
|
||||
uint32_t generation;
|
||||
};
|
||||
|
||||
static struct
|
||||
@@ -55,6 +56,9 @@ static struct
|
||||
struct InputBinding active;
|
||||
bool useTransport;
|
||||
bool notifiedAvailable;
|
||||
bool keyboardLEDsSyncEnabled;
|
||||
bool desiredKeyboardLEDsValid;
|
||||
uint8_t desiredKeyboardLEDs;
|
||||
|
||||
_Atomic(bool) keys[KEY_MAX];
|
||||
_Atomic(uint32_t) buttons;
|
||||
@@ -191,6 +195,29 @@ static void clearStateNL(void)
|
||||
atomic_store_explicit(&l_input.buttons, 0, memory_order_relaxed);
|
||||
}
|
||||
|
||||
static void resetKeyboardLEDsNL(const struct InputBinding * binding)
|
||||
{
|
||||
if (binding->ops && binding->ops->keyboardLEDsReset)
|
||||
binding->ops->keyboardLEDsReset(binding->opaque);
|
||||
}
|
||||
|
||||
static bool syncKeyboardLEDsNL(void)
|
||||
{
|
||||
if (!l_input.keyboardLEDsSyncEnabled ||
|
||||
!l_input.desiredKeyboardLEDsValid)
|
||||
return true;
|
||||
if (!l_input.active.ops)
|
||||
return false;
|
||||
if (!l_input.active.ops->keyboardLEDs)
|
||||
return true;
|
||||
|
||||
const uint8_t leds = l_input.desiredKeyboardLEDs;
|
||||
return l_input.active.ops->keyboardLEDs(l_input.active.opaque,
|
||||
(leds & LG_KEYBOARD_LED_NUM_LOCK) != 0,
|
||||
(leds & LG_KEYBOARD_LED_CAPS_LOCK) != 0,
|
||||
(leds & LG_KEYBOARD_LED_SCROLL_LOCK) != 0);
|
||||
}
|
||||
|
||||
static bool updateActiveNL(bool dropActive)
|
||||
{
|
||||
const struct InputBinding next =
|
||||
@@ -210,6 +237,7 @@ static bool updateActiveNL(bool dropActive)
|
||||
const bool keyboardLEDsChanged =
|
||||
!keyboardLEDsEqual(&next, &l_input.active);
|
||||
|
||||
resetKeyboardLEDsNL(&l_input.active);
|
||||
if (dropActive)
|
||||
clearStateNL();
|
||||
else
|
||||
@@ -220,6 +248,7 @@ static bool updateActiveNL(bool dropActive)
|
||||
{
|
||||
if (l_input.active.ops->reset)
|
||||
l_input.active.ops->reset(l_input.active.opaque);
|
||||
syncKeyboardLEDsNL();
|
||||
DEBUG_INFO("Using Input: %s", l_input.active.ops->name);
|
||||
}
|
||||
else
|
||||
@@ -230,24 +259,32 @@ static bool updateActiveNL(bool dropActive)
|
||||
static bool updateStatusNL(struct InputBinding * binding,
|
||||
const LG_InputStatus * status)
|
||||
{
|
||||
const struct InputBinding oldActive = l_input.active;
|
||||
const bool wasActive = bindingEqual(&l_input.active, binding);
|
||||
const struct InputBinding oldActive = l_input.active;
|
||||
const bool wasActive =
|
||||
bindingEqual(&l_input.active, binding);
|
||||
const bool generationChanged = wasActive &&
|
||||
binding->generation && status->available &&
|
||||
binding->generation != status->generation;
|
||||
|
||||
if (wasActive && !status->available)
|
||||
{
|
||||
resetKeyboardLEDsNL(&l_input.active);
|
||||
resetActiveNL();
|
||||
l_input.active = (struct InputBinding) { 0 };
|
||||
}
|
||||
|
||||
binding->available = status->available;
|
||||
binding->mouseAbsolute = status->available &&
|
||||
binding->available = status->available;
|
||||
binding->mouseAbsolute = status->available &&
|
||||
binding->ops->mousePosition &&
|
||||
binding->ops->supports(binding->opaque,
|
||||
LG_INPUT_SUPPORT_MOUSE_ABSOLUTE);
|
||||
binding->keyboardLEDsValid = status->available &&
|
||||
status->keyboardLEDsValid;
|
||||
binding->keyboardLEDs = status->keyboardLEDs;
|
||||
binding->generation = status->generation;
|
||||
updateActiveNL(false);
|
||||
if (generationChanged)
|
||||
syncKeyboardLEDsNL();
|
||||
return !keyboardLEDsEqual(&oldActive, &l_input.active);
|
||||
}
|
||||
|
||||
@@ -291,11 +328,14 @@ static void transportStatusChanged(void * opaque,
|
||||
|
||||
void lgInput_init(void)
|
||||
{
|
||||
l_input.fallback = (struct InputBinding) { 0 };
|
||||
l_input.transport = (struct InputBinding) { 0 };
|
||||
l_input.active = (struct InputBinding) { 0 };
|
||||
l_input.useTransport = true;
|
||||
l_input.notifiedAvailable = false;
|
||||
l_input.fallback = (struct InputBinding) { 0 };
|
||||
l_input.transport = (struct InputBinding) { 0 };
|
||||
l_input.active = (struct InputBinding) { 0 };
|
||||
l_input.useTransport = true;
|
||||
l_input.notifiedAvailable = false;
|
||||
l_input.keyboardLEDsSyncEnabled = false;
|
||||
l_input.desiredKeyboardLEDsValid = false;
|
||||
l_input.desiredKeyboardLEDs = 0;
|
||||
|
||||
for (int key = 0; key < KEY_MAX; ++key)
|
||||
atomic_init(&l_input.keys[key], false);
|
||||
@@ -316,6 +356,7 @@ void lgInput_free(void)
|
||||
LG_LOCK(l_input.keyboardLEDsDispatch);
|
||||
LG_LOCK(l_input.availabilityDispatch);
|
||||
LG_LOCK_EXCLUSIVE(l_input.activeLock);
|
||||
resetKeyboardLEDsNL(&l_input.active);
|
||||
resetActiveNL();
|
||||
fallback = l_input.fallback;
|
||||
transport = l_input.transport;
|
||||
@@ -532,15 +573,41 @@ bool lgInput_keyUp(int key)
|
||||
|
||||
bool lgInput_keyboardLEDs(bool numLock, bool capsLock, bool scrollLock)
|
||||
{
|
||||
LG_LOCK_SHARED(l_input.activeLock);
|
||||
const bool result = l_input.active.ops &&
|
||||
(!l_input.active.ops->keyboardLEDs ||
|
||||
l_input.active.ops->keyboardLEDs(l_input.active.opaque,
|
||||
numLock, capsLock, scrollLock));
|
||||
LG_UNLOCK_SHARED(l_input.activeLock);
|
||||
const uint8_t desired =
|
||||
(numLock ? LG_KEYBOARD_LED_NUM_LOCK : 0) |
|
||||
(capsLock ? LG_KEYBOARD_LED_CAPS_LOCK : 0) |
|
||||
(scrollLock ? LG_KEYBOARD_LED_SCROLL_LOCK : 0);
|
||||
|
||||
LG_LOCK_EXCLUSIVE(l_input.activeLock);
|
||||
l_input.desiredKeyboardLEDs = desired;
|
||||
l_input.desiredKeyboardLEDsValid = true;
|
||||
const bool result = syncKeyboardLEDsNL();
|
||||
LG_UNLOCK_EXCLUSIVE(l_input.activeLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
void lgInput_setKeyboardLEDsSync(bool enable)
|
||||
{
|
||||
LG_LOCK_EXCLUSIVE(l_input.activeLock);
|
||||
if (l_input.keyboardLEDsSyncEnabled == enable)
|
||||
{
|
||||
LG_UNLOCK_EXCLUSIVE(l_input.activeLock);
|
||||
return;
|
||||
}
|
||||
|
||||
l_input.keyboardLEDsSyncEnabled = enable;
|
||||
if (enable)
|
||||
syncKeyboardLEDsNL();
|
||||
else
|
||||
{
|
||||
resetKeyboardLEDsNL(&l_input.fallback);
|
||||
if (l_input.transport.ops != l_input.fallback.ops ||
|
||||
l_input.transport.opaque != l_input.fallback.opaque)
|
||||
resetKeyboardLEDsNL(&l_input.transport);
|
||||
}
|
||||
LG_UNLOCK_EXCLUSIVE(l_input.activeLock);
|
||||
}
|
||||
|
||||
void lgInput_releaseKeys(void)
|
||||
{
|
||||
LG_LOCK_EXCLUSIVE(l_input.activeLock);
|
||||
|
||||
Reference in New Issue
Block a user