[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:
Geoffrey McRae
2026-08-10 17:20:47 +10:00
parent b8955fd012
commit f8c4ef3360
4 changed files with 59 additions and 99 deletions

View File

@@ -63,43 +63,33 @@ bool x11InputPointerEnter(X11Input * input, bool mainWindow,
if (input->entered || !mainWindow || !normal)
return false;
input->sink->position(input->opaque, x, y);
input->sink->enter(input->opaque, true);
input->entered = true;
input->sink->enter(input->opaque, true);
input->sink->position(input->opaque, x, y);
return true;
}
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 ||
!normal)
return false;
input->sink->position(input->opaque, x, y);
input->sink->enter(input->opaque, false);
input->entered = false;
input->sink->enter(input->opaque, false);
return true;
}
void x11InputPointerMotion(X11Input * input, double x, double y,
bool pointerGrabbed)
void x11InputPointerMotion(X11Input * input, double x, double 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,
bool pressed, bool raw, uint32_t time, bool inputActive)
bool pressed, bool raw)
{
if (raw)
{
if (!inputActive)
return;
}
else if (!input->focused || !input->entered)
if (!raw && !input->entered)
return;
const unsigned int button = mapButton(detail);
@@ -108,26 +98,18 @@ void x11InputPointerButton(X11Input * input, unsigned int detail,
if (!raw)
{
if (pressed && button == 4)
input->sink->wheel(input->opaque, -0.5);
else if (pressed && button == 5)
input->sink->wheel(input->opaque, 0.5);
else if (button != 4 && button != 5)
input->sink->button(input->opaque, button, pressed);
return;
if (button == 4 || button == 5)
{
if (pressed)
{
input->sink->button(input->opaque, button, true);
input->sink->button(input->opaque, button, false);
input->sink->wheel(input->opaque, button == 4 ? -1.0 : 1.0);
}
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;
if (pressed)
input->buttons |= mask;
@@ -137,20 +119,9 @@ void x11InputPointerButton(X11Input * input, unsigned int detail,
input->sink->button(input->opaque, button, pressed);
}
void x11InputRelativeMotion(X11Input * input, uint32_t time,
double x, double y, double rawX, double rawY, bool inputActive)
void x11InputRelativeMotion(X11Input * input,
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);
}

View File

@@ -32,13 +32,6 @@ typedef struct X11Input
const LG_DSInputSink * sink;
void * opaque;
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 focused;
}
@@ -52,13 +45,12 @@ bool x11InputFocus(X11Input * input, bool focused, double x, double y,
bool x11InputPointerEnter(X11Input * input, bool mainWindow,
bool normal, double x, double y);
bool x11InputPointerLeave(X11Input * input, bool mainWindow,
bool normal, bool captureMode, double x, double y);
void x11InputPointerMotion(X11Input * input, double x, double y,
bool pointerGrabbed);
bool normal, bool captureMode);
void x11InputPointerMotion(X11Input * input, double x, double y);
void x11InputPointerButton(X11Input * input, unsigned int button,
bool pressed, bool raw, uint32_t time, bool inputActive);
void x11InputRelativeMotion(X11Input * input, uint32_t time,
double x, double y, double rawX, double rawY, bool inputActive);
bool pressed, bool raw);
void x11InputRelativeMotion(X11Input * input,
double x, double y, double rawX, double rawY);
void x11InputKeyboardKey(X11Input * input, unsigned int keycode,
int minKeycode, bool pressed, bool raw, bool inputActive,
const char * text);

View File

@@ -1373,8 +1373,7 @@ static void x11XInputEvent(XGenericEventCookie *cookie)
XILeaveEvent *xie = cookie->data;
if (!x11InputPointerLeave(&x11.input, xie->event == x11.window,
xie->mode != NotifyGrab, app_isCaptureMode(),
xie->event_x, xie->event_y))
xie->mode != NotifyGrab, app_isCaptureMode()))
return;
/**
@@ -1520,46 +1519,52 @@ static void x11XInputEvent(XGenericEventCookie *cookie)
case XI_ButtonPress:
{
XIDeviceEvent *device = cookie->data;
x11InputPointerButton(&x11.input, device->detail, true, false,
device->time, true);
x11InputPointerButton(&x11.input, device->detail, true, false);
return;
}
case XI_ButtonRelease:
{
XIDeviceEvent *device = cookie->data;
x11InputPointerButton(&x11.input, device->detail, false, false,
device->time, true);
x11InputPointerButton(&x11.input, device->detail, false, false);
return;
}
case XI_RawButtonPress:
{
if (!x11.input.entered ||
!atomic_load_explicit(&x11.pointerGrabbed, memory_order_acquire))
return;
XIRawEvent *raw = cookie->data;
x11InputPointerButton(&x11.input, raw->detail, true, true,
raw->time, x11.input.focused && x11.input.entered);
x11InputPointerButton(&x11.input, raw->detail, true, true);
return;
}
case XI_RawButtonRelease:
{
if (!x11.input.entered ||
!atomic_load_explicit(&x11.pointerGrabbed, memory_order_acquire))
return;
XIRawEvent *raw = cookie->data;
x11InputPointerButton(&x11.input, raw->detail, false, true,
raw->time, x11.input.focused && x11.input.entered);
x11InputPointerButton(&x11.input, raw->detail, false, true);
return;
}
case XI_Motion:
{
XIDeviceEvent *device = cookie->data;
x11InputPointerMotion(&x11.input, device->event_x, device->event_y,
atomic_load_explicit(&x11.pointerGrabbed,
memory_order_acquire));
x11InputPointerMotion(&x11.input, device->event_x, device->event_y);
return;
}
case XI_RawMotion:
{
if (!x11.input.entered ||
!atomic_load_explicit(&x11.pointerGrabbed, memory_order_acquire))
return;
XIRawEvent *raw = cookie->data;
double raw_axis[2] = { 0 };
double axis[2] = { 0 };
@@ -1594,9 +1599,8 @@ static void x11XInputEvent(XGenericEventCookie *cookie)
if (!has_axes)
return;
x11InputRelativeMotion(&x11.input, raw->time, axis[0], axis[1],
raw_axis[0], raw_axis[1],
x11.input.focused && x11.input.entered);
x11InputRelativeMotion(&x11.input, axis[0], axis[1],
raw_axis[0], raw_axis[1]);
return;
}
}