From 358515f4a8ca5f45af1dc9bbe9367646b14725ed Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 27 Mar 2021 11:35:04 +0200 Subject: [PATCH] [client] x11: Find and use the correct valuators for mouse axes Using the first two valuators present in the event is incorrect. Events with only one valuator set, such as those sent by the Xorg evdev driver when the mouse moved along one axis only, were being discarded. On the other hand, mice with multiple scroll wheels may be able to emit events with two scroll wheel valuators set. The XInput2 specification is light on details, but "Rel X" and "Rel Y" appear to be the de facto standard names for the motion valuators. If valuators with those labels are not found, fall back to using valuators with numbers 0 and 1. --- client/displayservers/X11/x11.c | 51 ++++++++++++++++++++++++--------- client/displayservers/X11/x11.h | 2 ++ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/client/displayservers/X11/x11.c b/client/displayservers/X11/x11.c index 46112457..518ead7b 100644 --- a/client/displayservers/X11/x11.c +++ b/client/displayservers/X11/x11.c @@ -96,6 +96,8 @@ static bool x11Init(const LG_DSInitParams params) int event, error; memset(&x11, 0, sizeof(x11)); + x11.xValuator = -1; + x11.yValuator = -1; x11.display = XOpenDisplay(NULL); XSetWindowAttributes swa = @@ -289,24 +291,39 @@ static bool x11Init(const LG_DSInitParams params) goto fail_window; } + Atom rel_x = XInternAtom(x11.display, "Rel X", True); + Atom rel_y = XInternAtom(x11.display, "Rel Y", True); + bool havePointer = false; bool haveKeyboard = false; for(int i = 0; i < count; ++i) { /* look for the master pointing device */ if (!havePointer && devinfo[i].use == XIMasterPointer) + { for(int j = 0; j < devinfo[i].num_classes; ++j) { XIAnyClassInfo *cdevinfo = (XIAnyClassInfo *)(devinfo[i].classes[j]); if (cdevinfo->type == XIValuatorClass) { - havePointer = true; - x11.pointerDev = devinfo[i].deviceid; - break; + XIValuatorClassInfo *vdevinfo = (XIValuatorClassInfo *)cdevinfo; + if (vdevinfo->label == rel_x || (!vdevinfo->label && + vdevinfo->number == 0 && vdevinfo->mode == XIModeRelative)) + x11.xValuator = vdevinfo->number; + else if (vdevinfo->label == rel_y || (!vdevinfo->label && + vdevinfo->number == 1 && vdevinfo->mode == XIModeRelative)) + x11.yValuator = vdevinfo->number; } } + if (x11.xValuator >= 0 && x11.yValuator >= 0) + { + havePointer = true; + x11.pointerDev = devinfo[i].deviceid; + } + } + /* look for the master keyboard device */ if (!haveKeyboard && devinfo[i].use == XIMasterKeyboard) for(int j = 0; j < devinfo[i].num_classes; ++j) @@ -817,31 +834,37 @@ static void x11GenericEvent(XGenericEventCookie *cookie) return; XIRawEvent *raw = cookie->data; - double raw_axis[2]; - double axis[2]; + double raw_axis[2] = { 0 }; + double axis[2] = { 0 }; /* select the active validators for the X & Y axis */ double *valuator = raw->valuators.values; double *r_value = raw->raw_values; - int count = 0; + bool has_axes = false; for(int i = 0; i < raw->valuators.mask_len * 8; ++i) { if (XIMaskIsSet(raw->valuators.mask, i)) { - raw_axis[count] = *r_value; - axis [count] = *valuator; - ++count; - - if (count == 2) - break; + if (i == x11.xValuator) + { + raw_axis[0] = *r_value; + axis [0] = *valuator; + has_axes = true; + } + else if (i == x11.yValuator) + { + raw_axis[1] = *r_value; + axis [1] = *valuator; + has_axes = true; + } ++valuator; ++r_value; } } - /* filter out scroll wheel and other events */ - if (count < 2) + /* filter out events with no axis data */ + if (!has_axes) return; /* filter out duplicate events */ diff --git a/client/displayservers/X11/x11.h b/client/displayservers/X11/x11.h index 105050f3..69425c59 100644 --- a/client/displayservers/X11/x11.h +++ b/client/displayservers/X11/x11.h @@ -38,6 +38,8 @@ struct X11DSState int pointerDev; int keyboardDev; + int xValuator; + int yValuator; bool pointerGrabbed; bool keyboardGrabbed;