mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-10 17:21:32 +00:00
[client] X11: match Wayland pointer input behaviour
Make cooked mouse input independent of keyboard focus. Preserve button state across pointer leave events. Match Wayland event order, wheel steps, and raw motion delivery.
This commit is contained in:
@@ -63,43 +63,33 @@ bool x11InputPointerEnter(X11Input * input, bool mainWindow,
|
|||||||
if (input->entered || !mainWindow || !normal)
|
if (input->entered || !mainWindow || !normal)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
input->sink->position(input->opaque, x, y);
|
|
||||||
input->sink->enter(input->opaque, true);
|
|
||||||
input->entered = true;
|
input->entered = true;
|
||||||
|
input->sink->enter(input->opaque, true);
|
||||||
|
input->sink->position(input->opaque, x, y);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool x11InputPointerLeave(X11Input * input, bool mainWindow,
|
bool x11InputPointerLeave(X11Input * input, bool mainWindow,
|
||||||
bool normal, bool captureMode, double x, double y)
|
bool normal, bool captureMode)
|
||||||
{
|
{
|
||||||
if (!input->entered || !mainWindow || input->buttons || captureMode ||
|
if (!input->entered || !mainWindow || input->buttons || captureMode ||
|
||||||
!normal)
|
!normal)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
input->sink->position(input->opaque, x, y);
|
|
||||||
input->sink->enter(input->opaque, false);
|
|
||||||
input->entered = false;
|
input->entered = false;
|
||||||
|
input->sink->enter(input->opaque, false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void x11InputPointerMotion(X11Input * input, double x, double y,
|
void x11InputPointerMotion(X11Input * input, double x, double y)
|
||||||
bool pointerGrabbed)
|
|
||||||
{
|
{
|
||||||
input->sink->position(input->opaque, x, y);
|
input->sink->position(input->opaque, x, y);
|
||||||
|
|
||||||
if (!pointerGrabbed)
|
|
||||||
input->sink->relative(input->opaque, 0.0, 0.0, 0.0, 0.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void x11InputPointerButton(X11Input * input, unsigned int detail,
|
void x11InputPointerButton(X11Input * input, unsigned int detail,
|
||||||
bool pressed, bool raw, uint32_t time, bool inputActive)
|
bool pressed, bool raw)
|
||||||
{
|
{
|
||||||
if (raw)
|
if (!raw && !input->entered)
|
||||||
{
|
|
||||||
if (!inputActive)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (!input->focused || !input->entered)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const unsigned int button = mapButton(detail);
|
const unsigned int button = mapButton(detail);
|
||||||
@@ -108,25 +98,17 @@ void x11InputPointerButton(X11Input * input, unsigned int detail,
|
|||||||
|
|
||||||
if (!raw)
|
if (!raw)
|
||||||
{
|
{
|
||||||
if (pressed && button == 4)
|
if (button == 4 || button == 5)
|
||||||
input->sink->wheel(input->opaque, -0.5);
|
{
|
||||||
else if (pressed && button == 5)
|
if (pressed)
|
||||||
input->sink->wheel(input->opaque, 0.5);
|
{
|
||||||
else if (button != 4 && button != 5)
|
input->sink->button(input->opaque, button, true);
|
||||||
input->sink->button(input->opaque, button, pressed);
|
input->sink->button(input->opaque, button, false);
|
||||||
|
input->sink->wheel(input->opaque, button == 4 ? -1.0 : 1.0);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
uint32_t * previousTime = pressed ?
|
|
||||||
&input->previousPressTime : &input->previousReleaseTime;
|
|
||||||
uint32_t * previousButton = pressed ?
|
|
||||||
&input->previousPressButton : &input->previousReleaseButton;
|
|
||||||
|
|
||||||
if (time == *previousTime && detail == *previousButton)
|
|
||||||
return;
|
|
||||||
|
|
||||||
*previousTime = time;
|
|
||||||
*previousButton = detail;
|
|
||||||
|
|
||||||
const uint32_t mask = UINT32_C(1) << button;
|
const uint32_t mask = UINT32_C(1) << button;
|
||||||
if (pressed)
|
if (pressed)
|
||||||
@@ -137,20 +119,9 @@ void x11InputPointerButton(X11Input * input, unsigned int detail,
|
|||||||
input->sink->button(input->opaque, button, pressed);
|
input->sink->button(input->opaque, button, pressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void x11InputRelativeMotion(X11Input * input, uint32_t time,
|
void x11InputRelativeMotion(X11Input * input,
|
||||||
double x, double y, double rawX, double rawY, bool inputActive)
|
double x, double y, double rawX, double rawY)
|
||||||
{
|
{
|
||||||
if (!inputActive)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (time == input->previousMotionTime &&
|
|
||||||
x == input->previousMotionX && y == input->previousMotionY)
|
|
||||||
return;
|
|
||||||
|
|
||||||
input->previousMotionTime = time;
|
|
||||||
input->previousMotionX = x;
|
|
||||||
input->previousMotionY = y;
|
|
||||||
|
|
||||||
input->sink->relative(input->opaque, x, y, rawX, rawY);
|
input->sink->relative(input->opaque, x, y, rawX, rawY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,13 +32,6 @@ typedef struct X11Input
|
|||||||
const LG_DSInputSink * sink;
|
const LG_DSInputSink * sink;
|
||||||
void * opaque;
|
void * opaque;
|
||||||
uint32_t buttons;
|
uint32_t buttons;
|
||||||
uint32_t previousPressTime;
|
|
||||||
uint32_t previousReleaseTime;
|
|
||||||
uint32_t previousPressButton;
|
|
||||||
uint32_t previousReleaseButton;
|
|
||||||
uint32_t previousMotionTime;
|
|
||||||
double previousMotionX;
|
|
||||||
double previousMotionY;
|
|
||||||
bool entered;
|
bool entered;
|
||||||
bool focused;
|
bool focused;
|
||||||
}
|
}
|
||||||
@@ -52,13 +45,12 @@ bool x11InputFocus(X11Input * input, bool focused, double x, double y,
|
|||||||
bool x11InputPointerEnter(X11Input * input, bool mainWindow,
|
bool x11InputPointerEnter(X11Input * input, bool mainWindow,
|
||||||
bool normal, double x, double y);
|
bool normal, double x, double y);
|
||||||
bool x11InputPointerLeave(X11Input * input, bool mainWindow,
|
bool x11InputPointerLeave(X11Input * input, bool mainWindow,
|
||||||
bool normal, bool captureMode, double x, double y);
|
bool normal, bool captureMode);
|
||||||
void x11InputPointerMotion(X11Input * input, double x, double y,
|
void x11InputPointerMotion(X11Input * input, double x, double y);
|
||||||
bool pointerGrabbed);
|
|
||||||
void x11InputPointerButton(X11Input * input, unsigned int button,
|
void x11InputPointerButton(X11Input * input, unsigned int button,
|
||||||
bool pressed, bool raw, uint32_t time, bool inputActive);
|
bool pressed, bool raw);
|
||||||
void x11InputRelativeMotion(X11Input * input, uint32_t time,
|
void x11InputRelativeMotion(X11Input * input,
|
||||||
double x, double y, double rawX, double rawY, bool inputActive);
|
double x, double y, double rawX, double rawY);
|
||||||
void x11InputKeyboardKey(X11Input * input, unsigned int keycode,
|
void x11InputKeyboardKey(X11Input * input, unsigned int keycode,
|
||||||
int minKeycode, bool pressed, bool raw, bool inputActive,
|
int minKeycode, bool pressed, bool raw, bool inputActive,
|
||||||
const char * text);
|
const char * text);
|
||||||
|
|||||||
@@ -1373,8 +1373,7 @@ static void x11XInputEvent(XGenericEventCookie *cookie)
|
|||||||
XILeaveEvent *xie = cookie->data;
|
XILeaveEvent *xie = cookie->data;
|
||||||
|
|
||||||
if (!x11InputPointerLeave(&x11.input, xie->event == x11.window,
|
if (!x11InputPointerLeave(&x11.input, xie->event == x11.window,
|
||||||
xie->mode != NotifyGrab, app_isCaptureMode(),
|
xie->mode != NotifyGrab, app_isCaptureMode()))
|
||||||
xie->event_x, xie->event_y))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1520,46 +1519,52 @@ static void x11XInputEvent(XGenericEventCookie *cookie)
|
|||||||
case XI_ButtonPress:
|
case XI_ButtonPress:
|
||||||
{
|
{
|
||||||
XIDeviceEvent *device = cookie->data;
|
XIDeviceEvent *device = cookie->data;
|
||||||
x11InputPointerButton(&x11.input, device->detail, true, false,
|
x11InputPointerButton(&x11.input, device->detail, true, false);
|
||||||
device->time, true);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case XI_ButtonRelease:
|
case XI_ButtonRelease:
|
||||||
{
|
{
|
||||||
XIDeviceEvent *device = cookie->data;
|
XIDeviceEvent *device = cookie->data;
|
||||||
x11InputPointerButton(&x11.input, device->detail, false, false,
|
x11InputPointerButton(&x11.input, device->detail, false, false);
|
||||||
device->time, true);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
raw->time, x11.input.focused && x11.input.entered);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
raw->time, x11.input.focused && x11.input.entered);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case XI_Motion:
|
case XI_Motion:
|
||||||
{
|
{
|
||||||
XIDeviceEvent *device = cookie->data;
|
XIDeviceEvent *device = cookie->data;
|
||||||
x11InputPointerMotion(&x11.input, device->event_x, device->event_y,
|
x11InputPointerMotion(&x11.input, device->event_x, device->event_y);
|
||||||
atomic_load_explicit(&x11.pointerGrabbed,
|
|
||||||
memory_order_acquire));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 };
|
||||||
@@ -1594,9 +1599,8 @@ static void x11XInputEvent(XGenericEventCookie *cookie)
|
|||||||
if (!has_axes)
|
if (!has_axes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
x11InputRelativeMotion(&x11.input, raw->time, axis[0], axis[1],
|
x11InputRelativeMotion(&x11.input, axis[0], axis[1],
|
||||||
raw_axis[0], raw_axis[1],
|
raw_axis[0], raw_axis[1]);
|
||||||
x11.input.focused && x11.input.entered);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,7 +168,6 @@ struct Fixture
|
|||||||
{
|
{
|
||||||
enum Backend backend;
|
enum Backend backend;
|
||||||
struct TraceLog trace;
|
struct TraceLog trace;
|
||||||
uint32_t time;
|
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
@@ -278,7 +277,6 @@ static void initFixture(struct Fixture * fixture, enum Backend backend)
|
|||||||
{
|
{
|
||||||
memset(fixture, 0, sizeof(*fixture));
|
memset(fixture, 0, sizeof(*fixture));
|
||||||
fixture->backend = backend;
|
fixture->backend = backend;
|
||||||
fixture->time = 1;
|
|
||||||
|
|
||||||
if (backend == BACKEND_WAYLAND)
|
if (backend == BACKEND_WAYLAND)
|
||||||
wlInputInit(&fixture->input.wayland, &sink, &fixture->trace);
|
wlInputInit(&fixture->input.wayland, &sink, &fixture->trace);
|
||||||
@@ -455,14 +453,12 @@ static void pointerEnter(struct Fixture * fixture, bool mainSurface,
|
|||||||
x11InputPointerEnter(&fixture->input.x11, mainSurface, true, x, y);
|
x11InputPointerEnter(&fixture->input.x11, mainSurface, true, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointerLeave(struct Fixture * fixture, bool mainSurface,
|
static void pointerLeave(struct Fixture * fixture, bool mainSurface)
|
||||||
double x, double y)
|
|
||||||
{
|
{
|
||||||
if (fixture->backend == BACKEND_WAYLAND)
|
if (fixture->backend == BACKEND_WAYLAND)
|
||||||
wlInputPointerLeave(&fixture->input.wayland, mainSurface);
|
wlInputPointerLeave(&fixture->input.wayland, mainSurface);
|
||||||
else
|
else
|
||||||
x11InputPointerLeave(&fixture->input.x11, mainSurface, true, false,
|
x11InputPointerLeave(&fixture->input.x11, mainSurface, true, false);
|
||||||
x, y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointerMotion(struct Fixture * fixture, double x, double y)
|
static void pointerMotion(struct Fixture * fixture, double x, double y)
|
||||||
@@ -470,7 +466,7 @@ static void pointerMotion(struct Fixture * fixture, double x, double y)
|
|||||||
if (fixture->backend == BACKEND_WAYLAND)
|
if (fixture->backend == BACKEND_WAYLAND)
|
||||||
wlInputPointerMotion(&fixture->input.wayland, x, y);
|
wlInputPointerMotion(&fixture->input.wayland, x, y);
|
||||||
else
|
else
|
||||||
x11InputPointerMotion(&fixture->input.x11, x, y, false);
|
x11InputPointerMotion(&fixture->input.x11, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int nativeButton(enum Backend backend,
|
static unsigned int nativeButton(enum Backend backend,
|
||||||
@@ -501,8 +497,7 @@ static void pointerButton(struct Fixture * fixture, unsigned int button,
|
|||||||
if (fixture->backend == BACKEND_WAYLAND)
|
if (fixture->backend == BACKEND_WAYLAND)
|
||||||
wlInputPointerButton(&fixture->input.wayland, native, pressed);
|
wlInputPointerButton(&fixture->input.wayland, native, pressed);
|
||||||
else
|
else
|
||||||
x11InputPointerButton(&fixture->input.x11, native, pressed, false,
|
x11InputPointerButton(&fixture->input.x11, native, pressed, false);
|
||||||
fixture->time++, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unmappedButton(struct Fixture * fixture)
|
static void unmappedButton(struct Fixture * fixture)
|
||||||
@@ -510,8 +505,7 @@ static void unmappedButton(struct Fixture * fixture)
|
|||||||
if (fixture->backend == BACKEND_WAYLAND)
|
if (fixture->backend == BACKEND_WAYLAND)
|
||||||
wlInputPointerButton(&fixture->input.wayland, BTN_STYLUS, true);
|
wlInputPointerButton(&fixture->input.wayland, BTN_STYLUS, true);
|
||||||
else
|
else
|
||||||
x11InputPointerButton(&fixture->input.x11, 6, true, false,
|
x11InputPointerButton(&fixture->input.x11, 6, true, false);
|
||||||
fixture->time++, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wheelStep(struct Fixture * fixture, bool down)
|
static void wheelStep(struct Fixture * fixture, bool down)
|
||||||
@@ -520,18 +514,17 @@ static void wheelStep(struct Fixture * fixture, bool down)
|
|||||||
wlInputPointerAxis(&fixture->input.wayland, true, down ? 15.0 : -15.0);
|
wlInputPointerAxis(&fixture->input.wayland, true, down ? 15.0 : -15.0);
|
||||||
else
|
else
|
||||||
x11InputPointerButton(&fixture->input.x11, down ? 5 : 4, true,
|
x11InputPointerButton(&fixture->input.x11, down ? 5 : 4, true,
|
||||||
false, fixture->time++, true);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void relativeMotion(struct Fixture * fixture, bool active,
|
static void relativeMotion(struct Fixture * fixture, bool active,
|
||||||
uint32_t time, double x, double y, double rawX, double rawY)
|
double x, double y, double rawX, double rawY)
|
||||||
{
|
{
|
||||||
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
|
else if (active)
|
||||||
x11InputRelativeMotion(&fixture->input.x11, time,
|
x11InputRelativeMotion(&fixture->input.x11, x, y, rawX, rawY);
|
||||||
x, y, rawX, rawY, active);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboardEnter(struct Fixture * fixture, bool mainSurface,
|
static void keyboardEnter(struct Fixture * fixture, bool mainSurface,
|
||||||
@@ -594,8 +587,8 @@ static void testPointerEvents(enum Backend backend)
|
|||||||
pointerEnter(&fixture, false, 1.0, 2.0);
|
pointerEnter(&fixture, false, 1.0, 2.0);
|
||||||
pointerEnter(&fixture, true, 10.0, 20.0);
|
pointerEnter(&fixture, true, 10.0, 20.0);
|
||||||
pointerMotion(&fixture, 11.5, 21.25);
|
pointerMotion(&fixture, 11.5, 21.25);
|
||||||
pointerLeave(&fixture, false, 4.0, 5.0);
|
pointerLeave(&fixture, false);
|
||||||
pointerLeave(&fixture, true, 12.0, 22.0);
|
pointerLeave(&fixture, true);
|
||||||
|
|
||||||
static const struct Trace expected[] =
|
static const struct Trace expected[] =
|
||||||
{
|
{
|
||||||
@@ -645,7 +638,7 @@ static void testPointerRelease(enum Backend backend)
|
|||||||
|
|
||||||
/* Wayland's implicit pointer grab suppresses this native leave. */
|
/* Wayland's implicit pointer grab suppresses this native leave. */
|
||||||
if (backend == BACKEND_X11)
|
if (backend == BACKEND_X11)
|
||||||
pointerLeave(&fixture, true, 100.0, 100.0);
|
pointerLeave(&fixture, true);
|
||||||
|
|
||||||
pointerButton(&fixture, 1, false);
|
pointerButton(&fixture, 1, false);
|
||||||
|
|
||||||
@@ -728,9 +721,9 @@ static void testRelativeMotion(enum Backend backend)
|
|||||||
initFixture(&fixture, backend);
|
initFixture(&fixture, backend);
|
||||||
activateInput(&fixture);
|
activateInput(&fixture);
|
||||||
|
|
||||||
relativeMotion(&fixture, false, 50, 1.0, 2.0, 3.0, 4.0);
|
relativeMotion(&fixture, false, 1.0, 2.0, 3.0, 4.0);
|
||||||
relativeMotion(&fixture, true, 51, 1.0, 2.0, 3.0, 4.0);
|
relativeMotion(&fixture, true, 1.0, 2.0, 3.0, 4.0);
|
||||||
relativeMotion(&fixture, true, 51, 1.0, 2.0, 3.0, 4.0);
|
relativeMotion(&fixture, true, 1.0, 2.0, 3.0, 4.0);
|
||||||
|
|
||||||
static const struct Trace expected[] =
|
static const struct Trace expected[] =
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user