From ed1788b8c3a78f6dc523487e46e202a5f667407c Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Sat, 10 Oct 2020 02:53:41 +0300 Subject: Add support for XI 2.4 gesture events --- include/X11/extensions/XInput2.h | 104 ++++++++++++++++++++++ man/XIGrabButton.txt | 65 +++++++++++--- man/XIQueryDevice.txt | 19 +++- src/XExtInt.c | 184 ++++++++++++++++++++++++++++++++++++++- src/XIPassiveGrab.c | 59 +++++++++++++ src/XIint.h | 1 + 6 files changed, 418 insertions(+), 14 deletions(-) diff --git a/include/X11/extensions/XInput2.h b/include/X11/extensions/XInput2.h index 33670eb..2722142 100644 --- a/include/X11/extensions/XInput2.h +++ b/include/X11/extensions/XInput2.h @@ -153,6 +153,14 @@ typedef struct int num_touches; } XITouchClassInfo; +/* new in XI 2.4 */ +typedef struct +{ + int type; + int sourceid; + int num_touches; +} XIGestureClassInfo; + typedef struct { int deviceid; @@ -360,6 +368,62 @@ typedef struct { BarrierEventID eventid; } XIBarrierEvent; +typedef struct { + int type; /* GenericEvent */ + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + int extension; /* XI extension offset */ + int evtype; + Time time; + int deviceid; + int sourceid; + int detail; + Window root; + Window event; + Window child; + double root_x; + double root_y; + double event_x; + double event_y; + double delta_x; + double delta_y; + double delta_unaccel_x; + double delta_unaccel_y; + double scale; + double delta_angle; + int flags; + XIModifierState mods; + XIGroupState group; +} XIGesturePinchEvent; + +typedef struct { + int type; /* GenericEvent */ + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + int extension; /* XI extension offset */ + int evtype; + Time time; + int deviceid; + int sourceid; + int detail; + Window root; + Window event; + Window child; + double root_x; + double root_y; + double event_x; + double event_y; + double delta_x; + double delta_y; + double delta_unaccel_x; + double delta_unaccel_y; + int flags; + XIModifierState mods; + XIGroupState group; +} XIGestureSwipeEvent; + _XFUNCPROTOBEGIN extern Bool XIQueryPointer( @@ -553,6 +617,30 @@ extern int XIGrabTouchBegin( XIGrabModifiers *modifiers_inout ); +extern int XIGrabPinchGestureBegin( + Display* display, + int deviceid, + Window grab_window, + int grab_mode, + int paired_device_mode, + int owner_events, + XIEventMask *mask, + int num_modifiers, + XIGrabModifiers *modifiers_inout +); + +extern int XIGrabSwipeGestureBegin( + Display* display, + int deviceid, + Window grab_window, + int grab_mode, + int paired_device_mode, + int owner_events, + XIEventMask *mask, + int num_modifiers, + XIGrabModifiers *modifiers_inout +); + extern Status XIUngrabButton( Display* display, int deviceid, @@ -595,6 +683,22 @@ extern Status XIUngrabTouchBegin( XIGrabModifiers *modifiers ); +extern Status XIUngrabPinchGestureBegin( + Display* display, + int deviceid, + Window grab_window, + int num_modifiers, + XIGrabModifiers *modifiers +); + +extern Status XIUngrabSwipeGestureBegin( + Display* display, + int deviceid, + Window grab_window, + int num_modifiers, + XIGrabModifiers *modifiers +); + extern Atom *XIListProperties( Display* display, int deviceid, diff --git a/man/XIGrabButton.txt b/man/XIGrabButton.txt index c5100fb..5d638f1 100644 --- a/man/XIGrabButton.txt +++ b/man/XIGrabButton.txt @@ -4,7 +4,7 @@ XIGRABBUTTON(libmansuffix) NAME ---- - XIGrabButton, XIUngrabButton, XIGrabKeycode, XIUngrabKeycode, XIGrabTouchBegin, XIUngrabTouchBegin - grab/ungrab buttons or keys + XIGrabButton, XIUngrabButton, XIGrabKeycode, XIUngrabKeycode, XIGrabTouchBegin, XIUngrabTouchBegin, XIGrabPinchGestureBegin, XIUngrabPinchGestureBegin, XIGrabSwipeGestureBegin, XIUngrabSwipeGestureBegin - grab/ungrab buttons or keys SYNOPSIS -------- @@ -62,6 +62,38 @@ SYNOPSIS int num_modifiers, XIGrabModifiers *modifiers); + int XIGrabPinchGestureBegin( Display* display, + int deviceid, + Window grab_window, + int grab_mode, + int paired_device_mode, + int owner_events, + XIEventMask *mask, + int num_modifiers, + XIGrabModifiers *modifiers_inout); + + int XIUngrabPinchGestureBegin( Display* display, + int deviceid, + Window grab_window, + int num_modifiers, + XIGrabModifiers *modifiers); + + int XIGrabSwipeGestureBegin( Display* display, + int deviceid, + Window grab_window, + int grab_mode, + int paired_device_mode, + int owner_events, + XIEventMask *mask, + int num_modifiers, + XIGrabModifiers *modifiers_inout); + + int XIUngrabSwipeGestureBegin( Display* display, + int deviceid, + Window grab_window, + int num_modifiers, + XIGrabModifiers *modifiers); + display Specifies the connection to the X server. @@ -114,8 +146,9 @@ SYNOPSIS DESCRIPTION ----------- - XIGrabButton, XIGrabKeycode and XIGrabTouchBegin establish a passive - grab. The modifier device for a button grab is the paired master device + XIGrabButton, XIGrabKeycode, XIGrabTouchBegin, XIGrabPinchGestureBegin, + XIGrabSwipeTouchBegin establish a passive grab. + The modifier device for a button grab is the paired master device if deviceid specifies a master pointer. Otherwise, the modifier device is the device specified with deviceid. In the future, the device is actively grabbed (as for XIGrabDevice, the @@ -123,7 +156,7 @@ DESCRIPTION was pressed and the XI_ButtonPress or XI_KeyPress event is reported if all of the following conditions are true: * The device is not grabbed, and the specified button or - keycode is logically pressed or a touch event occurs when the + keycode is logically pressed, a touch or a gesture event occurs when the specified modifier keys are logically down on the modifier device and no other buttons or modifier keys are logically down. * Either the grab window is an ancestor of (or is) the focus @@ -169,16 +202,20 @@ DESCRIPTION combination. XIGrabButton and XIGrabKeycode have no effect on an active grab. - On success, XIGrabButton, XIGrabKeycode and XIGrabTouchBegin return 0; + On success, XIGrabButton, XIGrabKeycode, XIGrabTouchBegin, + XIGrabPinchGestureBegin and XIGrabSwipeGestureBegin return 0; If one or more modifier combinations could not be grabbed, - XIGrabButton, XIGrabKeycode and XIGrabTouchBegin return the number of + XIGrabButton, XIGrabKeycode, XIGrabTouchBegin, XIGrabPinchGestureBegin + and XIGrabSwipeGestureBegin return the number of failed combinations and modifiers_inout contains the failed combinations and their respective error codes. - XIGrabButton, XIGrabKeycode and XIGrabTouchBegin can generate BadClass, + XIGrabButton, XIGrabKeycode, XIGrabTouchBegin, XIGrabPinchGestureBegin + and XIGrabSwipeGestureBegin can generate BadClass, BadDevice, BadMatch, BadValue, and BadWindow errors. - XIUngrabButton, XIUngrabKeycode and XIUngrabTouchBegin release the + XIUngrabButton, XIUngrabKeycode, XIUngrabTouchBegin, XIUngrabPinchGestureBegin + and XIUngrabSwipeGestureBegin release the passive grab for a button/modifier, keycode/modifier or touch/modifier combination on the specified window if it was grabbed by this client. A modifier of XIAnyModifier is equivalent to issuing the ungrab request @@ -188,12 +225,14 @@ DESCRIPTION XIUngrabButton and XIUngrabKeycode have no effect on an active grab. - XIUngrabButton, XIUngrabKeycode and XIUngrabTouchBegin can generate + XIUngrabButton, XIUngrabKeycode, XIUngrabTouchBegin, + XIUngrabPinchGestureBegin and XIUngrabSwipeGestureBegin can generate BadDevice, BadMatch, BadValue and BadWindow errors. RETURN VALUE ------------ - XIGrabButton, XIGrabKeycode and XIGrabTouchBegin return the number of + XIGrabButton, XIGrabKeycode, XIGrabTouchBegin and + XIGrabPinchGestureBegin and XIGrabSwipeGestureBegin return the number of modifier combination that could not establish a passive grab. The modifiers are returned in modifiers_inout, along with the respective error for this modifier combination. If XIGrabButton, XIGrabKeycode @@ -209,8 +248,10 @@ DIAGNOSTICS BadMatch This error may occur if XIGrabButton specified a device that has no buttons, or XIGrabKeycode specified a device - that has no keys, or XIGrabTouchBegin specified a device - that is not touch-capable. + that has no keys, + or XIGrabTouchBegin specified a device that is not touch-capable, + or XIGrabPinchGestureBegin specified a device that is not gesture-capable, + or XIGrabSwipeGestureBegin specified a device that is not gesture-capable. BadValue Some numeric value falls outside the range of values diff --git a/man/XIQueryDevice.txt b/man/XIQueryDevice.txt index 232d735..bc9e36f 100644 --- a/man/XIQueryDevice.txt +++ b/man/XIQueryDevice.txt @@ -101,7 +101,7 @@ DESCRIPTION The type field specifies the type of the input class. Currently, the following types are defined: XIKeyClass, XIButtonClass, XIValuatorClass, XIScrollClass, - XITouchClass + XITouchClass, XIGestureClass. In the future, additional types may be added. Clients are required to ignore unknown input classes. @@ -259,6 +259,23 @@ DESCRIPTION valuators must be defined with the respective XIValuatorClass classes. A valuator may send both pointer and touch-events. + typedef struct + { + int type; + int sourceid; + int num_touches; + } XIGestureClassInfo; + + A device may have zero or one XIGestureClassInfo, denoting + touchpad gesture capability on the device. A device with a XIGestureClassInfo + may send GestureSwipeBegin, GestureSwipeUpdate, GestureSwipeEnd, + GesturePinchBegin, GesturePinchUpdate, GesturePinchEnd. + + The num_touches field defines the maximum number of simultaneous touches + the device supports. A num_touches of 0 means the maximum number of + simultaneous touches is undefined or unspecified. This field should be + used as a guide only, devices will lie about their capabilities. + XIQueryDevice can generate a BadDevice error. XIFreeDeviceInfo frees the information returned by diff --git a/src/XExtInt.c b/src/XExtInt.c index d379876..f2b5a75 100644 --- a/src/XExtInt.c +++ b/src/XExtInt.c @@ -127,6 +127,12 @@ wireToTouchOwnershipEvent(xXITouchOwnershipEvent *in, static int wireToBarrierEvent(xXIBarrierEvent *in, XGenericEventCookie *cookie); +static int +wireToPinchEvent(xXIGesturePinchEvent *in, + XGenericEventCookie *cookie); +static int +wireToSwipeEvent(xXIGestureSwipeEvent *in, + XGenericEventCookie *cookie); static /* const */ XEvent emptyevent; @@ -1035,6 +1041,28 @@ XInputWireToCookie( break; } return ENQUEUE_EVENT; + case XI_GesturePinchBegin: + case XI_GesturePinchUpdate: + case XI_GesturePinchEnd: + *cookie = *(XGenericEventCookie*)save; + if (!wireToPinchEvent((xXIGesturePinchEndEvent*)event, cookie)) + { + printf("XInputWireToCookie: CONVERSION FAILURE! evtype=%d\n", + ge->evtype); + break; + } + return ENQUEUE_EVENT; + case XI_GestureSwipeBegin: + case XI_GestureSwipeUpdate: + case XI_GestureSwipeEnd: + *cookie = *(XGenericEventCookie*)save; + if (!wireToSwipeEvent((xXIGestureSwipeEndEvent*)event, cookie)) + { + printf("XInputWireToCookie: CONVERSION FAILURE! evtype=%d\n", + ge->evtype); + break; + } + return ENQUEUE_EVENT; default: printf("XInputWireToCookie: Unknown generic event. type %d\n", ge->evtype); @@ -1065,7 +1093,7 @@ sizeDeviceEvent(int buttons_len, int valuators_len, /* Return the size with added padding so next element would be double-aligned unless the architecture is known to allow unaligned data accesses. Not doing this can cause a bus error on - MIPS N32. */ + MIPS N32. */ static int pad_to_double(int size) { @@ -1143,6 +1171,9 @@ sizeDeviceClassType(int type, int num_elements) case XITouchClass: l = pad_to_double(sizeof(XITouchClassInfo)); break; + case XIGestureClass: + l = pad_to_double(sizeof(XIGestureClassInfo)); + break; default: printf("sizeDeviceClassType: unknown type %d\n", type); break; @@ -1432,6 +1463,41 @@ copyBarrierEvent(XGenericEventCookie *in_cookie, return True; } + +static Bool +copyGesturePinchEvent(XGenericEventCookie *cookie_in, + XGenericEventCookie *cookie_out) +{ + XIGesturePinchEvent *in, *out; + + in = cookie_in->data; + + out = cookie_out->data = malloc(sizeof(XIGesturePinchEvent)); + if (!out) + return False; + + *out = *in; + + return True; +} + +static Bool +copyGestureSwipeEvent(XGenericEventCookie *cookie_in, + XGenericEventCookie *cookie_out) +{ + XIGestureSwipeEvent *in, *out; + + in = cookie_in->data; + + out = cookie_out->data = malloc(sizeof(XIGestureSwipeEvent)); + if (!out) + return False; + + *out = *in; + + return True; +} + static Bool XInputCopyCookie(Display *dpy, XGenericEventCookie *in, XGenericEventCookie *out) { @@ -1493,6 +1559,16 @@ XInputCopyCookie(Display *dpy, XGenericEventCookie *in, XGenericEventCookie *out case XI_BarrierLeave: ret = copyBarrierEvent(in, out); break; + case XI_GesturePinchBegin: + case XI_GesturePinchUpdate: + case XI_GesturePinchEnd: + ret = copyGesturePinchEvent(in, out); + break; + case XI_GestureSwipeBegin: + case XI_GestureSwipeUpdate: + case XI_GestureSwipeEnd: + ret = copyGestureSwipeEvent(in, out); + break; default: printf("XInputCopyCookie: unknown evtype %d\n", in->evtype); ret = False; @@ -1607,6 +1683,9 @@ size_classes(xXIAnyInfo* from, int nclasses) case XITouchClass: l = sizeDeviceClassType(XITouchClass, 0); break; + case XIGestureClass: + l = sizeDeviceClassType(XIGestureClass, 0); + break; } len += l; @@ -1770,6 +1849,21 @@ copy_classes(XIDeviceInfo* to, xXIAnyInfo* from, int *nclasses) to->classes[cls_idx++] = any_lib; } break; + case XIGestureClass: + { + XIGestureClassInfo *cls_lib; + xXIGestureInfo *cls_wire; + + cls_wire = (xXIGestureInfo*)any_wire; + cls_lib = next_block(&ptr_lib, sizeof(XIGestureClassInfo)); + + cls_lib->type = cls_wire->type; + cls_lib->sourceid = cls_wire->sourceid; + cls_lib->num_touches = cls_wire->num_touches; + + to->classes[cls_idx++] = any_lib; + } + break; } len += any_wire->length * 4; ptr_wire += any_wire->length * 4; @@ -2029,3 +2123,91 @@ wireToBarrierEvent(xXIBarrierEvent *in, XGenericEventCookie *cookie) return 1; } + +static int +wireToPinchEvent(xXIGesturePinchEvent *in, + XGenericEventCookie *cookie) +{ + XIGesturePinchEvent *out; + + cookie->data = out = malloc(sizeof(XIGesturePinchEvent)); + + out->display = cookie->display; + out->type = in->type; + out->serial = cookie->serial; + out->extension = in->extension; + out->evtype = in->evtype; + out->send_event = ((in->type & 0x80) != 0); + out->time = in->time; + out->deviceid = in->deviceid; + out->sourceid = in->sourceid; + out->detail = in->detail; + out->root = in->root; + out->event = in->event; + out->child = in->child; + out->root_x = FP1616toDBL(in->root_x); + out->root_y = FP1616toDBL(in->root_y); + out->event_x = FP1616toDBL(in->event_x); + out->event_y = FP1616toDBL(in->event_y); + out->delta_x = FP1616toDBL(in->delta_x); + out->delta_y = FP1616toDBL(in->delta_y); + out->delta_unaccel_x = FP1616toDBL(in->delta_unaccel_x); + out->delta_unaccel_y = FP1616toDBL(in->delta_unaccel_y); + out->scale = FP1616toDBL(in->scale); + out->delta_angle = FP1616toDBL(in->delta_angle); + out->flags = in->flags; + + out->mods.base = in->mods.base_mods; + out->mods.locked = in->mods.locked_mods; + out->mods.latched = in->mods.latched_mods; + out->mods.effective = in->mods.effective_mods; + out->group.base = in->group.base_group; + out->group.locked = in->group.locked_group; + out->group.latched = in->group.latched_group; + out->group.effective = in->group.effective_group; + + return 1; +} + +static int +wireToSwipeEvent(xXIGestureSwipeEvent *in, + XGenericEventCookie *cookie) +{ + XIGestureSwipeEvent *out; + + cookie->data = out = malloc(sizeof(XIGestureSwipeEvent)); + + out->display = cookie->display; + out->type = in->type; + out->serial = cookie->serial; + out->extension = in->extension; + out->evtype = in->evtype; + out->send_event = ((in->type & 0x80) != 0); + out->time = in->time; + out->deviceid = in->deviceid; + out->sourceid = in->sourceid; + out->detail = in->detail; + out->root = in->root; + out->event = in->event; + out->child = in->child; + out->root_x = FP1616toDBL(in->root_x); + out->root_y = FP1616toDBL(in->root_y); + out->event_x = FP1616toDBL(in->event_x); + out->event_y = FP1616toDBL(in->event_y); + out->delta_x = FP1616toDBL(in->delta_x); + out->delta_y = FP1616toDBL(in->delta_y); + out->delta_unaccel_x = FP1616toDBL(in->delta_unaccel_x); + out->delta_unaccel_y = FP1616toDBL(in->delta_unaccel_y); + out->flags = in->flags; + + out->mods.base = in->mods.base_mods; + out->mods.locked = in->mods.locked_mods; + out->mods.latched = in->mods.latched_mods; + out->mods.effective = in->mods.effective_mods; + out->group.base = in->group.base_group; + out->group.locked = in->group.locked_group; + out->group.latched = in->group.latched_group; + out->group.effective = in->group.effective_group; + + return 1; +} diff --git a/src/XIPassiveGrab.c b/src/XIPassiveGrab.c index 32b0ab3..310e523 100644 --- a/src/XIPassiveGrab.c +++ b/src/XIPassiveGrab.c @@ -177,6 +177,37 @@ XIGrabTouchBegin(Display *dpy, int deviceid, Window grab_window, num_modifiers, modifiers_inout, CurrentTime); } +int XIGrabPinchGestureBegin(Display* dpy, int deviceid, Window grab_window, int grab_mode, + int paired_device_mode, int owner_events, + XIEventMask *mask, int num_modifiers, XIGrabModifiers *modifiers_inout) +{ + XExtDisplayInfo *extinfo = XInput_find_display(dpy); + + LockDisplay(dpy); + if (_XiCheckExtInit(dpy, XInput_2_4, extinfo) == -1) + return -1; + UnlockDisplay(dpy); + + return _XIPassiveGrabDevice(dpy, deviceid, XIGrabtypeGesturePinchBegin, 0, + grab_window, None, grab_mode, paired_device_mode, + owner_events, mask, num_modifiers, modifiers_inout, CurrentTime); +} + +int XIGrabSwipeGestureBegin(Display* dpy, int deviceid, Window grab_window, int grab_mode, + int paired_device_mode, int owner_events, + XIEventMask *mask, int num_modifiers, XIGrabModifiers *modifiers_inout) +{ + XExtDisplayInfo *extinfo = XInput_find_display(dpy); + + LockDisplay(dpy); + if (_XiCheckExtInit(dpy, XInput_2_4, extinfo) == -1) + return -1; + UnlockDisplay(dpy); + + return _XIPassiveGrabDevice(dpy, deviceid, XIGrabtypeGestureSwipeBegin, 0, + grab_window, None, grab_mode, paired_device_mode, + owner_events, mask, num_modifiers, modifiers_inout, CurrentTime); +} static int _XIPassiveUngrabDevice(Display* dpy, int deviceid, int grabtype, int detail, @@ -256,3 +287,31 @@ XIUngrabTouchBegin(Display* display, int deviceid, Window grab_window, return _XIPassiveUngrabDevice(display, deviceid, XIGrabtypeTouchBegin, 0, grab_window, num_modifiers, modifiers); } + +int XIUngrabPinchGestureBegin(Display* display, int deviceid, Window grab_window, + int num_modifiers, XIGrabModifiers *modifiers) +{ + XExtDisplayInfo *extinfo = XInput_find_display(display); + + LockDisplay(display); + if (_XiCheckExtInit(display, XInput_2_4, extinfo) == -1) + return -1; + UnlockDisplay(display); + + return _XIPassiveUngrabDevice(display, deviceid, XIGrabtypeGesturePinchBegin, 0, + grab_window, num_modifiers, modifiers); +} + +int XIUngrabSwipeGestureBegin(Display* display, int deviceid, Window grab_window, + int num_modifiers, XIGrabModifiers *modifiers) +{ + XExtDisplayInfo *extinfo = XInput_find_display(display); + + LockDisplay(display); + if (_XiCheckExtInit(display, XInput_2_4, extinfo) == -1) + return -1; + UnlockDisplay(display); + + return _XIPassiveUngrabDevice(display, deviceid, XIGrabtypeGestureSwipeBegin, 0, + grab_window, num_modifiers, modifiers); +} diff --git a/src/XIint.h b/src/XIint.h index 9479a79..40dec0b 100644 --- a/src/XIint.h +++ b/src/XIint.h @@ -23,6 +23,7 @@ #define XInput_2_1 8 #define XInput_2_2 9 #define XInput_2_3 10 +#define XInput_2_4 11 extern XExtDisplayInfo *XInput_find_display(Display *); -- cgit v1.2.1