mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-10 09:11:31 +00:00
[client] X11: test grabbed input routing
Some checks are pending
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Waiting to run
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Waiting to run
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Waiting to run
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Waiting to run
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Waiting to run
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Waiting to run
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Waiting to run
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Waiting to run
build / module (push) Waiting to run
build / host-linux (push) Waiting to run
build / host-windows-cross (push) Waiting to run
build / host-windows-native (push) Waiting to run
build / idd (push) Waiting to run
build / obs (clang) (push) Waiting to run
build / obs (gcc) (push) Waiting to run
build / docs (push) Waiting to run
Some checks are pending
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Waiting to run
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Waiting to run
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Waiting to run
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Waiting to run
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Waiting to run
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Waiting to run
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Waiting to run
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Waiting to run
build / module (push) Waiting to run
build / host-linux (push) Waiting to run
build / host-windows-cross (push) Waiting to run
build / host-windows-native (push) Waiting to run
build / idd (push) Waiting to run
build / obs (clang) (push) Waiting to run
build / obs (gcc) (push) Waiting to run
build / docs (push) Waiting to run
Keep raw and cooked event selection inside the tested X11 policy. Exercise grab transitions and held-key normalization directly.
This commit is contained in:
@@ -38,10 +38,36 @@ void x11InputInit(X11Input * input, const LG_DSInputSink * sink,
|
|||||||
void * opaque)
|
void * opaque)
|
||||||
{
|
{
|
||||||
memset(input, 0, sizeof(*input));
|
memset(input, 0, sizeof(*input));
|
||||||
|
atomic_init(&input->pointerGrabbed, false);
|
||||||
|
atomic_init(&input->keyboardGrabbed, false);
|
||||||
input->sink = sink;
|
input->sink = sink;
|
||||||
input->opaque = opaque;
|
input->opaque = opaque;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void x11InputSetPointerGrabbed(X11Input * input, bool grabbed)
|
||||||
|
{
|
||||||
|
atomic_store_explicit(&input->pointerGrabbed, grabbed,
|
||||||
|
memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool x11InputIsPointerGrabbed(const X11Input * input)
|
||||||
|
{
|
||||||
|
return atomic_load_explicit(&input->pointerGrabbed,
|
||||||
|
memory_order_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
void x11InputSetKeyboardGrabbed(X11Input * input, bool grabbed)
|
||||||
|
{
|
||||||
|
atomic_store_explicit(&input->keyboardGrabbed, grabbed,
|
||||||
|
memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool x11InputIsKeyboardGrabbed(const X11Input * input)
|
||||||
|
{
|
||||||
|
return atomic_load_explicit(&input->keyboardGrabbed,
|
||||||
|
memory_order_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
bool x11InputFocus(X11Input * input, bool focused,
|
bool x11InputFocus(X11Input * input, bool focused,
|
||||||
const uint32_t * keys, size_t count)
|
const uint32_t * keys, size_t count)
|
||||||
{
|
{
|
||||||
@@ -90,7 +116,7 @@ void x11InputPointerMotion(X11Input * input, double x, double y)
|
|||||||
void x11InputPointerButton(X11Input * input, unsigned int detail,
|
void x11InputPointerButton(X11Input * input, unsigned int detail,
|
||||||
bool pressed, bool raw)
|
bool pressed, bool raw)
|
||||||
{
|
{
|
||||||
if (!raw && !input->entered)
|
if (!input->entered || raw != x11InputIsPointerGrabbed(input))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const unsigned int button = mapButton(detail);
|
const unsigned int button = mapButton(detail);
|
||||||
@@ -123,24 +149,25 @@ void x11InputPointerButton(X11Input * input, unsigned int detail,
|
|||||||
void x11InputRelativeMotion(X11Input * input,
|
void x11InputRelativeMotion(X11Input * input,
|
||||||
double x, double y, double rawX, double rawY)
|
double x, double y, double rawX, double rawY)
|
||||||
{
|
{
|
||||||
|
if (!input->entered || !x11InputIsPointerGrabbed(input))
|
||||||
|
return;
|
||||||
|
|
||||||
input->sink->relative(input->opaque, x, y, rawX, rawY);
|
input->sink->relative(input->opaque, x, y, rawX, rawY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void x11InputKeyboardKey(X11Input * input, unsigned int keycode,
|
bool x11InputKeyboardKey(X11Input * input, unsigned int keycode,
|
||||||
int minKeycode, bool pressed, bool raw, bool inputActive,
|
int minKeycode, bool pressed, bool raw)
|
||||||
const char * text)
|
|
||||||
{
|
{
|
||||||
if (raw)
|
if (!input->focused || raw != x11InputIsKeyboardGrabbed(input))
|
||||||
{
|
return false;
|
||||||
if (!inputActive)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (!input->focused)
|
|
||||||
return;
|
|
||||||
|
|
||||||
input->sink->key(input->opaque, (int)keycode - minKeycode, pressed);
|
input->sink->key(input->opaque, (int)keycode - minKeycode, pressed);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!raw && pressed && text)
|
void x11InputKeyboardText(X11Input * input, const char * text)
|
||||||
|
{
|
||||||
|
if (text && *text)
|
||||||
input->sink->text(input->opaque, text);
|
input->sink->text(input->opaque, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,3 +178,29 @@ void x11InputKeyboardState(X11Input * input,
|
|||||||
input->sink->modifiers(input->opaque, ctrl, shift, alt, super);
|
input->sink->modifiers(input->opaque, ctrl, shift, alt, super);
|
||||||
input->sink->leds(input->opaque, numLock, capsLock, scrollLock);
|
input->sink->leds(input->opaque, numLock, capsLock, scrollLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t x11InputHeldKeys(
|
||||||
|
const char keymap[X11_INPUT_KEYMAP_SIZE],
|
||||||
|
int minKeycode, int maxKeycode,
|
||||||
|
uint32_t * keys, size_t capacity)
|
||||||
|
{
|
||||||
|
if (minKeycode < 0 || maxKeycode < minKeycode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size_t count = 0;
|
||||||
|
for (int keycode = minKeycode;
|
||||||
|
keycode <= maxKeycode && keycode < X11_INPUT_KEYMAP_SIZE * 8;
|
||||||
|
++keycode)
|
||||||
|
{
|
||||||
|
const unsigned char keyByte = (unsigned char)keymap[keycode / 8];
|
||||||
|
if (!(keyByte & (1U << (keycode % 8))))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (count == capacity)
|
||||||
|
break;
|
||||||
|
|
||||||
|
keys[count++] = keycode - minKeycode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdatomic.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "../input.h"
|
#include "../input.h"
|
||||||
@@ -32,14 +33,23 @@ typedef struct X11Input
|
|||||||
const LG_DSInputSink * sink;
|
const LG_DSInputSink * sink;
|
||||||
void * opaque;
|
void * opaque;
|
||||||
uint32_t buttons;
|
uint32_t buttons;
|
||||||
|
_Atomic(bool) pointerGrabbed;
|
||||||
|
_Atomic(bool) keyboardGrabbed;
|
||||||
bool entered;
|
bool entered;
|
||||||
bool focused;
|
bool focused;
|
||||||
}
|
}
|
||||||
X11Input;
|
X11Input;
|
||||||
|
|
||||||
|
#define X11_INPUT_KEYMAP_SIZE 32
|
||||||
|
|
||||||
void x11InputInit(X11Input * input, const LG_DSInputSink * sink,
|
void x11InputInit(X11Input * input, const LG_DSInputSink * sink,
|
||||||
void * opaque);
|
void * opaque);
|
||||||
|
|
||||||
|
void x11InputSetPointerGrabbed(X11Input * input, bool grabbed);
|
||||||
|
bool x11InputIsPointerGrabbed(const X11Input * input);
|
||||||
|
void x11InputSetKeyboardGrabbed(X11Input * input, bool grabbed);
|
||||||
|
bool x11InputIsKeyboardGrabbed(const X11Input * input);
|
||||||
|
|
||||||
bool x11InputFocus(X11Input * input, bool focused,
|
bool x11InputFocus(X11Input * input, bool focused,
|
||||||
const uint32_t * keys, size_t count);
|
const uint32_t * keys, size_t count);
|
||||||
bool x11InputPointerEnter(X11Input * input, bool mainWindow,
|
bool x11InputPointerEnter(X11Input * input, bool mainWindow,
|
||||||
@@ -51,11 +61,15 @@ void x11InputPointerButton(X11Input * input, unsigned int button,
|
|||||||
bool pressed, bool raw);
|
bool pressed, bool raw);
|
||||||
void x11InputRelativeMotion(X11Input * input,
|
void x11InputRelativeMotion(X11Input * input,
|
||||||
double x, double y, double rawX, double rawY);
|
double x, double y, double rawX, double rawY);
|
||||||
void x11InputKeyboardKey(X11Input * input, unsigned int keycode,
|
bool x11InputKeyboardKey(X11Input * input, unsigned int keycode,
|
||||||
int minKeycode, bool pressed, bool raw, bool inputActive,
|
int minKeycode, bool pressed, bool raw);
|
||||||
const char * text);
|
void x11InputKeyboardText(X11Input * input, const char * text);
|
||||||
void x11InputKeyboardState(X11Input * input,
|
void x11InputKeyboardState(X11Input * input,
|
||||||
bool ctrl, bool shift, bool alt, bool super,
|
bool ctrl, bool shift, bool alt, bool super,
|
||||||
bool numLock, bool capsLock, bool scrollLock);
|
bool numLock, bool capsLock, bool scrollLock);
|
||||||
|
size_t x11InputHeldKeys(
|
||||||
|
const char keymap[X11_INPUT_KEYMAP_SIZE],
|
||||||
|
int minKeycode, int maxKeycode,
|
||||||
|
uint32_t * keys, size_t capacity);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -443,7 +443,6 @@ static bool x11Init(const LG_DSInitParams params)
|
|||||||
x11InputInit(&x11.input, &inputSink, NULL);
|
x11InputInit(&x11.input, &inputSink, NULL);
|
||||||
LG_LOCK_INIT(x11.pointerLock);
|
LG_LOCK_INIT(x11.pointerLock);
|
||||||
atomic_init(&x11.captureActive, false);
|
atomic_init(&x11.captureActive, false);
|
||||||
atomic_init(&x11.pointerGrabbed, false);
|
|
||||||
x11.xValuator = -1;
|
x11.xValuator = -1;
|
||||||
x11.yValuator = -1;
|
x11.yValuator = -1;
|
||||||
x11.numLockIndicator = -1;
|
x11.numLockIndicator = -1;
|
||||||
@@ -1363,19 +1362,15 @@ static void setFocus(bool focused)
|
|||||||
{
|
{
|
||||||
x11UpdateKeyboardGroup();
|
x11UpdateKeyboardGroup();
|
||||||
|
|
||||||
char keymap[32] = { 0 };
|
char keymap[X11_INPUT_KEYMAP_SIZE] = { 0 };
|
||||||
XQueryKeymap(x11.display, keymap);
|
XQueryKeymap(x11.display, keymap);
|
||||||
memset(x11.modifiers, 0, sizeof(x11.modifiers));
|
memset(x11.modifiers, 0, sizeof(x11.modifiers));
|
||||||
|
|
||||||
for (int keycode = x11.minKeycode;
|
count = x11InputHeldKeys(keymap, x11.minKeycode, x11.maxKeycode,
|
||||||
keycode <= x11.maxKeycode && keycode < 256; ++keycode)
|
keys, ARRAY_LENGTH(keys));
|
||||||
|
for (size_t i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
const unsigned char keyByte = keymap[keycode / 8];
|
const unsigned int keycode = keys[i] + x11.minKeycode;
|
||||||
if (!(keyByte & (1U << (keycode % 8))))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
keys[count++] = keycode - x11.minKeycode;
|
|
||||||
|
|
||||||
const KeySym sym = XkbKeycodeToKeysym(x11.display, keycode,
|
const KeySym sym = XkbKeycodeToKeysym(x11.display, keycode,
|
||||||
atomic_load(&x11.keyboardGroup), 0);
|
atomic_load(&x11.keyboardGroup), 0);
|
||||||
const int modifier = keySymToModifier(sym);
|
const int modifier = keySymToModifier(sym);
|
||||||
@@ -1384,7 +1379,7 @@ static void setFocus(bool focused)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
x11InputFocus(&x11.input, focused, keys, count);
|
x11InputFocus(&x11.input, focused, focused ? keys : NULL, count);
|
||||||
if (focused)
|
if (focused)
|
||||||
updateKeyboardState();
|
updateKeyboardState();
|
||||||
}
|
}
|
||||||
@@ -1519,13 +1514,11 @@ static void x11XInputEvent(XGenericEventCookie *cookie)
|
|||||||
|
|
||||||
case XI_KeyPress:
|
case XI_KeyPress:
|
||||||
{
|
{
|
||||||
if (!x11.input.focused || x11.keyboardGrabbed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
XIDeviceEvent *device = cookie->data;
|
XIDeviceEvent *device = cookie->data;
|
||||||
atomic_store(&x11.keyboardGroup, device->group.effective);
|
atomic_store(&x11.keyboardGroup, device->group.effective);
|
||||||
x11InputKeyboardKey(&x11.input, device->detail, x11.minKeycode,
|
if (!x11InputKeyboardKey(&x11.input, device->detail,
|
||||||
true, false, true, NULL);
|
x11.minKeycode, true, false))
|
||||||
|
return;
|
||||||
|
|
||||||
if (x11.xic && app_isOverlayMode())
|
if (x11.xic && app_isOverlayMode())
|
||||||
{
|
{
|
||||||
@@ -1548,7 +1541,7 @@ static void x11XInputEvent(XGenericEventCookie *cookie)
|
|||||||
else if (status == XLookupChars || status == XLookupBoth)
|
else if (status == XLookupChars || status == XLookupBoth)
|
||||||
{
|
{
|
||||||
buffer[count] = '\0';
|
buffer[count] = '\0';
|
||||||
inputText(x11.input.opaque, buffer);
|
x11InputKeyboardText(&x11.input, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1558,36 +1551,33 @@ static void x11XInputEvent(XGenericEventCookie *cookie)
|
|||||||
|
|
||||||
case XI_KeyRelease:
|
case XI_KeyRelease:
|
||||||
{
|
{
|
||||||
if (!x11.input.focused || x11.keyboardGrabbed)
|
XIDeviceEvent *device = cookie->data;
|
||||||
|
if (!x11InputKeyboardKey(&x11.input, device->detail,
|
||||||
|
x11.minKeycode, false, false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
XIDeviceEvent *device = cookie->data;
|
|
||||||
x11InputKeyboardKey(&x11.input, device->detail, x11.minKeycode,
|
|
||||||
false, false, true, NULL);
|
|
||||||
updateKeyState(device->detail, false);
|
updateKeyState(device->detail, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case XI_RawKeyPress:
|
case XI_RawKeyPress:
|
||||||
{
|
{
|
||||||
if (!x11.input.focused || !x11.keyboardGrabbed)
|
XIRawEvent *raw = cookie->data;
|
||||||
|
if (!x11InputKeyboardKey(&x11.input, raw->detail,
|
||||||
|
x11.minKeycode, true, true))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
XIRawEvent *raw = cookie->data;
|
|
||||||
x11InputKeyboardKey(&x11.input, raw->detail, x11.minKeycode,
|
|
||||||
true, true, true, NULL);
|
|
||||||
updateKeyState(raw->detail, true);
|
updateKeyState(raw->detail, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case XI_RawKeyRelease:
|
case XI_RawKeyRelease:
|
||||||
{
|
{
|
||||||
if (!x11.input.focused || !x11.keyboardGrabbed)
|
XIRawEvent *raw = cookie->data;
|
||||||
|
if (!x11InputKeyboardKey(&x11.input, raw->detail,
|
||||||
|
x11.minKeycode, false, true))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
XIRawEvent *raw = cookie->data;
|
|
||||||
x11InputKeyboardKey(&x11.input, raw->detail, x11.minKeycode,
|
|
||||||
false, true, true, NULL);
|
|
||||||
updateKeyState(raw->detail, false);
|
updateKeyState(raw->detail, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1608,10 +1598,6 @@ static void x11XInputEvent(XGenericEventCookie *cookie)
|
|||||||
|
|
||||||
case XI_RawButtonPress:
|
case XI_RawButtonPress:
|
||||||
{
|
{
|
||||||
if (!x11.input.entered ||
|
|
||||||
!atomic_load_explicit(&x11.pointerGrabbed, memory_order_acquire))
|
|
||||||
return;
|
|
||||||
|
|
||||||
XIRawEvent *raw = cookie->data;
|
XIRawEvent *raw = cookie->data;
|
||||||
x11InputPointerButton(&x11.input, raw->detail, true, true);
|
x11InputPointerButton(&x11.input, raw->detail, true, true);
|
||||||
return;
|
return;
|
||||||
@@ -1619,10 +1605,6 @@ static void x11XInputEvent(XGenericEventCookie *cookie)
|
|||||||
|
|
||||||
case XI_RawButtonRelease:
|
case XI_RawButtonRelease:
|
||||||
{
|
{
|
||||||
if (!x11.input.entered ||
|
|
||||||
!atomic_load_explicit(&x11.pointerGrabbed, memory_order_acquire))
|
|
||||||
return;
|
|
||||||
|
|
||||||
XIRawEvent *raw = cookie->data;
|
XIRawEvent *raw = cookie->data;
|
||||||
x11InputPointerButton(&x11.input, raw->detail, false, true);
|
x11InputPointerButton(&x11.input, raw->detail, false, true);
|
||||||
return;
|
return;
|
||||||
@@ -1637,10 +1619,6 @@ static void x11XInputEvent(XGenericEventCookie *cookie)
|
|||||||
|
|
||||||
case XI_RawMotion:
|
case XI_RawMotion:
|
||||||
{
|
{
|
||||||
if (!x11.input.entered ||
|
|
||||||
!atomic_load_explicit(&x11.pointerGrabbed, memory_order_acquire))
|
|
||||||
return;
|
|
||||||
|
|
||||||
XIRawEvent *raw = cookie->data;
|
XIRawEvent *raw = cookie->data;
|
||||||
double raw_axis[2] = { 0 };
|
double raw_axis[2] = { 0 };
|
||||||
double axis[2] = { 0 };
|
double axis[2] = { 0 };
|
||||||
@@ -2027,7 +2005,7 @@ static void x11PrintGrabError(const char * type, int dev, Status ret)
|
|||||||
|
|
||||||
static bool x11GrabPointerLocked(void)
|
static bool x11GrabPointerLocked(void)
|
||||||
{
|
{
|
||||||
if (atomic_load_explicit(&x11.pointerGrabbed, memory_order_acquire))
|
if (x11InputIsPointerGrabbed(&x11.input))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)] = { 0 };
|
unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)] = { 0 };
|
||||||
@@ -2076,7 +2054,7 @@ static bool x11GrabPointerLocked(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_store_explicit(&x11.pointerGrabbed, true, memory_order_release);
|
x11InputSetPointerGrabbed(&x11.input, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2089,7 +2067,7 @@ static void x11GrabPointer(void)
|
|||||||
|
|
||||||
static void x11UngrabPointerLocked(void)
|
static void x11UngrabPointerLocked(void)
|
||||||
{
|
{
|
||||||
if (!atomic_load_explicit(&x11.pointerGrabbed, memory_order_acquire))
|
if (!x11InputIsPointerGrabbed(&x11.input))
|
||||||
{
|
{
|
||||||
app_handleGrabEvent(false);
|
app_handleGrabEvent(false);
|
||||||
return;
|
return;
|
||||||
@@ -2098,7 +2076,7 @@ static void x11UngrabPointerLocked(void)
|
|||||||
XIUngrabDevice(x11.display, x11.pointerDev, CurrentTime);
|
XIUngrabDevice(x11.display, x11.pointerDev, CurrentTime);
|
||||||
XSync(x11.display, False);
|
XSync(x11.display, False);
|
||||||
|
|
||||||
atomic_store_explicit(&x11.pointerGrabbed, false, memory_order_release);
|
x11InputSetPointerGrabbed(&x11.input, false);
|
||||||
app_handleGrabEvent(false);
|
app_handleGrabEvent(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2112,7 +2090,7 @@ static void x11UngrabPointer(void)
|
|||||||
|
|
||||||
static bool x11IsPointerGrabbed(void)
|
static bool x11IsPointerGrabbed(void)
|
||||||
{
|
{
|
||||||
return atomic_load_explicit(&x11.pointerGrabbed, memory_order_acquire);
|
return x11InputIsPointerGrabbed(&x11.input);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x11CapturePointer(void)
|
static void x11CapturePointer(void)
|
||||||
@@ -2148,7 +2126,7 @@ static bool x11IsPointerCaptured(void)
|
|||||||
|
|
||||||
static void x11GrabKeyboard(void)
|
static void x11GrabKeyboard(void)
|
||||||
{
|
{
|
||||||
if (x11.keyboardGrabbed)
|
if (x11InputIsKeyboardGrabbed(&x11.input))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
||||||
@@ -2178,18 +2156,18 @@ static void x11GrabKeyboard(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
x11.keyboardGrabbed = true;
|
x11InputSetKeyboardGrabbed(&x11.input, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x11UngrabKeyboard(void)
|
static void x11UngrabKeyboard(void)
|
||||||
{
|
{
|
||||||
if (!x11.keyboardGrabbed)
|
if (!x11InputIsKeyboardGrabbed(&x11.input))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
XIUngrabDevice(x11.display, x11.keyboardDev, CurrentTime);
|
XIUngrabDevice(x11.display, x11.keyboardDev, CurrentTime);
|
||||||
XSync(x11.display, False);
|
XSync(x11.display, False);
|
||||||
|
|
||||||
x11.keyboardGrabbed = false;
|
x11InputSetKeyboardGrabbed(&x11.input, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x11WarpPointer(int x, int y, bool exiting)
|
static void x11WarpPointer(int x, int y, bool exiting)
|
||||||
|
|||||||
@@ -104,8 +104,6 @@ struct X11DSState
|
|||||||
X11Input input;
|
X11Input input;
|
||||||
LG_Lock pointerLock;
|
LG_Lock pointerLock;
|
||||||
_Atomic(bool) captureActive;
|
_Atomic(bool) captureActive;
|
||||||
_Atomic(bool) pointerGrabbed;
|
|
||||||
bool keyboardGrabbed;
|
|
||||||
bool fullscreen;
|
bool fullscreen;
|
||||||
|
|
||||||
struct Rect rect;
|
struct Rect rect;
|
||||||
|
|||||||
@@ -87,6 +87,15 @@ foreach(name IN ITEMS wheel-residual wheel-multiple)
|
|||||||
)
|
)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
foreach(name IN ITEMS pointer-routing keyboard-routing held-keys)
|
||||||
|
add_test(NAME display-input-x11-${name}
|
||||||
|
COMMAND displayserver-input-tests x11 ${name}
|
||||||
|
)
|
||||||
|
set_tests_properties(display-input-x11-${name} PROPERTIES
|
||||||
|
TIMEOUT 10
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
add_executable(mouse-tests
|
add_executable(mouse-tests
|
||||||
mouse_test.c
|
mouse_test.c
|
||||||
../src/core.c
|
../src/core.c
|
||||||
|
|||||||
@@ -523,8 +523,11 @@ static void relativeMotion(struct Fixture * fixture, bool active,
|
|||||||
if (fixture->backend == BACKEND_WAYLAND)
|
if (fixture->backend == BACKEND_WAYLAND)
|
||||||
wlInputRelativeMotion(&fixture->input.wayland, active,
|
wlInputRelativeMotion(&fixture->input.wayland, active,
|
||||||
x, y, rawX, rawY);
|
x, y, rawX, rawY);
|
||||||
else if (active)
|
else
|
||||||
|
{
|
||||||
|
x11InputSetPointerGrabbed(&fixture->input.x11, active);
|
||||||
x11InputRelativeMotion(&fixture->input.x11, x, y, rawX, rawY);
|
x11InputRelativeMotion(&fixture->input.x11, x, y, rawX, rawY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboardEnter(struct Fixture * fixture, bool mainSurface,
|
static void keyboardEnter(struct Fixture * fixture, bool mainSurface,
|
||||||
@@ -545,13 +548,17 @@ static void keyboardLeave(struct Fixture * fixture, bool mainSurface)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void keyboardKey(struct Fixture * fixture, unsigned int key,
|
static void keyboardKey(struct Fixture * fixture, unsigned int key,
|
||||||
bool pressed, const char * text, bool inputActive)
|
bool pressed, const char * text)
|
||||||
{
|
{
|
||||||
if (fixture->backend == BACKEND_WAYLAND)
|
if (fixture->backend == BACKEND_WAYLAND)
|
||||||
wlInputKeyboardKey(&fixture->input.wayland, key, pressed, text);
|
wlInputKeyboardKey(&fixture->input.wayland, key, pressed, text);
|
||||||
else
|
else
|
||||||
x11InputKeyboardKey(&fixture->input.x11, key + 8, 8, pressed,
|
{
|
||||||
false, inputActive, text);
|
const bool accepted = x11InputKeyboardKey(
|
||||||
|
&fixture->input.x11, key + 8, 8, pressed, false);
|
||||||
|
if (accepted && pressed)
|
||||||
|
x11InputKeyboardText(&fixture->input.x11, text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboardState(struct Fixture * fixture,
|
static void keyboardState(struct Fixture * fixture,
|
||||||
@@ -759,31 +766,140 @@ static void testKeyboardKeys(enum Backend backend)
|
|||||||
struct Fixture fixture;
|
struct Fixture fixture;
|
||||||
initFixture(&fixture, backend);
|
initFixture(&fixture, backend);
|
||||||
|
|
||||||
keyboardKey(&fixture, 30, true, "ignored", true);
|
keyboardKey(&fixture, 30, true, "ignored");
|
||||||
keyboardKey(&fixture, 30, false, "ignored", true);
|
keyboardKey(&fixture, 30, false, "ignored");
|
||||||
CHECK(fixture.trace.count == 0);
|
CHECK(fixture.trace.count == 0);
|
||||||
|
|
||||||
keyboardEnter(&fixture, true, NULL, 0);
|
keyboardEnter(&fixture, true, NULL, 0);
|
||||||
clearTrace(&fixture);
|
clearTrace(&fixture);
|
||||||
|
|
||||||
keyboardKey(&fixture, 30, true, "a", true);
|
keyboardKey(&fixture, 30, true, "a");
|
||||||
keyboardKey(&fixture, 30, false, "ignored", true);
|
keyboardKey(&fixture, 30, false, "ignored");
|
||||||
|
keyboardKey(&fixture, 31, true, "");
|
||||||
|
keyboardKey(&fixture, 31, false, NULL);
|
||||||
|
|
||||||
static const struct Trace expected[] =
|
static const struct Trace expected[] =
|
||||||
{
|
{
|
||||||
KEY(30, true),
|
KEY(30, true),
|
||||||
TEXT("a"),
|
TEXT("a"),
|
||||||
KEY(30, false),
|
KEY(30, false),
|
||||||
|
KEY(31, true),
|
||||||
|
KEY(31, false),
|
||||||
};
|
};
|
||||||
expectTrace(&fixture, expected, ARRAY_LENGTH(expected));
|
expectTrace(&fixture, expected, ARRAY_LENGTH(expected));
|
||||||
|
|
||||||
keyboardLeave(&fixture, true);
|
keyboardLeave(&fixture, true);
|
||||||
clearTrace(&fixture);
|
clearTrace(&fixture);
|
||||||
keyboardKey(&fixture, 31, true, "s", true);
|
keyboardKey(&fixture, 31, true, "s");
|
||||||
keyboardKey(&fixture, 31, false, NULL, true);
|
keyboardKey(&fixture, 31, false, NULL);
|
||||||
CHECK(fixture.trace.count == 0);
|
CHECK(fixture.trace.count == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void testX11PointerRouting(enum Backend backend)
|
||||||
|
{
|
||||||
|
CHECK(backend == BACKEND_X11);
|
||||||
|
|
||||||
|
struct Fixture fixture;
|
||||||
|
initFixture(&fixture, backend);
|
||||||
|
pointerEnter(&fixture, true, 40.0, 30.0);
|
||||||
|
clearTrace(&fixture);
|
||||||
|
|
||||||
|
x11InputPointerButton(&fixture.input.x11, 1, true, true);
|
||||||
|
x11InputRelativeMotion(&fixture.input.x11, 1.0, 2.0, 3.0, 4.0);
|
||||||
|
|
||||||
|
x11InputSetPointerGrabbed(&fixture.input.x11, true);
|
||||||
|
x11InputPointerButton(&fixture.input.x11, 1, true, false);
|
||||||
|
x11InputPointerButton(&fixture.input.x11, 1, true, true);
|
||||||
|
x11InputRelativeMotion(&fixture.input.x11, 1.0, 2.0, 3.0, 4.0);
|
||||||
|
|
||||||
|
x11InputSetPointerGrabbed(&fixture.input.x11, false);
|
||||||
|
x11InputPointerButton(&fixture.input.x11, 1, false, true);
|
||||||
|
x11InputRelativeMotion(&fixture.input.x11, 1.0, 2.0, 3.0, 4.0);
|
||||||
|
x11InputPointerButton(&fixture.input.x11, 1, false, false);
|
||||||
|
|
||||||
|
static const struct Trace expected[] =
|
||||||
|
{
|
||||||
|
BUTTON(1, true),
|
||||||
|
RELATIVE(1.0, 2.0, 3.0, 4.0),
|
||||||
|
BUTTON(1, false),
|
||||||
|
};
|
||||||
|
expectTrace(&fixture, expected, ARRAY_LENGTH(expected));
|
||||||
|
CHECK(fixture.input.x11.buttons == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testX11KeyboardRouting(enum Backend backend)
|
||||||
|
{
|
||||||
|
CHECK(backend == BACKEND_X11);
|
||||||
|
|
||||||
|
struct Fixture fixture;
|
||||||
|
initFixture(&fixture, backend);
|
||||||
|
keyboardEnter(&fixture, true, NULL, 0);
|
||||||
|
clearTrace(&fixture);
|
||||||
|
|
||||||
|
CHECK(!x11InputKeyboardKey(&fixture.input.x11,
|
||||||
|
30 + 8, 8, true, true));
|
||||||
|
CHECK(x11InputKeyboardKey(&fixture.input.x11,
|
||||||
|
30 + 8, 8, true, false));
|
||||||
|
x11InputKeyboardText(&fixture.input.x11, "a");
|
||||||
|
|
||||||
|
x11InputSetKeyboardGrabbed(&fixture.input.x11, true);
|
||||||
|
CHECK(!x11InputKeyboardKey(&fixture.input.x11,
|
||||||
|
31 + 8, 8, true, false));
|
||||||
|
CHECK(x11InputKeyboardKey(&fixture.input.x11,
|
||||||
|
30 + 8, 8, false, true));
|
||||||
|
CHECK(x11InputKeyboardKey(&fixture.input.x11,
|
||||||
|
31 + 8, 8, true, true));
|
||||||
|
|
||||||
|
x11InputSetKeyboardGrabbed(&fixture.input.x11, false);
|
||||||
|
CHECK(!x11InputKeyboardKey(&fixture.input.x11,
|
||||||
|
31 + 8, 8, false, true));
|
||||||
|
CHECK(x11InputKeyboardKey(&fixture.input.x11,
|
||||||
|
31 + 8, 8, false, false));
|
||||||
|
|
||||||
|
static const struct Trace expected[] =
|
||||||
|
{
|
||||||
|
KEY(30, true),
|
||||||
|
TEXT("a"),
|
||||||
|
KEY(30, false),
|
||||||
|
KEY(31, true),
|
||||||
|
KEY(31, false),
|
||||||
|
};
|
||||||
|
expectTrace(&fixture, expected, ARRAY_LENGTH(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setKeymapKey(char keymap[X11_INPUT_KEYMAP_SIZE],
|
||||||
|
unsigned int keycode)
|
||||||
|
{
|
||||||
|
CHECK(keycode < X11_INPUT_KEYMAP_SIZE * 8);
|
||||||
|
keymap[keycode / 8] = (char)(
|
||||||
|
(unsigned char)keymap[keycode / 8] | (1U << (keycode % 8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testX11HeldKeys(enum Backend backend)
|
||||||
|
{
|
||||||
|
CHECK(backend == BACKEND_X11);
|
||||||
|
|
||||||
|
char keymap[X11_INPUT_KEYMAP_SIZE] = { 0 };
|
||||||
|
setKeymapKey(keymap, 7);
|
||||||
|
setKeymapKey(keymap, 8);
|
||||||
|
setKeymapKey(keymap, 30);
|
||||||
|
setKeymapKey(keymap, 42);
|
||||||
|
setKeymapKey(keymap, 43);
|
||||||
|
|
||||||
|
uint32_t keys[4];
|
||||||
|
size_t count = x11InputHeldKeys(keymap, 8, 42,
|
||||||
|
keys, ARRAY_LENGTH(keys));
|
||||||
|
CHECK(count == 3);
|
||||||
|
CHECK(keys[0] == 0);
|
||||||
|
CHECK(keys[1] == 22);
|
||||||
|
CHECK(keys[2] == 34);
|
||||||
|
|
||||||
|
count = x11InputHeldKeys(keymap, 8, 42, keys, 2);
|
||||||
|
CHECK(count == 2);
|
||||||
|
CHECK(keys[0] == 0);
|
||||||
|
CHECK(keys[1] == 22);
|
||||||
|
}
|
||||||
|
|
||||||
static void testKeyboardState(enum Backend backend)
|
static void testKeyboardState(enum Backend backend)
|
||||||
{
|
{
|
||||||
struct Fixture fixture;
|
struct Fixture fixture;
|
||||||
@@ -815,15 +931,18 @@ struct Test
|
|||||||
static const struct Test tests[] =
|
static const struct Test tests[] =
|
||||||
{
|
{
|
||||||
{ "pointer-events" , testPointerEvents },
|
{ "pointer-events" , testPointerEvents },
|
||||||
{ "pointer-buttons", testPointerButtons },
|
{ "pointer-buttons" , testPointerButtons },
|
||||||
{ "pointer-release", testPointerRelease },
|
{ "pointer-release" , testPointerRelease },
|
||||||
{ "wheel-steps" , testWheelSteps },
|
{ "wheel-steps" , testWheelSteps },
|
||||||
{ "wheel-residual" , testWheelResidual },
|
{ "wheel-residual" , testWheelResidual },
|
||||||
{ "wheel-multiple" , testWheelMultiple },
|
{ "wheel-multiple" , testWheelMultiple },
|
||||||
{ "relative-motion", testRelativeMotion },
|
{ "relative-motion" , testRelativeMotion },
|
||||||
{ "keyboard-focus" , testKeyboardFocus },
|
{ "keyboard-focus" , testKeyboardFocus },
|
||||||
{ "keyboard-keys" , testKeyboardKeys },
|
{ "keyboard-keys" , testKeyboardKeys },
|
||||||
{ "keyboard-state" , testKeyboardState },
|
{ "keyboard-state" , testKeyboardState },
|
||||||
|
{ "pointer-routing" , testX11PointerRouting },
|
||||||
|
{ "keyboard-routing", testX11KeyboardRouting },
|
||||||
|
{ "held-keys" , testX11HeldKeys },
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool parseBackend(const char * name, enum Backend * backend)
|
static bool parseBackend(const char * name, enum Backend * backend)
|
||||||
|
|||||||
Reference in New Issue
Block a user