From 3304bbff9b4ed63f1a47410a5320a136420ba2c6 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 15 Feb 2011 18:49:58 +0000 Subject: Input: Add smooth-scrolling support to GetPointerEvents For scroll wheel support, we used to send buttons 4/5 and 6/7 for horizontal/vertical positive/negative scroll events. For touchpads, we really want more fine-grained scroll values. GetPointerEvents now accepts both old-school scroll button presses, and new-style scroll axis events, while emitting both types of events to support both old and new clients. This works with the new XIScrollClass to mark axes as scrolling axes. Drivers mark any valuators that send scroll events with SetScrollValuator. (Currently missing: the XIDeviceChangeEvent being sent when a driver changes a scroll axis at run-time. This can be added later.) Note: the SCROLL_TYPE enums are intentionally different values to the XI2 proto values to avoid copy/overlapping range bugs. Co-authored-by: Daniel Stone Signed-off-by: Peter Hutterer Reviewed-by: Peter Hutterer Reviewed-by: Daniel Stone --- Xi/exevents.c | 49 +++++++++++ Xi/xiquerydevice.c | 73 +++++++++++++++- Xi/xiquerydevice.h | 1 + dix/devices.c | 12 +++ dix/getevents.c | 170 +++++++++++++++++++++++++++++++++++++- include/exevents.h | 23 ++++++ include/inputstr.h | 20 +++++ test/input.c | 57 +++++++++++++ test/xi2/protocol-common.c | 63 +++++++++++++- test/xi2/protocol-xiquerydevice.c | 49 +++++++++-- 10 files changed, 506 insertions(+), 11 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index a6455e6ac..74a78ecf2 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1091,6 +1091,55 @@ InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, int if (mode & OutOfProximity) dev->proximity->in_proximity = FALSE; + return SetScrollValuator(dev, axnum, SCROLL_TYPE_NONE, 0, SCROLL_FLAG_NONE); +} + +/** + * Set the given axis number as a scrolling valuator. + */ +Bool +SetScrollValuator(DeviceIntPtr dev, int axnum, enum ScrollType type, double increment, int flags) +{ + AxisInfoPtr ax; + int *current_ax; + + if (!dev || !dev->valuator || axnum >= dev->valuator->numAxes) + return FALSE; + + switch (type) + { + case SCROLL_TYPE_VERTICAL: + current_ax = &dev->valuator->v_scroll_axis; + break; + case SCROLL_TYPE_HORIZONTAL: + current_ax = &dev->valuator->h_scroll_axis; + break; + case SCROLL_TYPE_NONE: + ax = &dev->valuator->axes[axnum]; + ax->scroll.type = type; + return TRUE; + default: + return FALSE; + } + + if (increment == 0.0) + return FALSE; + + if (*current_ax != -1 && axnum != *current_ax) + { + ax = &dev->valuator->axes[*current_ax]; + if (ax->scroll.type == type && + (flags & SCROLL_FLAG_PREFERRED) && (ax->scroll.flags & SCROLL_FLAG_PREFERRED)) + return FALSE; + } + *current_ax = axnum; + + ax = &dev->valuator->axes[axnum]; + ax->scroll.type = type; + ax->scroll.increment = increment; + ax->scroll.flags = flags; + /* FIXME: generate DeviceChanged Events */ + return TRUE; } diff --git a/Xi/xiquerydevice.c b/Xi/xiquerydevice.c index 902eb918c..9961d1b6f 100644 --- a/Xi/xiquerydevice.c +++ b/Xi/xiquerydevice.c @@ -229,7 +229,16 @@ SizeDeviceClasses(DeviceIntPtr dev) } if (dev->valuator) - len += sizeof(xXIValuatorInfo) * dev->valuator->numAxes; + { + int i; + len += (sizeof(xXIValuatorInfo)) * dev->valuator->numAxes; + + for (i = 0; i < dev->valuator->numAxes; i++) { + if (dev->valuator->axes[i].scroll.type != SCROLL_TYPE_NONE) + len += sizeof(xXIScrollInfo); + } + } + return len; } @@ -369,6 +378,56 @@ SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info) swaps(&info->sourceid); } +int +ListScrollInfo(DeviceIntPtr dev, xXIScrollInfo *info, int axisnumber) +{ + ValuatorClassPtr v = dev->valuator; + AxisInfoPtr axis = &v->axes[axisnumber]; + + if (axis->scroll.type == SCROLL_TYPE_NONE) + return 0; + + info->type = XIScrollClass; + info->length = sizeof(xXIScrollInfo)/4; + info->number = axisnumber; + switch(axis->scroll.type) + { + case SCROLL_TYPE_VERTICAL: + info->scroll_type = XIScrollTypeVertical; + break; + case SCROLL_TYPE_HORIZONTAL: + info->scroll_type = XIScrollTypeHorizontal; + break; + default: + ErrorF("[Xi] Unknown scroll type %d. This is a bug.\n", axis->scroll.type); + break; + } + info->increment.integral = (int)axis->scroll.increment; + info->increment.frac = (unsigned int)(axis->scroll.increment * (1UL << 16) * (1UL << 16)); + info->sourceid = v->sourceid; + + info->flags = 0; + + if (axis->scroll.flags & SCROLL_FLAG_DONT_EMULATE) + info->flags |= XIScrollFlagNoEmulation; + if (axis->scroll.flags & SCROLL_FLAG_PREFERRED) + info->flags |= XIScrollFlagPreferred; + + return info->length * 4; +} + +static void +SwapScrollInfo(DeviceIntPtr dev, xXIScrollInfo* info) +{ + swaps(&info->type); + swaps(&info->length); + swaps(&info->number); + swaps(&info->sourceid); + swaps(&info->scroll_type); + swapl(&info->increment.integral); + swapl(&info->increment.frac); +} + int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment) { DeviceIntPtr master = GetMaster(dev, MASTER_ATTACHED); @@ -458,6 +517,15 @@ ListDeviceClasses(ClientPtr client, DeviceIntPtr dev, total_len += len; } + for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) + { + len = ListScrollInfo(dev, (xXIScrollInfo*)any, i); + if (len) + (*nclasses)++; + any += len; + total_len += len; + } + return total_len; } @@ -484,6 +552,9 @@ SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info) case XIValuatorClass: SwapValuatorInfo(dev, (xXIValuatorInfo*)any); break; + case XIScrollClass: + SwapScrollInfo(dev, (xXIScrollInfo*)any); + break; } any += len * 4; diff --git a/Xi/xiquerydevice.h b/Xi/xiquerydevice.h index 02f06591e..9db6aa293 100644 --- a/Xi/xiquerydevice.h +++ b/Xi/xiquerydevice.h @@ -44,4 +44,5 @@ int ListButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info, Bool reportState); int ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info); int ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info, int axisnumber, Bool reportState); +int ListScrollInfo(DeviceIntPtr dev, xXIScrollInfo* info, int axisnumber); #endif /* QUERYDEV_H */ diff --git a/dix/devices.c b/dix/devices.c index ab8a648a9..64557aaf1 100644 --- a/dix/devices.c +++ b/dix/devices.c @@ -260,6 +260,8 @@ AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart) offsetof(DeviceIntRec, devPrivates), PRIVATE_DEVICE); if (!dev) return (DeviceIntPtr)NULL; + + dev->last.scroll = NULL; dev->id = devid; dev->public.processInputProc = ProcessOtherEvent; dev->public.realInputProc = ProcessOtherEvent; @@ -939,6 +941,7 @@ CloseDevice(DeviceIntPtr dev) free(dev->deviceGrab.sync.event); free(dev->config_info); /* Allocated in xf86ActivateDevice. */ + free(dev->last.scroll); dev->config_info = NULL; dixFreeObjectWithPrivates(dev, PRIVATE_DEVICE); } @@ -1277,10 +1280,19 @@ InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels, if (!valc) return FALSE; + dev->last.scroll = valuator_mask_new(numAxes); + if (!dev->last.scroll) + { + free(valc); + return FALSE; + } + valc->sourceid = dev->id; valc->motion = NULL; valc->first_motion = 0; valc->last_motion = 0; + valc->h_scroll_axis = -1; + valc->v_scroll_axis = -1; valc->numMotionEvents = numMotionEvents; valc->motionHintWindow = NullWindow; diff --git a/dix/getevents.c b/dix/getevents.c index 45243df5c..c42971592 100644 --- a/dix/getevents.c +++ b/dix/getevents.c @@ -2,6 +2,7 @@ * Copyright © 2006 Nokia Corporation * Copyright © 2006-2007 Daniel Stone * Copyright © 2008 Red Hat, Inc. + * Copyright © 2011 The Chromium Authors * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -603,8 +604,10 @@ GetMaximumEventsNum(void) { /* One raw event * One device event * One possible device changed event + * Lots of possible separate button scroll events (horiz + vert) + * Lots of possible separate raw button scroll events (horiz + vert) */ - return 3; + return 100; } @@ -1170,6 +1173,95 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type, return num_events; } +/** + * Generate events for each scroll axis that changed between before/after + * for the device. + * + * @param events The pointer to the event list to fill the events + * @param dev The device to generate the events for + * @param axis The axis number to generate events for + * @param mask State before this event in absolute coords + * @param[in,out] last Last scroll state posted in absolute coords (modified + * in-place) + * @param ms Current time in ms + * @param max_events Max number of events to be generated + * @return The number of events generated + */ +static int +emulate_scroll_button_events(InternalEvent *events, + DeviceIntPtr dev, + int axis, + const ValuatorMask *mask, + ValuatorMask *last, + CARD32 ms, + int max_events) +{ + AxisInfoPtr ax; + double delta; + double incr; + int num_events = 0; + double total; + int b; + + if (dev->valuator->axes[axis].scroll.type == SCROLL_TYPE_NONE) + return 0; + + if (!valuator_mask_isset(mask, axis)) + return 0; + + ax = &dev->valuator->axes[axis]; + incr = ax->scroll.increment; + + if (!valuator_mask_isset(last, axis)) + valuator_mask_set_double(last, axis, 0); + + delta = valuator_mask_get_double(mask, axis) - valuator_mask_get_double(last, axis); + total = delta; + b = (ax->scroll.type == SCROLL_TYPE_VERTICAL) ? 5 : 7; + + if ((incr > 0 && delta < 0) || + (incr < 0 && delta > 0)) + b--; /* we're scrolling up or left → button 4 or 6 */ + + while (fabs(delta) >= fabs(incr)) + { + int nev_tmp; + + if (delta > 0) + delta -= fabs(incr); + else if (delta < 0) + delta += fabs(incr); + + /* fill_pointer_events() generates four events: one normal and one raw + * event for button press and button release. + * We may get a bigger scroll delta than we can generate events + * for. In that case, we keep decreasing delta, but skip events. + */ + if (num_events + 4 < max_events) + { + nev_tmp = fill_pointer_events(events, dev, ButtonPress, b, ms, + POINTER_EMULATED, NULL); + events += nev_tmp; + num_events += nev_tmp; + nev_tmp = fill_pointer_events(events, dev, ButtonRelease, b, ms, + POINTER_EMULATED, NULL); + events += nev_tmp; + num_events += nev_tmp; + } + } + + /* We emulated, update last.scroll */ + if (total != delta) + { + total -= delta; + valuator_mask_set_double(last, axis, + valuator_mask_get_double(last, axis) + total); + } + + return num_events; +} + + /** * Generate a complete series of InternalEvents (filled into the EventList) * representing pointer motion, or button presses. If the device is a slave @@ -1193,7 +1285,12 @@ GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type, int buttons, int flags, const ValuatorMask *mask_in) { CARD32 ms = GetTimeInMillis(); - int num_events = 0; + int num_events = 0, nev_tmp; + int h_scroll_axis = pDev->valuator->h_scroll_axis; + int v_scroll_axis = pDev->valuator->v_scroll_axis; + ValuatorMask mask; + ValuatorMask scroll; + int i; /* refuse events from disabled devices */ if (!pDev->enabled) @@ -1204,8 +1301,73 @@ GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type, events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events); - num_events += fill_pointer_events(events, pDev, type, buttons, ms, flags, - mask_in); + + valuator_mask_copy(&mask, mask_in); + + /* Turn a scroll button press into a smooth-scrolling event if + * necessary. This only needs to cater for the XIScrollFlagPreferred + * axis (if more than one scrolling axis is present) */ + if (type == ButtonPress) + { + double val, adj; + int axis; + + switch (buttons) { + case 4: + adj = 1.0; + axis = v_scroll_axis; + break; + case 5: + adj = -1.0; + axis = v_scroll_axis; + break; + case 6: + adj = 1.0; + axis = h_scroll_axis; + break; + case 7: + adj = -1.0; + axis = h_scroll_axis; + break; + default: + adj = 0.0; + axis = -1; + break; + } + + if (adj != 0.0 && axis != -1) + { + adj *= pDev->valuator->axes[axis].scroll.increment; + val = valuator_mask_get_double(&mask, axis) + adj; + valuator_mask_set_double(&mask, axis, val); + type = MotionNotify; + buttons = 0; + } + } + + /* First fill out the original event set, with smooth-scrolling axes. */ + nev_tmp = fill_pointer_events(events, pDev, type, buttons, ms, flags, + &mask); + events += nev_tmp; + num_events += nev_tmp; + + valuator_mask_zero(&scroll); + + /* Now turn the smooth-scrolling axes back into emulated button presses + * for legacy clients, based on the integer delta between before and now */ + for (i = 0; i < valuator_mask_size(&mask); i++) { + if (!valuator_mask_isset(&mask, i)) + continue; + + valuator_mask_set_double(&scroll, i, pDev->last.valuators[i]); + + nev_tmp = emulate_scroll_button_events(events, pDev, i, &scroll, + pDev->last.scroll, ms, + GetMaximumEventsNum() - num_events); + events += nev_tmp; + num_events += nev_tmp; + } + return num_events; } diff --git a/include/exevents.h b/include/exevents.h index 731f31eac..4fe6c61a9 100644 --- a/include/exevents.h +++ b/include/exevents.h @@ -37,6 +37,22 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * Interface available to drivers * ***************************************************************/ +/** + * Scroll flags for ::SetScrollValuator. + */ +enum ScrollFlags { + SCROLL_FLAG_NONE = 0, + /** + * Do not emulate legacy button events for valuator events on this axis. + */ + SCROLL_FLAG_DONT_EMULATE = (1 << 1), + /** + * This axis is the preferred axis for valuator emulation for this axis' + * scroll type. + */ + SCROLL_FLAG_PREFERRED = (1 << 2) +}; + extern _X_EXPORT int InitProximityClassDeviceStruct( DeviceIntPtr /* dev */); @@ -51,6 +67,13 @@ extern _X_EXPORT Bool InitValuatorAxisStruct( int /* max_res */, int /* mode */); +extern _X_EXPORT Bool SetScrollValuator( + DeviceIntPtr /* dev */, + int /* axnum */, + enum ScrollType /* type */, + double /* increment */, + int /* flags */); + /* Input device properties */ extern _X_EXPORT void XIDeleteAllDeviceProperties( DeviceIntPtr /* device */ diff --git a/include/inputstr.h b/include/inputstr.h index c25f5c670..9d4108ef5 100644 --- a/include/inputstr.h +++ b/include/inputstr.h @@ -74,6 +74,16 @@ extern _X_EXPORT int CountBits(const uint8_t *mask, int len); #define XI2LASTEVENT 17 /* XI_RawMotion */ #define XI2MASKSIZE ((XI2LASTEVENT + 7)/8) /* no of bits for masks */ +/** + * Scroll types for ::SetScrollValuator and the scroll type in the + * ::ScrollInfoPtr. + */ +enum ScrollType { + SCROLL_TYPE_NONE = 0, /**< Not a scrolling valuator */ + SCROLL_TYPE_VERTICAL = 8, + SCROLL_TYPE_HORIZONTAL = 9, +}; + /** * This struct stores the core event mask for each client except the client * that created the window. @@ -252,6 +262,12 @@ typedef struct _KeyClassRec { struct _XkbSrvInfo *xkbInfo; } KeyClassRec, *KeyClassPtr; +typedef struct _ScrollInfo { + enum ScrollType type; + double increment; + int flags; +} ScrollInfo, *ScrollInfoPtr; + typedef struct _AxisInfo { int resolution; int min_resolution; @@ -260,6 +276,7 @@ typedef struct _AxisInfo { int max_value; Atom label; CARD8 mode; + ScrollInfo scroll; } AxisInfo, *AxisInfoPtr; typedef struct _ValuatorAccelerationRec { @@ -283,6 +300,8 @@ typedef struct _ValuatorClassRec { unsigned short numAxes; double *axisVal; /* always absolute, but device-coord system */ ValuatorAccelerationRec accelScheme; + int h_scroll_axis; /* horiz smooth-scrolling axis */ + int v_scroll_axis; /* vert smooth-scrolling axis */ } ValuatorClassRec; typedef struct _ButtonClassRec { @@ -524,6 +543,7 @@ typedef struct _DeviceIntRec { double valuators[MAX_VALUATORS]; int numValuators; DeviceIntPtr slave; + ValuatorMask *scroll; } last; /* Input device property handling. */ diff --git a/test/input.c b/test/input.c index 2501d59b7..afc4d4d99 100644 --- a/test/input.c +++ b/test/input.c @@ -52,6 +52,7 @@ static void dix_init_valuators(void) { DeviceIntRec dev; ValuatorClassPtr val; + AxisInfoPtr axis; const int num_axes = 2; int i; Atom atoms[MAX_VALUATORS] = { 0 }; @@ -78,6 +79,62 @@ static void dix_init_valuators(void) } assert(dev.last.numValuators == num_axes); + + /* invalid increment */ + assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_VERTICAL, 0.0, SCROLL_FLAG_NONE) == FALSE); + /* invalid type */ + assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_VERTICAL - 1, 1.0, SCROLL_FLAG_NONE) == FALSE); + assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_HORIZONTAL + 1, 1.0, SCROLL_FLAG_NONE) == FALSE); + /* invalid axisnum */ + assert(SetScrollValuator(&dev, 2, SCROLL_TYPE_HORIZONTAL, 1.0, SCROLL_FLAG_NONE) == FALSE); + + /* valid */ + assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_VERTICAL, 3.0, SCROLL_FLAG_NONE) == TRUE); + axis = &dev.valuator->axes[0]; + assert(axis->scroll.increment == 3.0); + assert(axis->scroll.type == SCROLL_TYPE_VERTICAL); + assert(axis->scroll.flags == 0); + + /* valid */ + assert(SetScrollValuator(&dev, 1, SCROLL_TYPE_HORIZONTAL, 2.0, SCROLL_FLAG_NONE) == TRUE); + axis = &dev.valuator->axes[1]; + assert(axis->scroll.increment == 2.0); + assert(axis->scroll.type == SCROLL_TYPE_HORIZONTAL); + assert(axis->scroll.flags == 0); + + /* can add another non-preffered axis */ + assert(SetScrollValuator(&dev, 1, SCROLL_TYPE_VERTICAL, 5.0, SCROLL_FLAG_NONE) == TRUE); + assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_HORIZONTAL, 5.0, SCROLL_FLAG_NONE) == TRUE); + + /* can overwrite with Preferred */ + assert(SetScrollValuator(&dev, 1, SCROLL_TYPE_VERTICAL, 5.5, SCROLL_FLAG_PREFERRED) == TRUE); + axis = &dev.valuator->axes[1]; + assert(axis->scroll.increment == 5.5); + assert(axis->scroll.type == SCROLL_TYPE_VERTICAL); + assert(axis->scroll.flags == SCROLL_FLAG_PREFERRED); + + assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_HORIZONTAL, 8.8, SCROLL_FLAG_PREFERRED) == TRUE); + axis = &dev.valuator->axes[0]; + assert(axis->scroll.increment == 8.8); + assert(axis->scroll.type == SCROLL_TYPE_HORIZONTAL); + assert(axis->scroll.flags == SCROLL_FLAG_PREFERRED); + + /* can overwrite as none */ + assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_NONE, 5.0, + SCROLL_FLAG_NONE) == TRUE); + axis = &dev.valuator->axes[0]; + assert(axis->scroll.type == SCROLL_TYPE_NONE); + + /* can overwrite axis with new settings */ + assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_VERTICAL, 5.0, SCROLL_FLAG_NONE) == TRUE); + axis = &dev.valuator->axes[0]; + assert(axis->scroll.type == SCROLL_TYPE_VERTICAL); + assert(axis->scroll.increment == 5.0); + assert(axis->scroll.flags == SCROLL_FLAG_NONE); + assert(SetScrollValuator(&dev, 0, SCROLL_TYPE_VERTICAL, 3.0, SCROLL_FLAG_NONE) == TRUE); + assert(axis->scroll.type == SCROLL_TYPE_VERTICAL); + assert(axis->scroll.increment == 3.0); + assert(axis->scroll.flags == SCROLL_FLAG_NONE); } /* just check the known success cases, and that error cases set the client's diff --git a/test/xi2/protocol-common.c b/test/xi2/protocol-common.c index 423453358..56d6bd268 100644 --- a/test/xi2/protocol-common.c +++ b/test/xi2/protocol-common.c @@ -29,6 +29,8 @@ #include "extinit.h" /* for XInputExtensionInit */ #include "exglobals.h" #include "xkbsrv.h" /* for XkbInitPrivates */ +#include "xserver-properties.h" +#include #include "protocol-common.h" @@ -63,6 +65,65 @@ static void fake_init_sprite(DeviceIntPtr dev) sprite->physLimits.y2 = screen.height; } +/* This is essentially CorePointerProc with ScrollAxes added */ +static int +TestPointerProc(DeviceIntPtr pDev, int what) +{ +#define NBUTTONS 10 +#define NAXES 4 + BYTE map[NBUTTONS + 1]; + int i = 0; + Atom btn_labels[NBUTTONS] = {0}; + Atom axes_labels[NAXES] = {0}; + + switch (what) { + case DEVICE_INIT: + for (i = 1; i <= NBUTTONS; i++) + map[i] = i; + + btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); + btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); + btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); + btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); + btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); + btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); + btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); + /* don't know about the rest */ + + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_VSCROLL); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_HSCROLL); + + if (!InitPointerDeviceStruct((DevicePtr)pDev, map, NBUTTONS, btn_labels, + (PtrCtrlProcPtr)NoopDDA, + GetMotionHistorySize(), NAXES, axes_labels)) + { + ErrorF("Could not initialize device '%s'. Out of memory.\n", + pDev->name); + return BadAlloc; + } + pDev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2; + pDev->last.valuators[0] = pDev->valuator->axisVal[0]; + pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2; + pDev->last.valuators[1] = pDev->valuator->axisVal[1]; + + SetScrollValuator(pDev, 2, SCROLL_TYPE_VERTICAL, 2.4, SCROLL_FLAG_NONE); + SetScrollValuator(pDev, 3, SCROLL_TYPE_HORIZONTAL, 3.5, SCROLL_FLAG_PREFERRED); + break; + + case DEVICE_CLOSE: + break; + + default: + break; + } + + return Success; + +#undef NBUTTONS +#undef NAXES +} /** * Create and init 2 master devices (VCP + VCK) and two slave devices, one * default mouse, one default keyboard. @@ -84,7 +145,7 @@ struct devices init_devices(void) EnableDevice(devices.vck, FALSE); AllocDevicePair(&client, "", &devices.mouse, &devices.kbd, - CorePointerProc, CoreKeyboardProc, FALSE); + TestPointerProc, CoreKeyboardProc, FALSE); ActivateDevice(devices.mouse, FALSE); ActivateDevice(devices.kbd, FALSE); EnableDevice(devices.mouse, FALSE); diff --git a/test/xi2/protocol-xiquerydevice.c b/test/xi2/protocol-xiquerydevice.c index 47eb5b14c..63d725f28 100644 --- a/test/xi2/protocol-xiquerydevice.c +++ b/test/xi2/protocol-xiquerydevice.c @@ -127,7 +127,7 @@ static void reply_XIQueryDevice_data(ClientPtr client, int len, char *data, void dev = devices.mouse; assert(info->use == XISlavePointer); assert(info->attachment == devices.vcp->id); - assert(info->num_classes == 3); /* 2 axes + button */ + assert(info->num_classes == 7); /* 4 axes + button + 2 scroll*/ break; case 5: /* keyboard */ dev = devices.kbd; @@ -183,11 +183,48 @@ static void reply_XIQueryDevice_data(ClientPtr client, int len, char *data, void } break; } - case 2: /* VCP and mouse have the same properties */ case 4: { assert(any->type == XIButtonClass || - any->type == XIValuatorClass); + any->type == XIValuatorClass || + any->type == XIScrollClass); + + if (any->type == XIScrollClass) + { + xXIScrollInfo *si = (xXIScrollInfo*)any; + + if (client->swapped) + { + swaps(&si->number); + swaps(&si->scroll_type); + swapl(&si->increment.integral); + swapl(&si->increment.frac); + } + assert(si->length == 6); + assert(si->number == 2 || si->number == 3); + if (si->number == 2) { + assert(si->scroll_type == XIScrollTypeVertical); + assert(!si->flags); + } + if (si->number == 3) { + assert(si->scroll_type == XIScrollTypeHorizontal); + assert(si->flags & XIScrollFlagPreferred); + assert(!(si->flags & ~XIScrollFlagPreferred)); + } + + assert(si->increment.integral == si->number); + /* FIXME: frac testing with float/FP issues? */ + assert(si->increment.frac > 0.3 * (1UL << 32)); + assert(si->increment.frac < 0.6 * (1UL << 32)); + } + + } + /* fall through */ + case 2: /* VCP and mouse have the same properties except for scroll */ + { + if (info->deviceid == 2 ) /* VCP */ + assert(any->type == XIButtonClass || + any->type == XIValuatorClass); if (any->type == XIButtonClass) { @@ -217,8 +254,10 @@ static void reply_XIQueryDevice_data(ClientPtr client, int len, char *data, void } assert(vi->length == 11); - assert(vi->number == 0 || - vi->number == 1); + assert(vi->number >= 0 && vi->number < 4); + if (info->deviceid == 2) /* VCP */ + assert(vi->number < 2); + assert(vi->mode == XIModeRelative); /* device was set up as relative, so standard * values here. */ -- cgit v1.2.3