2298 lines
		
	
	
		
			73 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			2298 lines
		
	
	
		
			73 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * 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"),
 | |
|  * to deal in the Software without restriction, including without limitation
 | |
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | |
|  * and/or sell copies of the Software, and to permit persons to whom the
 | |
|  * Software is furnished to do so, subject to the following conditions:
 | |
|  *
 | |
|  * The above copyright notice and this permission notice (including the next
 | |
|  * paragraph) shall be included in all copies or substantial portions of the
 | |
|  * Software.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | |
|  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | |
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | |
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | |
|  * DEALINGS IN THE SOFTWARE.
 | |
|  *
 | |
|  * Authors: Daniel Stone <daniel@fooishbar.org>
 | |
|  *          Peter Hutterer <peter.hutterer@who-t.net>
 | |
|  */
 | |
| 
 | |
| #ifdef HAVE_DIX_CONFIG_H
 | |
| #include <dix-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <X11/X.h>
 | |
| #include <X11/keysym.h>
 | |
| #include <X11/Xproto.h>
 | |
| #include <math.h>
 | |
| #include <limits.h>
 | |
| 
 | |
| #include "misc.h"
 | |
| #include "resource.h"
 | |
| #include "inputstr.h"
 | |
| #include "scrnintstr.h"
 | |
| #include "cursorstr.h"
 | |
| #include "dixstruct.h"
 | |
| #include "globals.h"
 | |
| #include "dixevents.h"
 | |
| #include "mipointer.h"
 | |
| #include "eventstr.h"
 | |
| #include "eventconvert.h"
 | |
| #include "inpututils.h"
 | |
| #include "mi.h"
 | |
| #include "windowstr.h"
 | |
| 
 | |
| #include <X11/extensions/XKBproto.h>
 | |
| #include "xkbsrv.h"
 | |
| 
 | |
| #ifdef PANORAMIX
 | |
| #include "panoramiX.h"
 | |
| #include "panoramiXsrv.h"
 | |
| #endif
 | |
| 
 | |
| #include <X11/extensions/XI.h>
 | |
| #include <X11/extensions/XI2.h>
 | |
| #include <X11/extensions/XIproto.h>
 | |
| #include <pixman.h>
 | |
| #include "exglobals.h"
 | |
| #include "exevents.h"
 | |
| #include "extnsionst.h"
 | |
| #include "listdev.h"            /* for sizing up DeviceClassesChangedEvent */
 | |
| #include "probes.h"
 | |
| 
 | |
| /* Number of motion history events to store. */
 | |
| #define MOTION_HISTORY_SIZE 256
 | |
| 
 | |
| /**
 | |
|  * InputEventList is the storage for input events generated by
 | |
|  * QueuePointerEvents, QueueKeyboardEvents, and QueueProximityEvents.
 | |
|  * This list is allocated on startup by the DIX.
 | |
|  */
 | |
| InternalEvent *InputEventList = NULL;
 | |
| 
 | |
| /**
 | |
|  * Pick some arbitrary size for Xi motion history.
 | |
|  */
 | |
| int
 | |
| GetMotionHistorySize(void)
 | |
| {
 | |
|     return MOTION_HISTORY_SIZE;
 | |
| }
 | |
| 
 | |
| void
 | |
| set_button_down(DeviceIntPtr pDev, int button, int type)
 | |
| {
 | |
|     if (type == BUTTON_PROCESSED)
 | |
|         SetBit(pDev->button->down, button);
 | |
|     else
 | |
|         SetBit(pDev->button->postdown, button);
 | |
| }
 | |
| 
 | |
| void
 | |
| set_button_up(DeviceIntPtr pDev, int button, int type)
 | |
| {
 | |
|     if (type == BUTTON_PROCESSED)
 | |
|         ClearBit(pDev->button->down, button);
 | |
|     else
 | |
|         ClearBit(pDev->button->postdown, button);
 | |
| }
 | |
| 
 | |
| Bool
 | |
| button_is_down(DeviceIntPtr pDev, int button, int type)
 | |
| {
 | |
|     Bool ret = FALSE;
 | |
| 
 | |
|     if (type & BUTTON_PROCESSED)
 | |
|         ret = ret || BitIsOn(pDev->button->down, button);
 | |
|     if (type & BUTTON_POSTED)
 | |
|         ret = ret || BitIsOn(pDev->button->postdown, button);
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| void
 | |
| set_key_down(DeviceIntPtr pDev, int key_code, int type)
 | |
| {
 | |
|     if (type == KEY_PROCESSED)
 | |
|         SetBit(pDev->key->down, key_code);
 | |
|     else
 | |
|         SetBit(pDev->key->postdown, key_code);
 | |
| }
 | |
| 
 | |
| void
 | |
| set_key_up(DeviceIntPtr pDev, int key_code, int type)
 | |
| {
 | |
|     if (type == KEY_PROCESSED)
 | |
|         ClearBit(pDev->key->down, key_code);
 | |
|     else
 | |
|         ClearBit(pDev->key->postdown, key_code);
 | |
| }
 | |
| 
 | |
| Bool
 | |
| key_is_down(DeviceIntPtr pDev, int key_code, int type)
 | |
| {
 | |
|     Bool ret = FALSE;
 | |
| 
 | |
|     if (type & KEY_PROCESSED)
 | |
|         ret = ret || BitIsOn(pDev->key->down, key_code);
 | |
|     if (type & KEY_POSTED)
 | |
|         ret = ret || BitIsOn(pDev->key->postdown, key_code);
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| key_autorepeats(DeviceIntPtr pDev, int key_code)
 | |
| {
 | |
|     return ! !(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3] &
 | |
|                (1 << (key_code & 7)));
 | |
| }
 | |
| 
 | |
| static void
 | |
| init_touch_ownership(DeviceIntPtr dev, TouchOwnershipEvent *event, Time ms)
 | |
| {
 | |
|     memset(event, 0, sizeof(TouchOwnershipEvent));
 | |
|     event->header = ET_Internal;
 | |
|     event->type = ET_TouchOwnership;
 | |
|     event->length = sizeof(TouchOwnershipEvent);
 | |
|     event->time = ms;
 | |
|     event->deviceid = dev->id;
 | |
| }
 | |
| 
 | |
| static void
 | |
| init_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail)
 | |
| {
 | |
|     memset(event, 0, sizeof(RawDeviceEvent));
 | |
|     event->header = ET_Internal;
 | |
|     event->length = sizeof(RawDeviceEvent);
 | |
|     switch (type) {
 | |
|     case MotionNotify:
 | |
|         event->type = ET_RawMotion;
 | |
|         break;
 | |
|     case ButtonPress:
 | |
|         event->type = ET_RawButtonPress;
 | |
|         break;
 | |
|     case ButtonRelease:
 | |
|         event->type = ET_RawButtonRelease;
 | |
|         break;
 | |
|     case KeyPress:
 | |
|         event->type = ET_RawKeyPress;
 | |
|         break;
 | |
|     case KeyRelease:
 | |
|         event->type = ET_RawKeyRelease;
 | |
|         break;
 | |
|     case XI_TouchBegin:
 | |
|         event->type = ET_RawTouchBegin;
 | |
|         break;
 | |
|     case XI_TouchUpdate:
 | |
|         event->type = ET_RawTouchUpdate;
 | |
|         break;
 | |
|     case XI_TouchEnd:
 | |
|         event->type = ET_RawTouchEnd;
 | |
|         break;
 | |
|     }
 | |
|     event->time = ms;
 | |
|     event->deviceid = dev->id;
 | |
|     event->sourceid = dev->id;
 | |
|     event->detail.button = detail;
 | |
| }
 | |
| 
 | |
| static void
 | |
| set_raw_valuators(RawDeviceEvent *event, ValuatorMask *mask,
 | |
|                   BOOL use_unaccel, double *data)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     use_unaccel = use_unaccel && valuator_mask_has_unaccelerated(mask);
 | |
| 
 | |
|     for (i = 0; i < valuator_mask_size(mask); i++) {
 | |
|         if (valuator_mask_isset(mask, i)) {
 | |
|             double v;
 | |
| 
 | |
|             SetBit(event->valuators.mask, i);
 | |
| 
 | |
|             if (use_unaccel)
 | |
|                 v = valuator_mask_get_unaccelerated(mask, i);
 | |
|             else
 | |
|                 v = valuator_mask_get_double(mask, i);
 | |
| 
 | |
|             data[i] = v;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| set_valuators(DeviceIntPtr dev, DeviceEvent *event, ValuatorMask *mask)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     /* Set the data to the previous value for unset absolute axes. The values
 | |
|      * may be used when sent as part of an XI 1.x valuator event. */
 | |
|     for (i = 0; i < valuator_mask_size(mask); i++) {
 | |
|         if (valuator_mask_isset(mask, i)) {
 | |
|             SetBit(event->valuators.mask, i);
 | |
|             if (valuator_get_mode(dev, i) == Absolute)
 | |
|                 SetBit(event->valuators.mode, i);
 | |
|             event->valuators.data[i] = valuator_mask_get_double(mask, i);
 | |
|         }
 | |
|         else
 | |
|             event->valuators.data[i] = dev->valuator->axisVal[i];
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| CreateClassesChangedEvent(InternalEvent *event,
 | |
|                           DeviceIntPtr master, DeviceIntPtr slave, int flags)
 | |
| {
 | |
|     int i;
 | |
|     DeviceChangedEvent *dce;
 | |
|     CARD32 ms = GetTimeInMillis();
 | |
| 
 | |
|     dce = &event->changed_event;
 | |
|     memset(dce, 0, sizeof(DeviceChangedEvent));
 | |
|     dce->deviceid = slave->id;
 | |
|     dce->masterid = master ? master->id : 0;
 | |
|     dce->header = ET_Internal;
 | |
|     dce->length = sizeof(DeviceChangedEvent);
 | |
|     dce->type = ET_DeviceChanged;
 | |
|     dce->time = ms;
 | |
|     dce->flags = flags;
 | |
|     dce->sourceid = slave->id;
 | |
| 
 | |
|     if (slave->button) {
 | |
|         dce->buttons.num_buttons = slave->button->numButtons;
 | |
|         for (i = 0; i < dce->buttons.num_buttons; i++)
 | |
|             dce->buttons.names[i] = slave->button->labels[i];
 | |
|     }
 | |
|     if (slave->valuator) {
 | |
|         dce->num_valuators = slave->valuator->numAxes;
 | |
|         for (i = 0; i < dce->num_valuators; i++) {
 | |
|             dce->valuators[i].min = slave->valuator->axes[i].min_value;
 | |
|             dce->valuators[i].max = slave->valuator->axes[i].max_value;
 | |
|             dce->valuators[i].resolution = slave->valuator->axes[i].resolution;
 | |
|             dce->valuators[i].mode = slave->valuator->axes[i].mode;
 | |
|             dce->valuators[i].name = slave->valuator->axes[i].label;
 | |
|             dce->valuators[i].scroll = slave->valuator->axes[i].scroll;
 | |
|             dce->valuators[i].value = slave->valuator->axisVal[i];
 | |
|         }
 | |
|     }
 | |
|     if (slave->key) {
 | |
|         dce->keys.min_keycode = slave->key->xkbInfo->desc->min_key_code;
 | |
|         dce->keys.max_keycode = slave->key->xkbInfo->desc->max_key_code;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Rescale the coord between the two axis ranges.
 | |
|  */
 | |
| static double
 | |
| rescaleValuatorAxis(double coord, AxisInfoPtr from, AxisInfoPtr to,
 | |
|                     double defmin, double defmax)
 | |
| {
 | |
|     double fmin = defmin, fmax = defmax;
 | |
|     double tmin = defmin, tmax = defmax;
 | |
| 
 | |
|     if (from && from->min_value < from->max_value) {
 | |
|         fmin = from->min_value;
 | |
|         fmax = from->max_value + 1;
 | |
|     }
 | |
|     if (to && to->min_value < to->max_value) {
 | |
|         tmin = to->min_value;
 | |
|         tmax = to->max_value + 1;
 | |
|     }
 | |
| 
 | |
|     if (fmin == tmin && fmax == tmax)
 | |
|         return coord;
 | |
| 
 | |
|     if (fmax == fmin)           /* avoid division by 0 */
 | |
|         return 0.0;
 | |
| 
 | |
|     return (coord - fmin) * (tmax - tmin) / (fmax - fmin) + tmin;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Update all coordinates when changing to a different SD
 | |
|  * to ensure that relative reporting will work as expected
 | |
|  * without loss of precision.
 | |
|  *
 | |
|  * pDev->last.valuators will be in absolute device coordinates after this
 | |
|  * function.
 | |
|  */
 | |
| static void
 | |
| updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev)
 | |
| {
 | |
|     /* master->last.valuators[0]/[1] is in desktop-wide coords and the actual
 | |
|      * position of the pointer */
 | |
|     pDev->last.valuators[0] = master->last.valuators[0];
 | |
|     pDev->last.valuators[1] = master->last.valuators[1];
 | |
| 
 | |
|     if (!pDev->valuator)
 | |
|         return;
 | |
| 
 | |
|     /* scale back to device coordinates */
 | |
|     if (pDev->valuator->numAxes > 0) {
 | |
|         pDev->last.valuators[0] = rescaleValuatorAxis(pDev->last.valuators[0],
 | |
|                                                       NULL,
 | |
|                                                       pDev->valuator->axes + 0,
 | |
|                                                       screenInfo.x,
 | |
|                                                       screenInfo.width);
 | |
|     }
 | |
|     if (pDev->valuator->numAxes > 1) {
 | |
|         pDev->last.valuators[1] = rescaleValuatorAxis(pDev->last.valuators[1],
 | |
|                                                       NULL,
 | |
|                                                       pDev->valuator->axes + 1,
 | |
|                                                       screenInfo.y,
 | |
|                                                       screenInfo.height);
 | |
|     }
 | |
| 
 | |
|     /* other axes are left as-is */
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Allocate the motion history buffer.
 | |
|  */
 | |
| void
 | |
| AllocateMotionHistory(DeviceIntPtr pDev)
 | |
| {
 | |
|     int size;
 | |
| 
 | |
|     free(pDev->valuator->motion);
 | |
| 
 | |
|     if (pDev->valuator->numMotionEvents < 1)
 | |
|         return;
 | |
| 
 | |
|     /* An MD must have a motion history size large enough to keep all
 | |
|      * potential valuators, plus the respective range of the valuators.
 | |
|      * 3 * INT32 for (min_val, max_val, curr_val))
 | |
|      */
 | |
|     if (IsMaster(pDev))
 | |
|         size = sizeof(INT32) * 3 * MAX_VALUATORS;
 | |
|     else {
 | |
|         ValuatorClassPtr v = pDev->valuator;
 | |
|         int numAxes;
 | |
| 
 | |
|         /* XI1 doesn't understand mixed mode devices */
 | |
|         for (numAxes = 0; numAxes < v->numAxes; numAxes++)
 | |
|             if (valuator_get_mode(pDev, numAxes) != valuator_get_mode(pDev, 0))
 | |
|                 break;
 | |
|         size = sizeof(INT32) * numAxes;
 | |
|     }
 | |
| 
 | |
|     size += sizeof(Time);
 | |
| 
 | |
|     pDev->valuator->motion = calloc(pDev->valuator->numMotionEvents, size);
 | |
|     pDev->valuator->first_motion = 0;
 | |
|     pDev->valuator->last_motion = 0;
 | |
|     if (!pDev->valuator->motion)
 | |
|         ErrorF("[dix] %s: Failed to alloc motion history (%d bytes).\n",
 | |
|                pDev->name, size * pDev->valuator->numMotionEvents);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Dump the motion history between start and stop into the supplied buffer.
 | |
|  * Only records the event for a given screen in theory, but in practice, we
 | |
|  * sort of ignore this.
 | |
|  *
 | |
|  * If core is set, we only generate x/y, in INT16, scaled to screen coords.
 | |
|  */
 | |
| int
 | |
| GetMotionHistory(DeviceIntPtr pDev, xTimecoord ** buff, unsigned long start,
 | |
|                  unsigned long stop, ScreenPtr pScreen, BOOL core)
 | |
| {
 | |
|     char *ibuff = NULL, *obuff;
 | |
|     int i = 0, ret = 0;
 | |
|     int j, coord;
 | |
|     Time current;
 | |
| 
 | |
|     /* The size of a single motion event. */
 | |
|     int size;
 | |
|     AxisInfo from, *to;         /* for scaling */
 | |
|     INT32 *ocbuf, *icbuf;       /* pointer to coordinates for copying */
 | |
|     INT16 *corebuf;
 | |
|     AxisInfo core_axis = { 0 };
 | |
| 
 | |
|     if (!pDev->valuator || !pDev->valuator->numMotionEvents)
 | |
|         return 0;
 | |
| 
 | |
|     if (core && !pScreen)
 | |
|         return 0;
 | |
| 
 | |
|     if (IsMaster(pDev))
 | |
|         size = (sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(Time);
 | |
|     else
 | |
|         size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
 | |
| 
 | |
|     *buff = malloc(size * pDev->valuator->numMotionEvents);
 | |
|     if (!(*buff))
 | |
|         return 0;
 | |
|     obuff = (char *) *buff;
 | |
| 
 | |
|     for (i = pDev->valuator->first_motion;
 | |
|          i != pDev->valuator->last_motion;
 | |
|          i = (i + 1) % pDev->valuator->numMotionEvents) {
 | |
|         /* We index the input buffer by which element we're accessing, which
 | |
|          * is not monotonic, and the output buffer by how many events we've
 | |
|          * written so far. */
 | |
|         ibuff = (char *) pDev->valuator->motion + (i * size);
 | |
|         memcpy(¤t, ibuff, sizeof(Time));
 | |
| 
 | |
|         if (current > stop) {
 | |
|             return ret;
 | |
|         }
 | |
|         else if (current >= start) {
 | |
|             if (core) {
 | |
|                 memcpy(obuff, ibuff, sizeof(Time));     /* copy timestamp */
 | |
| 
 | |
|                 icbuf = (INT32 *) (ibuff + sizeof(Time));
 | |
|                 corebuf = (INT16 *) (obuff + sizeof(Time));
 | |
| 
 | |
|                 /* fetch x coordinate + range */
 | |
|                 memcpy(&from.min_value, icbuf++, sizeof(INT32));
 | |
|                 memcpy(&from.max_value, icbuf++, sizeof(INT32));
 | |
|                 memcpy(&coord, icbuf++, sizeof(INT32));
 | |
| 
 | |
|                 /* scale to screen coords */
 | |
|                 to = &core_axis;
 | |
|                 to->max_value = pScreen->width;
 | |
|                 coord =
 | |
|                     rescaleValuatorAxis(coord, &from, to, 0, pScreen->width);
 | |
| 
 | |
|                 memcpy(corebuf, &coord, sizeof(INT16));
 | |
|                 corebuf++;
 | |
| 
 | |
|                 /* fetch y coordinate + range */
 | |
|                 memcpy(&from.min_value, icbuf++, sizeof(INT32));
 | |
|                 memcpy(&from.max_value, icbuf++, sizeof(INT32));
 | |
|                 memcpy(&coord, icbuf++, sizeof(INT32));
 | |
| 
 | |
|                 to->max_value = pScreen->height;
 | |
|                 coord =
 | |
|                     rescaleValuatorAxis(coord, &from, to, 0, pScreen->height);
 | |
|                 memcpy(corebuf, &coord, sizeof(INT16));
 | |
| 
 | |
|             }
 | |
|             else if (IsMaster(pDev)) {
 | |
|                 memcpy(obuff, ibuff, sizeof(Time));     /* copy timestamp */
 | |
| 
 | |
|                 ocbuf = (INT32 *) (obuff + sizeof(Time));
 | |
|                 icbuf = (INT32 *) (ibuff + sizeof(Time));
 | |
|                 for (j = 0; j < MAX_VALUATORS; j++) {
 | |
|                     if (j >= pDev->valuator->numAxes)
 | |
|                         break;
 | |
| 
 | |
|                     /* fetch min/max/coordinate */
 | |
|                     memcpy(&from.min_value, icbuf++, sizeof(INT32));
 | |
|                     memcpy(&from.max_value, icbuf++, sizeof(INT32));
 | |
|                     memcpy(&coord, icbuf++, sizeof(INT32));
 | |
| 
 | |
|                     to = (j <
 | |
|                           pDev->valuator->numAxes) ? &pDev->valuator->
 | |
|                         axes[j] : NULL;
 | |
| 
 | |
|                     /* x/y scaled to screen if no range is present */
 | |
|                     if (j == 0 && (from.max_value < from.min_value))
 | |
|                         from.max_value = pScreen->width;
 | |
|                     else if (j == 1 && (from.max_value < from.min_value))
 | |
|                         from.max_value = pScreen->height;
 | |
| 
 | |
|                     /* scale from stored range into current range */
 | |
|                     coord = rescaleValuatorAxis(coord, &from, to, 0, 0);
 | |
|                     memcpy(ocbuf, &coord, sizeof(INT32));
 | |
|                     ocbuf++;
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|                 memcpy(obuff, ibuff, size);
 | |
| 
 | |
|             /* don't advance by size here. size may be different to the
 | |
|              * actually written size if the MD has less valuators than MAX */
 | |
|             if (core)
 | |
|                 obuff += sizeof(INT32) + sizeof(Time);
 | |
|             else
 | |
|                 obuff +=
 | |
|                     (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
 | |
|             ret++;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Update the motion history for a specific device, with the list of
 | |
|  * valuators.
 | |
|  *
 | |
|  * Layout of the history buffer:
 | |
|  *   for SDs: [time] [val0] [val1] ... [valn]
 | |
|  *   for MDs: [time] [min_val0] [max_val0] [val0] [min_val1] ... [valn]
 | |
|  *
 | |
|  * For events that have some valuators unset:
 | |
|  *      min_val == max_val == val == 0.
 | |
|  */
 | |
| static void
 | |
| updateMotionHistory(DeviceIntPtr pDev, CARD32 ms, ValuatorMask *mask,
 | |
|                     double *valuators)
 | |
| {
 | |
|     char *buff = (char *) pDev->valuator->motion;
 | |
|     ValuatorClassPtr v;
 | |
|     int i;
 | |
| 
 | |
|     if (!pDev->valuator->numMotionEvents)
 | |
|         return;
 | |
| 
 | |
|     v = pDev->valuator;
 | |
|     if (IsMaster(pDev)) {
 | |
|         buff += ((sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(CARD32)) *
 | |
|             v->last_motion;
 | |
| 
 | |
|         memcpy(buff, &ms, sizeof(Time));
 | |
|         buff += sizeof(Time);
 | |
| 
 | |
|         memset(buff, 0, sizeof(INT32) * 3 * MAX_VALUATORS);
 | |
| 
 | |
|         for (i = 0; i < v->numAxes; i++) {
 | |
|             int val;
 | |
| 
 | |
|             /* XI1 doesn't support mixed mode devices */
 | |
|             if (valuator_get_mode(pDev, i) != valuator_get_mode(pDev, 0))
 | |
|                 break;
 | |
|             if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i)) {
 | |
|                 buff += 3 * sizeof(INT32);
 | |
|                 continue;
 | |
|             }
 | |
|             memcpy(buff, &v->axes[i].min_value, sizeof(INT32));
 | |
|             buff += sizeof(INT32);
 | |
|             memcpy(buff, &v->axes[i].max_value, sizeof(INT32));
 | |
|             buff += sizeof(INT32);
 | |
|             val = valuators[i];
 | |
|             memcpy(buff, &val, sizeof(INT32));
 | |
|             buff += sizeof(INT32);
 | |
|         }
 | |
|     }
 | |
|     else {
 | |
| 
 | |
|         buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) *
 | |
|             pDev->valuator->last_motion;
 | |
| 
 | |
|         memcpy(buff, &ms, sizeof(Time));
 | |
|         buff += sizeof(Time);
 | |
| 
 | |
|         memset(buff, 0, sizeof(INT32) * pDev->valuator->numAxes);
 | |
| 
 | |
|         for (i = 0; i < MAX_VALUATORS; i++) {
 | |
|             int val;
 | |
| 
 | |
|             if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i)) {
 | |
|                 buff += sizeof(INT32);
 | |
|                 continue;
 | |
|             }
 | |
|             val = valuators[i];
 | |
|             memcpy(buff, &val, sizeof(INT32));
 | |
|             buff += sizeof(INT32);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pDev->valuator->last_motion = (pDev->valuator->last_motion + 1) %
 | |
|         pDev->valuator->numMotionEvents;
 | |
|     /* If we're wrapping around, just keep the circular buffer going. */
 | |
|     if (pDev->valuator->first_motion == pDev->valuator->last_motion)
 | |
|         pDev->valuator->first_motion = (pDev->valuator->first_motion + 1) %
 | |
|             pDev->valuator->numMotionEvents;
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Returns the maximum number of events GetKeyboardEvents
 | |
|  * and GetPointerEvents will ever return.
 | |
|  *
 | |
|  * This MUST be absolutely constant, from init until exit.
 | |
|  */
 | |
| int
 | |
| 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 100;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Clip an axis to its bounds, which are declared in the call to
 | |
|  * InitValuatorAxisClassStruct.
 | |
|  */
 | |
| static void
 | |
| clipAxis(DeviceIntPtr pDev, int axisNum, double *val)
 | |
| {
 | |
|     AxisInfoPtr axis;
 | |
| 
 | |
|     if (axisNum >= pDev->valuator->numAxes)
 | |
|         return;
 | |
| 
 | |
|     axis = pDev->valuator->axes + axisNum;
 | |
| 
 | |
|     /* If a value range is defined, clip. If not, do nothing */
 | |
|     if (axis->max_value <= axis->min_value)
 | |
|         return;
 | |
| 
 | |
|     if (*val < axis->min_value)
 | |
|         *val = axis->min_value;
 | |
|     if (*val > axis->max_value)
 | |
|         *val = axis->max_value;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Clip every axis in the list of valuators to its bounds.
 | |
|  */
 | |
| static void
 | |
| clipValuators(DeviceIntPtr pDev, ValuatorMask *mask)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < valuator_mask_size(mask); i++)
 | |
|         if (valuator_mask_isset(mask, i)) {
 | |
|             double val = valuator_mask_get_double(mask, i);
 | |
| 
 | |
|             clipAxis(pDev, i, &val);
 | |
|             valuator_mask_set_double(mask, i, val);
 | |
|         }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Create the DCCE event (does not update the master's device state yet, this
 | |
|  * is done in the event processing).
 | |
|  * Pull in the coordinates from the MD if necessary.
 | |
|  *
 | |
|  * @param events Pointer to a pre-allocated event array.
 | |
|  * @param dev The slave device that generated an event.
 | |
|  * @param type Either DEVCHANGE_POINTER_EVENT and/or DEVCHANGE_KEYBOARD_EVENT
 | |
|  * @param num_events The current number of events, returns the number of
 | |
|  *        events if a DCCE was generated.
 | |
|  * @return The updated @events pointer.
 | |
|  */
 | |
| InternalEvent *
 | |
| UpdateFromMaster(InternalEvent *events, DeviceIntPtr dev, int type,
 | |
|                  int *num_events)
 | |
| {
 | |
|     DeviceIntPtr master;
 | |
| 
 | |
|     master =
 | |
|         GetMaster(dev,
 | |
|                   (type & DEVCHANGE_POINTER_EVENT) ? MASTER_POINTER :
 | |
|                   MASTER_KEYBOARD);
 | |
| 
 | |
|     if (master && master->last.slave != dev) {
 | |
|         CreateClassesChangedEvent(events, master, dev,
 | |
|                                   type | DEVCHANGE_SLAVE_SWITCH);
 | |
|         if (IsPointerDevice(master)) {
 | |
|             updateSlaveDeviceCoords(master, dev);
 | |
|             master->last.numValuators = dev->last.numValuators;
 | |
|         }
 | |
|         master->last.slave = dev;
 | |
|         (*num_events)++;
 | |
|         events++;
 | |
|     }
 | |
|     return events;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Move the device's pointer to the position given in the valuators.
 | |
|  *
 | |
|  * @param dev The device whose pointer is to be moved.
 | |
|  * @param mask Valuator data for this event.
 | |
|  */
 | |
| static void
 | |
| clipAbsolute(DeviceIntPtr dev, ValuatorMask *mask)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < valuator_mask_size(mask); i++) {
 | |
|         double val;
 | |
| 
 | |
|         if (!valuator_mask_isset(mask, i))
 | |
|             continue;
 | |
|         val = valuator_mask_get_double(mask, i);
 | |
|         clipAxis(dev, i, &val);
 | |
|         valuator_mask_set_double(mask, i, val);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| add_to_scroll_valuator(DeviceIntPtr dev, ValuatorMask *mask, int valuator, double value)
 | |
| {
 | |
|     double v;
 | |
| 
 | |
|     if (!valuator_mask_fetch_double(mask, valuator, &v))
 | |
|         return;
 | |
| 
 | |
|     /* protect against scrolling overflow. INT_MAX for double, because
 | |
|      * we'll eventually write this as 32.32 fixed point */
 | |
|     if ((value > 0 && v > INT_MAX - value) || (value < 0 && v < INT_MIN - value)) {
 | |
|         v = 0;
 | |
| 
 | |
|         /* reset last.scroll to avoid a button storm */
 | |
|         valuator_mask_set_double(dev->last.scroll, valuator, 0);
 | |
|     }
 | |
|     else
 | |
|         v += value;
 | |
| 
 | |
|     valuator_mask_set_double(mask, valuator, v);
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| scale_for_device_resolution(DeviceIntPtr dev, ValuatorMask *mask)
 | |
| {
 | |
|     double y;
 | |
|     ValuatorClassPtr v = dev->valuator;
 | |
|     int xrange = v->axes[0].max_value - v->axes[0].min_value + 1;
 | |
|     int yrange = v->axes[1].max_value - v->axes[1].min_value + 1;
 | |
| 
 | |
|     double screen_ratio = 1.0 * screenInfo.width/screenInfo.height;
 | |
|     double device_ratio = 1.0 * xrange/yrange;
 | |
|     double resolution_ratio = 1.0;
 | |
|     double ratio;
 | |
| 
 | |
|     if (!valuator_mask_fetch_double(mask, 1, &y))
 | |
|         return;
 | |
| 
 | |
|     if (v->axes[0].resolution != 0 && v->axes[1].resolution != 0)
 | |
|         resolution_ratio = 1.0 * v->axes[0].resolution/v->axes[1].resolution;
 | |
| 
 | |
|     ratio = device_ratio/resolution_ratio/screen_ratio;
 | |
|     valuator_mask_set_double(mask, 1, y / ratio);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Move the device's pointer by the values given in @valuators.
 | |
|  *
 | |
|  * @param dev The device whose pointer is to be moved.
 | |
|  * @param[in,out] mask Valuator data for this event, modified in-place.
 | |
|  */
 | |
| static void
 | |
| moveRelative(DeviceIntPtr dev, int flags, ValuatorMask *mask)
 | |
| {
 | |
|     int i;
 | |
|     Bool clip_xy = IsMaster(dev) || !IsFloating(dev);
 | |
|     ValuatorClassPtr v = dev->valuator;
 | |
| 
 | |
|     /* for abs devices in relative mode, we've just scaled wrong, since we
 | |
|        mapped the device's shape into the screen shape. Undo this. */
 | |
|     if ((flags & POINTER_ABSOLUTE) == 0 && v && v->numAxes > 1 &&
 | |
|         v->axes[0].min_value < v->axes[0].max_value &&
 | |
|         v->axes[1].min_value < v->axes[1].max_value) {
 | |
|         scale_for_device_resolution(dev, mask);
 | |
|     }
 | |
| 
 | |
|     /* calc other axes, clip, drop back into valuators */
 | |
|     for (i = 0; i < valuator_mask_size(mask); i++) {
 | |
|         double val = dev->last.valuators[i];
 | |
| 
 | |
|         if (!valuator_mask_isset(mask, i))
 | |
|             continue;
 | |
| 
 | |
|         add_to_scroll_valuator(dev, mask, i, val);
 | |
| 
 | |
|         /* x & y need to go over the limits to cross screens if the SD
 | |
|          * isn't currently attached; otherwise, clip to screen bounds. */
 | |
|         if (valuator_get_mode(dev, i) == Absolute &&
 | |
|             ((i != 0 && i != 1) || clip_xy)) {
 | |
|             val = valuator_mask_get_double(mask, i);
 | |
|             clipAxis(dev, i, &val);
 | |
|             valuator_mask_set_double(mask, i, val);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Accelerate the data in valuators based on the device's acceleration scheme.
 | |
|  *
 | |
|  * @param dev The device which's pointer is to be moved.
 | |
|  * @param valuators Valuator mask
 | |
|  * @param ms Current time.
 | |
|  */
 | |
| static void
 | |
| accelPointer(DeviceIntPtr dev, ValuatorMask *valuators, CARD32 ms)
 | |
| {
 | |
|     if (dev->valuator->accelScheme.AccelSchemeProc)
 | |
|         dev->valuator->accelScheme.AccelSchemeProc(dev, valuators, ms);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Scale from absolute screen coordinates to absolute coordinates in the
 | |
|  * device's coordinate range.
 | |
|  *
 | |
|  * @param dev The device to scale for.
 | |
|  * @param[in, out] mask The mask in desktop/screen coordinates, modified in place
 | |
|  * to contain device coordinate range.
 | |
|  * @param flags If POINTER_SCREEN is set, mask is in per-screen coordinates.
 | |
|  *              Otherwise, mask is in desktop coords.
 | |
|  */
 | |
| static void
 | |
| scale_from_screen(DeviceIntPtr dev, ValuatorMask *mask, int flags)
 | |
| {
 | |
|     double scaled;
 | |
|     ScreenPtr scr = miPointerGetScreen(dev);
 | |
| 
 | |
|     if (valuator_mask_isset(mask, 0)) {
 | |
|         scaled = valuator_mask_get_double(mask, 0);
 | |
|         if (flags & POINTER_SCREEN)
 | |
|             scaled += scr->x;
 | |
|         scaled = rescaleValuatorAxis(scaled,
 | |
|                                      NULL, dev->valuator->axes + 0,
 | |
|                                      screenInfo.x, screenInfo.width);
 | |
|         valuator_mask_set_double(mask, 0, scaled);
 | |
|     }
 | |
|     if (valuator_mask_isset(mask, 1)) {
 | |
|         scaled = valuator_mask_get_double(mask, 1);
 | |
|         if (flags & POINTER_SCREEN)
 | |
|             scaled += scr->y;
 | |
|         scaled = rescaleValuatorAxis(scaled,
 | |
|                                      NULL, dev->valuator->axes + 1,
 | |
|                                      screenInfo.y, screenInfo.height);
 | |
|         valuator_mask_set_double(mask, 1, scaled);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Scale from (absolute) device to screen coordinates here,
 | |
|  *
 | |
|  * The coordinates provided are always absolute. see fill_pointer_events for
 | |
|  * information on coordinate systems.
 | |
|  *
 | |
|  * @param dev The device to be moved.
 | |
|  * @param mask Mask of axis values for this event
 | |
|  * @param[out] devx x desktop-wide coordinate in device coordinate system
 | |
|  * @param[out] devy y desktop-wide coordinate in device coordinate system
 | |
|  * @param[out] screenx x coordinate in desktop coordinate system
 | |
|  * @param[out] screeny y coordinate in desktop coordinate system
 | |
|  */
 | |
| static ScreenPtr
 | |
| scale_to_desktop(DeviceIntPtr dev, ValuatorMask *mask,
 | |
|                  double *devx, double *devy, double *screenx, double *screeny)
 | |
| {
 | |
|     ScreenPtr scr = miPointerGetScreen(dev);
 | |
|     double x, y;
 | |
| 
 | |
|     BUG_WARN(dev->valuator && dev->valuator->numAxes < 2);
 | |
|     if (!dev->valuator || dev->valuator->numAxes < 2) {
 | |
|         /* if we have no axes, last.valuators must be in screen coords
 | |
|          * anyway */
 | |
|         *devx = *screenx = dev->last.valuators[0];
 | |
|         *devy = *screeny = dev->last.valuators[1];
 | |
|         return scr;
 | |
|     }
 | |
| 
 | |
|     if (valuator_mask_isset(mask, 0))
 | |
|         x = valuator_mask_get_double(mask, 0);
 | |
|     else
 | |
|         x = dev->last.valuators[0];
 | |
|     if (valuator_mask_isset(mask, 1))
 | |
|         y = valuator_mask_get_double(mask, 1);
 | |
|     else
 | |
|         y = dev->last.valuators[1];
 | |
| 
 | |
|     /* scale x&y to desktop coordinates */
 | |
|     *screenx = rescaleValuatorAxis(x, dev->valuator->axes + 0, NULL,
 | |
|                                    screenInfo.x, screenInfo.width);
 | |
|     *screeny = rescaleValuatorAxis(y, dev->valuator->axes + 1, NULL,
 | |
|                                    screenInfo.y, screenInfo.height);
 | |
| 
 | |
|     *devx = x;
 | |
|     *devy = y;
 | |
| 
 | |
|     return scr;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * If we have HW cursors, this actually moves the visible sprite. If not, we
 | |
|  * just do all the screen crossing, etc.
 | |
|  *
 | |
|  * We use the screen coordinates here, call miPointerSetPosition() and then
 | |
|  * scale back into device coordinates (if needed). miPSP will change x/y if
 | |
|  * the screen was crossed.
 | |
|  *
 | |
|  * The coordinates provided are always absolute. The parameter mode
 | |
|  * specifies whether it was relative or absolute movement that landed us at
 | |
|  * those coordinates. see fill_pointer_events for information on coordinate
 | |
|  * systems.
 | |
|  *
 | |
|  * @param dev The device to be moved.
 | |
|  * @param mode Movement mode (Absolute or Relative)
 | |
|  * @param[out] mask Mask of axis values for this event, returns the
 | |
|  * per-screen device coordinates after confinement
 | |
|  * @param[in,out] devx x desktop-wide coordinate in device coordinate system
 | |
|  * @param[in,out] devy y desktop-wide coordinate in device coordinate system
 | |
|  * @param[in,out] screenx x coordinate in desktop coordinate system
 | |
|  * @param[in,out] screeny y coordinate in desktop coordinate system
 | |
|  * @param[out] nevents Number of barrier events added to events
 | |
|  * @param[in,out] events List of events barrier events are added to
 | |
|  */
 | |
| static ScreenPtr
 | |
| positionSprite(DeviceIntPtr dev, int mode, ValuatorMask *mask,
 | |
|                double *devx, double *devy, double *screenx, double *screeny,
 | |
|                int *nevents, InternalEvent* events)
 | |
| {
 | |
|     ScreenPtr scr = miPointerGetScreen(dev);
 | |
|     double tmpx, tmpy;
 | |
| 
 | |
|     if (!dev->valuator || dev->valuator->numAxes < 2)
 | |
|         return scr;
 | |
| 
 | |
|     tmpx = *screenx;
 | |
|     tmpy = *screeny;
 | |
| 
 | |
|     /* miPointerSetPosition takes care of crossing screens for us, as well as
 | |
|      * clipping to the current screen. Coordinates returned are in desktop
 | |
|      * coord system */
 | |
|     scr = miPointerSetPosition(dev, mode, screenx, screeny, nevents, events);
 | |
| 
 | |
|     /* If we were constrained, rescale x/y from the screen coordinates so
 | |
|      * the device valuators reflect the correct position. For screen
 | |
|      * crossing this doesn't matter much, the coords would be 0 or max.
 | |
|      */
 | |
|     if (tmpx != *screenx)
 | |
|         *devx = rescaleValuatorAxis(*screenx, NULL, dev->valuator->axes + 0,
 | |
|                                     screenInfo.x, screenInfo.width);
 | |
| 
 | |
|     if (tmpy != *screeny)
 | |
|         *devy = rescaleValuatorAxis(*screeny, NULL, dev->valuator->axes + 1,
 | |
|                                     screenInfo.y, screenInfo.height);
 | |
| 
 | |
|     /* Recalculate the per-screen device coordinates */
 | |
|     if (valuator_mask_isset(mask, 0)) {
 | |
|         double x;
 | |
| 
 | |
|         x = rescaleValuatorAxis(*screenx - scr->x, NULL,
 | |
|                                 dev->valuator->axes + 0, 0, scr->width);
 | |
|         valuator_mask_set_double(mask, 0, x);
 | |
|     }
 | |
|     if (valuator_mask_isset(mask, 1)) {
 | |
|         double y;
 | |
| 
 | |
|         y = rescaleValuatorAxis(*screeny - scr->y, NULL,
 | |
|                                 dev->valuator->axes + 1, 0, scr->height);
 | |
|         valuator_mask_set_double(mask, 1, y);
 | |
|     }
 | |
| 
 | |
|     return scr;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Update the motion history for the device and (if appropriate) for its
 | |
|  * master device.
 | |
|  * @param dev Slave device to update.
 | |
|  * @param mask Bit mask of valid valuators to append to history.
 | |
|  * @param num Total number of valuators to append to history.
 | |
|  * @param ms Current time
 | |
|  */
 | |
| static void
 | |
| updateHistory(DeviceIntPtr dev, ValuatorMask *mask, CARD32 ms)
 | |
| {
 | |
|     if (!dev->valuator)
 | |
|         return;
 | |
| 
 | |
|     updateMotionHistory(dev, ms, mask, dev->last.valuators);
 | |
|     if (!IsMaster(dev) && !IsFloating(dev)) {
 | |
|         DeviceIntPtr master = GetMaster(dev, MASTER_POINTER);
 | |
| 
 | |
|         updateMotionHistory(master, ms, mask, dev->last.valuators);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| queueEventList(DeviceIntPtr device, InternalEvent *events, int nevents)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < nevents; i++)
 | |
|         mieqEnqueue(device, &events[i]);
 | |
| }
 | |
| 
 | |
| static void
 | |
| event_set_root_coordinates(DeviceEvent *event, double x, double y)
 | |
| {
 | |
|     event->root_x = trunc(x);
 | |
|     event->root_y = trunc(y);
 | |
|     event->root_x_frac = x - trunc(x);
 | |
|     event->root_y_frac = y - trunc(y);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Generate internal events representing this keyboard event and enqueue
 | |
|  * them on the event queue.
 | |
|  *
 | |
|  * This function is not reentrant. Disable signals before calling.
 | |
|  *
 | |
|  * @param device The device to generate the event for
 | |
|  * @param type Event type, one of KeyPress or KeyRelease
 | |
|  * @param keycode Key code of the pressed/released key
 | |
|  *
 | |
|  */
 | |
| void
 | |
| QueueKeyboardEvents(DeviceIntPtr device, int type,
 | |
|                     int keycode)
 | |
| {
 | |
|     int nevents;
 | |
| 
 | |
|     nevents = GetKeyboardEvents(InputEventList, device, type, keycode);
 | |
|     queueEventList(device, InputEventList, nevents);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Returns a set of InternalEvents for KeyPress/KeyRelease, optionally
 | |
|  * also with valuator events.
 | |
|  *
 | |
|  * The DDX is responsible for allocating the event list in the first
 | |
|  * place via InitEventList(), and for freeing it.
 | |
|  *
 | |
|  * @return the number of events written into events.
 | |
|  */
 | |
| int
 | |
| GetKeyboardEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
 | |
|                   int key_code)
 | |
| {
 | |
|     int num_events = 0;
 | |
|     CARD32 ms = 0;
 | |
|     DeviceEvent *event;
 | |
|     RawDeviceEvent *raw;
 | |
|     enum DeviceEventSource source_type = EVENT_SOURCE_NORMAL;
 | |
| 
 | |
| #ifdef XSERVER_DTRACE
 | |
|     if (XSERVER_INPUT_EVENT_ENABLED()) {
 | |
|         XSERVER_INPUT_EVENT(pDev->id, type, key_code, 0, 0,
 | |
|                             NULL, NULL);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     if (type == EnterNotify) {
 | |
|         source_type = EVENT_SOURCE_FOCUS;
 | |
|         type = KeyPress;
 | |
|     } else if (type == LeaveNotify) {
 | |
|         source_type = EVENT_SOURCE_FOCUS;
 | |
|         type = KeyRelease;
 | |
|     }
 | |
| 
 | |
|     /* refuse events from disabled devices */
 | |
|     if (!pDev->enabled)
 | |
|         return 0;
 | |
| 
 | |
|     if (!events || !pDev->key || !pDev->focus || !pDev->kbdfeed ||
 | |
|         (type != KeyPress && type != KeyRelease) ||
 | |
|         (key_code < 8 || key_code > 255))
 | |
|         return 0;
 | |
| 
 | |
|     num_events = 1;
 | |
| 
 | |
|     events =
 | |
|         UpdateFromMaster(events, pDev, DEVCHANGE_KEYBOARD_EVENT, &num_events);
 | |
| 
 | |
|     /* Handle core repeating, via press/release/press/release. */
 | |
|     if (type == KeyPress && key_is_down(pDev, key_code, KEY_POSTED)) {
 | |
|         /* If autorepeating is disabled either globally or just for that key,
 | |
|          * or we have a modifier, don't generate a repeat event. */
 | |
|         if (!pDev->kbdfeed->ctrl.autoRepeat ||
 | |
|             !key_autorepeats(pDev, key_code) ||
 | |
|             pDev->key->xkbInfo->desc->map->modmap[key_code])
 | |
|             return 0;
 | |
|     }
 | |
| 
 | |
|     ms = GetTimeInMillis();
 | |
| 
 | |
|     if (source_type == EVENT_SOURCE_NORMAL) {
 | |
|         raw = &events->raw_event;
 | |
|         init_raw(pDev, raw, ms, type, key_code);
 | |
|         events++;
 | |
|         num_events++;
 | |
|     }
 | |
| 
 | |
|     event = &events->device_event;
 | |
|     init_device_event(event, pDev, ms, source_type);
 | |
|     event->detail.key = key_code;
 | |
| 
 | |
|     if (type == KeyPress) {
 | |
|         event->type = ET_KeyPress;
 | |
|         set_key_down(pDev, key_code, KEY_POSTED);
 | |
|     }
 | |
|     else if (type == KeyRelease) {
 | |
|         event->type = ET_KeyRelease;
 | |
|         set_key_up(pDev, key_code, KEY_POSTED);
 | |
|     }
 | |
| 
 | |
|     return num_events;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Initialize an event array large enough for num_events arrays.
 | |
|  * This event list is to be passed into GetPointerEvents() and
 | |
|  * GetKeyboardEvents().
 | |
|  *
 | |
|  * @param num_events Number of elements in list.
 | |
|  */
 | |
| InternalEvent *
 | |
| InitEventList(int num_events)
 | |
| {
 | |
|     InternalEvent *events = calloc(num_events, sizeof(InternalEvent));
 | |
| 
 | |
|     return events;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Free an event list.
 | |
|  *
 | |
|  * @param list The list to be freed.
 | |
|  * @param num_events Number of elements in list.
 | |
|  */
 | |
| void
 | |
| FreeEventList(InternalEvent *list, int num_events)
 | |
| {
 | |
|     free(list);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Transform vector x/y according to matrix m and drop the rounded coords
 | |
|  * back into x/y.
 | |
|  */
 | |
| static void
 | |
| transform(struct pixman_f_transform *m, double *x, double *y)
 | |
| {
 | |
|     struct pixman_f_vector p = {.v = {*x, *y, 1} };
 | |
|     pixman_f_transform_point(m, &p);
 | |
| 
 | |
|     *x = p.v[0];
 | |
|     *y = p.v[1];
 | |
| }
 | |
| 
 | |
| static void
 | |
| transformRelative(DeviceIntPtr dev, ValuatorMask *mask)
 | |
| {
 | |
|     double x = 0, y = 0;
 | |
| 
 | |
|     valuator_mask_fetch_double(mask, 0, &x);
 | |
|     valuator_mask_fetch_double(mask, 1, &y);
 | |
| 
 | |
|     transform(&dev->relative_transform, &x, &y);
 | |
| 
 | |
|     if (x)
 | |
|         valuator_mask_set_double(mask, 0, x);
 | |
|     else
 | |
|         valuator_mask_unset(mask, 0);
 | |
| 
 | |
|     if (y)
 | |
|         valuator_mask_set_double(mask, 1, y);
 | |
|     else
 | |
|         valuator_mask_unset(mask, 1);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Apply the device's transformation matrix to the valuator mask and replace
 | |
|  * the scaled values in mask. This transformation only applies to valuators
 | |
|  * 0 and 1, others will be untouched.
 | |
|  *
 | |
|  * @param dev The device the valuators came from
 | |
|  * @param[in,out] mask The valuator mask.
 | |
|  */
 | |
| static void
 | |
| transformAbsolute(DeviceIntPtr dev, ValuatorMask *mask)
 | |
| {
 | |
|     double x, y, ox = 0.0, oy = 0.0;
 | |
|     int has_x, has_y;
 | |
| 
 | |
|     has_x = valuator_mask_isset(mask, 0);
 | |
|     has_y = valuator_mask_isset(mask, 1);
 | |
| 
 | |
|     if (!has_x && !has_y)
 | |
|         return;
 | |
| 
 | |
|     if (!has_x || !has_y) {
 | |
|         struct pixman_f_transform invert;
 | |
| 
 | |
|         /* undo transformation from last event */
 | |
|         ox = dev->last.valuators[0];
 | |
|         oy = dev->last.valuators[1];
 | |
| 
 | |
|         pixman_f_transform_invert(&invert, &dev->scale_and_transform);
 | |
|         transform(&invert, &ox, &oy);
 | |
|     }
 | |
| 
 | |
|     if (has_x)
 | |
|         ox = valuator_mask_get_double(mask, 0);
 | |
| 
 | |
|     if (has_y)
 | |
|         oy = valuator_mask_get_double(mask, 1);
 | |
| 
 | |
|     x = ox;
 | |
|     y = oy;
 | |
| 
 | |
|     transform(&dev->scale_and_transform, &x, &y);
 | |
| 
 | |
|     if (has_x || ox != x)
 | |
|         valuator_mask_set_double(mask, 0, x);
 | |
| 
 | |
|     if (has_y || oy != y)
 | |
|         valuator_mask_set_double(mask, 1, y);
 | |
| }
 | |
| 
 | |
| static void
 | |
| storeLastValuators(DeviceIntPtr dev, ValuatorMask *mask, double devx, double devy)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     /* store desktop-wide in last.valuators */
 | |
|     if (valuator_mask_isset(mask, 0))
 | |
|         dev->last.valuators[0] = devx;
 | |
|     if (valuator_mask_isset(mask, 1))
 | |
|         dev->last.valuators[1] = devy;
 | |
| 
 | |
|     for (i = 0; i < valuator_mask_size(mask); i++) {
 | |
|         if (i == 0 || i == 1)
 | |
|             continue;
 | |
| 
 | |
|         if (valuator_mask_isset(mask, i))
 | |
|             dev->last.valuators[i] = valuator_mask_get_double(mask, i);
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Generate internal events representing this pointer event and enqueue them
 | |
|  * on the event queue.
 | |
|  *
 | |
|  * This function is not reentrant. Disable signals before calling.
 | |
|  *
 | |
|  * @param device The device to generate the event for
 | |
|  * @param type Event type, one of ButtonPress, ButtonRelease, MotionNotify
 | |
|  * @param buttons Button number of the buttons modified. Must be 0 for
 | |
|  * MotionNotify
 | |
|  * @param flags Event modification flags
 | |
|  * @param mask Valuator mask for valuators present for this event.
 | |
|  */
 | |
| void
 | |
| QueuePointerEvents(DeviceIntPtr device, int type,
 | |
|                    int buttons, int flags, const ValuatorMask *mask)
 | |
| {
 | |
|     int nevents;
 | |
| 
 | |
|     nevents =
 | |
|         GetPointerEvents(InputEventList, device, type, buttons, flags, mask);
 | |
|     queueEventList(device, InputEventList, nevents);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Helper function for GetPointerEvents, which only generates motion and
 | |
|  * raw motion events for the slave device: does not update the master device.
 | |
|  *
 | |
|  * Should not be called by anyone other than GetPointerEvents.
 | |
|  *
 | |
|  * We use several different coordinate systems and need to switch between
 | |
|  * the three in fill_pointer_events, positionSprite and
 | |
|  * miPointerSetPosition. "desktop" refers to the width/height of all
 | |
|  * screenInfo.screens[n]->width/height added up. "screen" is ScreenRec, not
 | |
|  * output.
 | |
|  *
 | |
|  * Coordinate systems:
 | |
|  * - relative events have a mask_in in relative coordinates, mapped to
 | |
|  *   pixels. These events are mapped to the current position±delta.
 | |
|  * - absolute events have a mask_in in absolute device coordinates in
 | |
|  *   device-specific range. This range is mapped to the desktop.
 | |
|  * - POINTER_SCREEN absolute events (x86WarpCursor) are in screen-relative
 | |
|  *   screen coordinate range.
 | |
|  * - rootx/rooty in events must be be relative to the current screen's
 | |
|  *   origin (screen coordinate system)
 | |
|  * - XI2 valuators must be relative to the current screen's origin. On
 | |
|  *   the protocol the device min/max range maps to the current screen.
 | |
|  *
 | |
|  * For screen switching we need to get the desktop coordinates for each
 | |
|  * event, then map that to the respective position on each screen and
 | |
|  * position the cursor there.
 | |
|  * The device's last.valuator[] stores the last position in desktop-wide
 | |
|  * coordinates (in device range for slave devices, desktop range for master
 | |
|  * devices).
 | |
|  *
 | |
|  * screen-relative device coordinates requires scaling: A device coordinate
 | |
|  * x/y of range [n..m] that maps to positions Sx/Sy on Screen S must be
 | |
|  * rescaled to match Sx/Sy for [n..m]. In the simplest example, x of (m/2-1)
 | |
|  * is the last coordinate on the first screen and must be rescaled for the
 | |
|  * event to be m. XI2 clients that do their own coordinate mapping would
 | |
|  * otherwise interpret the position of the device elsewhere to the cursor.
 | |
|  * However, this scaling leads to losses:
 | |
|  * if we have two ScreenRecs we scale from e.g. [0..44704]  (Wacom I4) to
 | |
|  * [0..2048[. that gives us 2047.954 as desktop coord, or the per-screen
 | |
|  * coordinate 1023.954. Scaling that back into the device coordinate range
 | |
|  * gives us 44703. So off by one device unit. It's a bug, but we'll have to
 | |
|  * live with it because with all this scaling, we just cannot win.
 | |
|  *
 | |
|  * @return the number of events written into events.
 | |
|  */
 | |
| static int
 | |
| fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type,
 | |
|                     int buttons, CARD32 ms, int flags,
 | |
|                     const ValuatorMask *mask_in)
 | |
| {
 | |
|     int num_events = 0;
 | |
|     DeviceEvent *event;
 | |
|     RawDeviceEvent *raw = NULL;
 | |
|     double screenx = 0.0, screeny = 0.0;        /* desktop coordinate system */
 | |
|     double devx = 0.0, devy = 0.0;      /* desktop-wide in device coords */
 | |
|     int sx = 0, sy = 0;                 /* for POINTER_SCREEN */
 | |
|     ValuatorMask mask;
 | |
|     ScreenPtr scr;
 | |
|     int num_barrier_events = 0;
 | |
| 
 | |
|     switch (type) {
 | |
|     case MotionNotify:
 | |
|         if (!pDev->valuator) {
 | |
|             ErrorF("[dix] motion events from device %d without valuators\n",
 | |
|                    pDev->id);
 | |
|             return 0;
 | |
|         }
 | |
|         if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0)
 | |
|             return 0;
 | |
|         break;
 | |
|     case ButtonPress:
 | |
|     case ButtonRelease:
 | |
|         if (!pDev->button || !buttons)
 | |
|             return 0;
 | |
|         if (mask_in && valuator_mask_size(mask_in) > 0 && !pDev->valuator) {
 | |
|             ErrorF
 | |
|                 ("[dix] button event with valuator from device %d without valuators\n",
 | |
|                  pDev->id);
 | |
|             return 0;
 | |
|         }
 | |
|         break;
 | |
|     default:
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     valuator_mask_copy(&mask, mask_in);
 | |
| 
 | |
|     if ((flags & POINTER_NORAW) == 0) {
 | |
|         raw = &events->raw_event;
 | |
|         events++;
 | |
|         num_events++;
 | |
| 
 | |
|         init_raw(pDev, raw, ms, type, buttons);
 | |
| 
 | |
|         if (flags & POINTER_EMULATED)
 | |
|             raw->flags = XIPointerEmulated;
 | |
| 
 | |
|         set_raw_valuators(raw, &mask, TRUE, raw->valuators.data_raw);
 | |
|     }
 | |
| 
 | |
|     valuator_mask_drop_unaccelerated(&mask);
 | |
| 
 | |
|     /* valuators are in driver-native format (rel or abs) */
 | |
| 
 | |
|     if (flags & POINTER_ABSOLUTE) {
 | |
|         if (flags & (POINTER_SCREEN | POINTER_DESKTOP)) {    /* valuators are in screen/desktop coords */
 | |
|             sx = valuator_mask_get(&mask, 0);
 | |
|             sy = valuator_mask_get(&mask, 1);
 | |
|             scale_from_screen(pDev, &mask, flags);
 | |
|         }
 | |
| 
 | |
|         transformAbsolute(pDev, &mask);
 | |
|         clipAbsolute(pDev, &mask);
 | |
|         if ((flags & POINTER_NORAW) == 0 && raw)
 | |
|             set_raw_valuators(raw, &mask, FALSE, raw->valuators.data);
 | |
|     }
 | |
|     else {
 | |
|         transformRelative(pDev, &mask);
 | |
| 
 | |
|         if (flags & POINTER_ACCELERATE)
 | |
|             accelPointer(pDev, &mask, ms);
 | |
|         if ((flags & POINTER_NORAW) == 0 && raw)
 | |
|             set_raw_valuators(raw, &mask, FALSE, raw->valuators.data);
 | |
| 
 | |
|         moveRelative(pDev, flags, &mask);
 | |
|     }
 | |
| 
 | |
|     /* valuators are in device coordinate system in absolute coordinates */
 | |
|     scale_to_desktop(pDev, &mask, &devx, &devy, &screenx, &screeny);
 | |
| 
 | |
|     /* #53037 XWarpPointer's scaling back and forth between screen and
 | |
|        device may leave us with rounding errors. End result is that the
 | |
|        pointer doesn't end up on the pixel it should.
 | |
|        Avoid this by forcing screenx/screeny back to what the input
 | |
|        coordinates were.
 | |
|      */
 | |
|     if (flags & POINTER_SCREEN) {
 | |
|         scr = miPointerGetScreen(pDev);
 | |
|         screenx = sx + scr->x;
 | |
|         screeny = sy + scr->y;
 | |
|     }
 | |
| 
 | |
|     scr = positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative,
 | |
|                          &mask, &devx, &devy, &screenx, &screeny,
 | |
|                          &num_barrier_events, events);
 | |
|     num_events += num_barrier_events;
 | |
|     events += num_barrier_events;
 | |
| 
 | |
|     /* screenx, screeny are in desktop coordinates,
 | |
|        mask is in device coordinates per-screen (the event data)
 | |
|        devx/devy is in device coordinate desktop-wide */
 | |
|     updateHistory(pDev, &mask, ms);
 | |
| 
 | |
|     clipValuators(pDev, &mask);
 | |
| 
 | |
|     storeLastValuators(pDev, &mask, devx, devy);
 | |
| 
 | |
|     /* Update the MD's coordinates, which are always in desktop space. */
 | |
|     if (!IsMaster(pDev) && !IsFloating(pDev)) {
 | |
|         DeviceIntPtr master = GetMaster(pDev, MASTER_POINTER);
 | |
| 
 | |
|         master->last.valuators[0] = screenx;
 | |
|         master->last.valuators[1] = screeny;
 | |
|     }
 | |
| 
 | |
|     if ((flags & POINTER_RAWONLY) == 0) {
 | |
|         num_events++;
 | |
| 
 | |
|         event = &events->device_event;
 | |
|         init_device_event(event, pDev, ms, EVENT_SOURCE_NORMAL);
 | |
| 
 | |
|         if (type == MotionNotify) {
 | |
|             event->type = ET_Motion;
 | |
|             event->detail.button = 0;
 | |
|         }
 | |
|         else {
 | |
|             if (type == ButtonPress) {
 | |
|                 event->type = ET_ButtonPress;
 | |
|                 set_button_down(pDev, buttons, BUTTON_POSTED);
 | |
|             }
 | |
|             else if (type == ButtonRelease) {
 | |
|                 event->type = ET_ButtonRelease;
 | |
|                 set_button_up(pDev, buttons, BUTTON_POSTED);
 | |
|             }
 | |
|             event->detail.button = buttons;
 | |
|         }
 | |
| 
 | |
|         /* root_x and root_y must be in per-screen coordinates */
 | |
|         event_set_root_coordinates(event, screenx - scr->x, screeny - scr->y);
 | |
| 
 | |
|         if (flags & POINTER_EMULATED)
 | |
|             event->flags = XIPointerEmulated;
 | |
| 
 | |
|         set_valuators(pDev, event, &mask);
 | |
|     }
 | |
| 
 | |
|     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 type The real type of the event
 | |
|  * @param axis The axis number to generate events for
 | |
|  * @param mask State before this event in absolute coords
 | |
|  * @param last_valuators The device's last valuators value
 | |
|  * @param[in,out] lastScroll 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 type,
 | |
|                              int axis,
 | |
|                              const ValuatorMask *mask,
 | |
|                              const ValuatorMask *last_valuators,
 | |
|                              ValuatorMask *lastScroll, CARD32 ms, int max_events)
 | |
| {
 | |
|     AxisInfoPtr ax;
 | |
|     double delta;
 | |
|     double incr;
 | |
|     int direction = 0; /* -1 for up, 1 for down */
 | |
|     int num_events = 0;
 | |
|     int b;
 | |
|     int flags = 0;
 | |
|     double last_val,    /* abs axis value from previous event */
 | |
|            current_val, /* abs axis value for this event */
 | |
|            last_scroll_val; /* abs axis value we sent out the last scroll button for */
 | |
| 
 | |
|     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;
 | |
| 
 | |
|     BUG_WARN_MSG(incr == 0, "for device %s\n", dev->name);
 | |
|     if (incr == 0)
 | |
|         return 0;
 | |
| 
 | |
|     if (type != ButtonPress && type != ButtonRelease)
 | |
|         flags |= POINTER_EMULATED;
 | |
| 
 | |
|     if (!valuator_mask_isset(lastScroll, axis))
 | |
|         valuator_mask_set_double(lastScroll, axis, 0);
 | |
| 
 | |
|     /* The delta between the last value we sent a scroll button event for
 | |
|      * and the current event value (which has been applied already in
 | |
|      * fill_pointer_events). This tells us the scroll direction. */
 | |
|     delta = valuator_mask_get_double(mask, axis) - valuator_mask_get_double(lastScroll, axis);
 | |
|     direction = delta * incr > 0 ? 1 : -1;
 | |
| 
 | |
|     b = (ax->scroll.type == SCROLL_TYPE_VERTICAL) ? 5 : 7;
 | |
|     if (direction < 0)
 | |
|         b--;                    /* we're scrolling up or left → button 4 or 6 */
 | |
| 
 | |
|     /* Note: we emulate scroll on multiples of the increment, regardless of the
 | |
|      * current delta, mostly for the benefit of Xwayland which doesn't (cannot)
 | |
|      * distinguish between devices, see #1339 and #1414.
 | |
|      *
 | |
|      * Where a device scrolls a fraction of an increment, a subsequent scroll in
 | |
|      * the other direction did not trigger a scroll event. For example, where
 | |
|      * the increment is 1.0, the current axis value is 3.0 and a device scrolls
 | |
|      * down by 0.7 (a), then up by -1.0 (b), no scroll event was emitted:
 | |
|      *      -----|------b--|------a--|----
 | |
|      *          2.0       3.0       4.0
 | |
|      * For both events, the last button was sent at 3.0 and since the delta
 | |
|      * from that is never a full increment, no events were generated.
 | |
|      * With Xwayland this can happen when we switch between smooth-scroll
 | |
|      * devices and discrete devices.
 | |
|      *
 | |
|      * To avoid this, we now emulate button events whenever we cross a multiple
 | |
|      * of the scroll increment. For example, for a scroll increment of 1.0
 | |
|      * we expect events at -2.0, -1.0, 0.0, 1.0, 2.0,...
 | |
|      *
 | |
|      * In the above example, we go from 3.0 to 3.7 (no scroll button event),
 | |
|      * then from 3.7 to 2.7 which triggers a scroll button event because we
 | |
|      * cross 3.0.
 | |
|      *
 | |
|      * This trades off one bug for another. Previously, the first scroll button
 | |
|      * event after changing direction was always between
 | |
|      * [increment, 2 * increment). Above example again: the first event would be
 | |
|      * emulated at 2.0 so the full movement before a button event was actually
 | |
|      * -1.7.
 | |
|      *
 | |
|      * Now, the first scroll button event is always between (0.0, increment).
 | |
|      * Above example again: the first event would be emulated at 3.0
 | |
|      * so the full movement before a button event was actually -0.7.
 | |
|      *
 | |
|      * This only affects changes of directions. Above example again: the next
 | |
|      * button event in-direction would've been emulated at 4.0 so only 0.3
 | |
|      * from the current position.
 | |
|      */
 | |
|     last_val = valuator_mask_get_double(last_valuators, axis);
 | |
|     last_scroll_val = valuator_mask_get_double(lastScroll, axis);
 | |
|     current_val = valuator_mask_get_double(mask, axis);
 | |
| 
 | |
|     /* We're crossing an increment multiple? */
 | |
|     if ((current_val < last_scroll_val && last_scroll_val < last_val) ||
 | |
|         (last_val < last_scroll_val && last_scroll_val < current_val)) {
 | |
|         last_scroll_val -= direction * incr;
 | |
|     }
 | |
| 
 | |
|     while (TRUE) {
 | |
|         /* The next value we want to send out a button event for */
 | |
|         double next_val = last_scroll_val + direction * incr;
 | |
| 
 | |
|         if ((((direction > 0 && incr > 0) || (direction < 0 && incr < 0)) && (next_val > current_val)) ||
 | |
|             (((direction > 0 && incr < 0) || (direction < 0 && incr > 0)) && (next_val < current_val)))
 | |
|             break;
 | |
| 
 | |
|         /* 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) {
 | |
|             int nev_tmp;
 | |
| 
 | |
|             if (type != ButtonRelease) {
 | |
|                 nev_tmp = fill_pointer_events(events, dev, ButtonPress, b, ms,
 | |
|                                               flags, NULL);
 | |
|                 events += nev_tmp;
 | |
|                 num_events += nev_tmp;
 | |
|             }
 | |
|             if (type != ButtonPress) {
 | |
|                 nev_tmp = fill_pointer_events(events, dev, ButtonRelease, b, ms,
 | |
|                                               flags, NULL);
 | |
|                 events += nev_tmp;
 | |
|                 num_events += nev_tmp;
 | |
|             }
 | |
|         }
 | |
|         /* send out scroll event */
 | |
|         last_scroll_val = next_val;
 | |
|     }
 | |
| 
 | |
|     valuator_mask_set_double(lastScroll, axis, last_scroll_val);
 | |
| 
 | |
|     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
 | |
|  * device, also potentially generate a DeviceClassesChangedEvent to update
 | |
|  * the master device.
 | |
|  *
 | |
|  * events is not NULL-terminated; the return value is the number of events.
 | |
|  * The DDX is responsible for allocating the event structure in the first
 | |
|  * place via InitEventList() and GetMaximumEventsNum(), and for freeing it.
 | |
|  *
 | |
|  * In the generated events rootX/Y will be in absolute screen coords and
 | |
|  * the valuator information in the absolute or relative device coords.
 | |
|  *
 | |
|  * last.valuators[x] of the device is always in absolute device coords.
 | |
|  * last.valuators[x] of the master device is in absolute screen coords.
 | |
|  *
 | |
|  * master->last.valuators[x] for x > 2 is undefined.
 | |
|  */
 | |
| int
 | |
| GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
 | |
|                  int buttons, int flags, const ValuatorMask *mask_in)
 | |
| {
 | |
|     CARD32 ms = GetTimeInMillis();
 | |
|     int num_events = 0, nev_tmp;
 | |
|     ValuatorMask last_valuators;
 | |
|     ValuatorMask mask;
 | |
|     ValuatorMask scroll;
 | |
|     int i;
 | |
|     int realtype = type;
 | |
| 
 | |
| #ifdef XSERVER_DTRACE
 | |
|     if (XSERVER_INPUT_EVENT_ENABLED()) {
 | |
|         XSERVER_INPUT_EVENT(pDev->id, type, buttons, flags,
 | |
|                             mask_in ? mask_in->last_bit + 1 : 0,
 | |
|                             mask_in ? mask_in->mask : NULL,
 | |
|                             mask_in ? mask_in->valuators : NULL);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     BUG_RETURN_VAL(buttons >= MAX_BUTTONS, 0);
 | |
| 
 | |
|     /* refuse events from disabled devices */
 | |
|     if (!pDev->enabled)
 | |
|         return 0;
 | |
| 
 | |
|     if (!miPointerGetScreen(pDev))
 | |
|         return 0;
 | |
| 
 | |
|     events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT,
 | |
|                               &num_events);
 | |
| 
 | |
|     valuator_mask_copy(&mask, mask_in);
 | |
| 
 | |
|     /* Back up the current value of last.valuators. fill_pointer_events()
 | |
|      * overwrites those but we need them for scroll button emulation */
 | |
|     valuator_mask_zero(&last_valuators);
 | |
|     for (size_t idx = 0; idx < pDev->last.numValuators; idx++)
 | |
|         valuator_mask_set_double(&last_valuators, idx, pDev->last.valuators[idx]);
 | |
| 
 | |
|     /* 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 adj;
 | |
|         int axis;
 | |
|         int h_scroll_axis = -1;
 | |
|         int v_scroll_axis = -1;
 | |
| 
 | |
|         if (pDev->valuator) {
 | |
|             h_scroll_axis = pDev->valuator->h_scroll_axis;
 | |
|             v_scroll_axis = pDev->valuator->v_scroll_axis;
 | |
|         }
 | |
| 
 | |
|         /* Up is negative on valuators, down positive */
 | |
|         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;
 | |
|             if (!valuator_mask_isset(&mask, axis))
 | |
|                 valuator_mask_set(&mask, axis, 0);
 | |
|             add_to_scroll_valuator(pDev, &mask, axis, adj);
 | |
|             type = MotionNotify;
 | |
|             buttons = 0;
 | |
|             flags |= POINTER_EMULATED;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* 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 ( !pDev->valuator || (i >= pDev->valuator->numAxes))
 | |
|             break;
 | |
| 
 | |
|         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, realtype, i, &scroll,
 | |
|                                          &last_valuators, pDev->last.scroll, ms,
 | |
|                                          GetMaximumEventsNum() - num_events);
 | |
|         events += nev_tmp;
 | |
|         num_events += nev_tmp;
 | |
|     }
 | |
| 
 | |
|     return num_events;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Generate internal events representing this proximity event and enqueue
 | |
|  * them on the event queue.
 | |
|  *
 | |
|  * This function is not reentrant. Disable signals before calling.
 | |
|  *
 | |
|  * @param device The device to generate the event for
 | |
|  * @param type Event type, one of ProximityIn or ProximityOut
 | |
|  * @param keycode Key code of the pressed/released key
 | |
|  * @param mask Valuator mask for valuators present for this event.
 | |
|  *
 | |
|  */
 | |
| void
 | |
| QueueProximityEvents(DeviceIntPtr device, int type, const ValuatorMask *mask)
 | |
| {
 | |
|     int nevents;
 | |
| 
 | |
|     nevents = GetProximityEvents(InputEventList, device, type, mask);
 | |
|     queueEventList(device, InputEventList, nevents);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Generate ProximityIn/ProximityOut InternalEvents, accompanied by
 | |
|  * valuators.
 | |
|  *
 | |
|  * The DDX is responsible for allocating the events in the first place via
 | |
|  * InitEventList(), and for freeing it.
 | |
|  *
 | |
|  * @return the number of events written into events.
 | |
|  */
 | |
| int
 | |
| GetProximityEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
 | |
|                    const ValuatorMask *mask_in)
 | |
| {
 | |
|     int num_events = 1, i;
 | |
|     DeviceEvent *event;
 | |
|     ValuatorMask mask;
 | |
| 
 | |
| #ifdef XSERVER_DTRACE
 | |
|     if (XSERVER_INPUT_EVENT_ENABLED()) {
 | |
|         XSERVER_INPUT_EVENT(pDev->id, type, 0, 0,
 | |
|                             mask_in ? mask_in->last_bit + 1 : 0,
 | |
|                             mask_in ? mask_in->mask : NULL,
 | |
|                             mask_in ? mask_in->valuators : NULL);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     /* refuse events from disabled devices */
 | |
|     if (!pDev->enabled)
 | |
|         return 0;
 | |
| 
 | |
|     /* Sanity checks. */
 | |
|     if ((type != ProximityIn && type != ProximityOut) || !mask_in)
 | |
|         return 0;
 | |
|     if (!pDev->valuator || !pDev->proximity)
 | |
|         return 0;
 | |
| 
 | |
|     valuator_mask_copy(&mask, mask_in);
 | |
| 
 | |
|     /* ignore relative axes for proximity. */
 | |
|     for (i = 0; i < valuator_mask_size(&mask); i++) {
 | |
|         if (valuator_mask_isset(&mask, i) &&
 | |
|             valuator_get_mode(pDev, i) == Relative)
 | |
|             valuator_mask_unset(&mask, i);
 | |
|     }
 | |
| 
 | |
|     /* FIXME: posting proximity events with relative valuators only results
 | |
|      * in an empty event, EventToXI() will fail to convert → no event sent
 | |
|      * to client. */
 | |
| 
 | |
|     events =
 | |
|         UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events);
 | |
| 
 | |
|     event = &events->device_event;
 | |
|     init_device_event(event, pDev, GetTimeInMillis(), EVENT_SOURCE_NORMAL);
 | |
|     event->type = (type == ProximityIn) ? ET_ProximityIn : ET_ProximityOut;
 | |
| 
 | |
|     clipValuators(pDev, &mask);
 | |
| 
 | |
|     set_valuators(pDev, event, &mask);
 | |
| 
 | |
|     return num_events;
 | |
| }
 | |
| 
 | |
| int
 | |
| GetTouchOwnershipEvents(InternalEvent *events, DeviceIntPtr pDev,
 | |
|                         TouchPointInfoPtr ti, uint8_t reason, XID resource,
 | |
|                         uint32_t flags)
 | |
| {
 | |
|     TouchClassPtr t = pDev->touch;
 | |
|     TouchOwnershipEvent *event;
 | |
|     CARD32 ms = GetTimeInMillis();
 | |
| 
 | |
|     if (!pDev->enabled || !t || !ti)
 | |
|         return 0;
 | |
| 
 | |
|     event = &events->touch_ownership_event;
 | |
|     init_touch_ownership(pDev, event, ms);
 | |
| 
 | |
|     event->touchid = ti->client_id;
 | |
|     event->sourceid = ti->sourceid;
 | |
|     event->resource = resource;
 | |
|     event->flags = flags;
 | |
|     event->reason = reason;
 | |
| 
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Generate internal events representing this touch event and enqueue them
 | |
|  * on the event queue.
 | |
|  *
 | |
|  * This function is not reentrant. Disable signals before calling.
 | |
|  *
 | |
|  * @param device The device to generate the event for
 | |
|  * @param type Event type, one of XI_TouchBegin, XI_TouchUpdate, XI_TouchEnd
 | |
|  * @param touchid Touch point ID
 | |
|  * @param flags Event modification flags
 | |
|  * @param mask Valuator mask for valuators present for this event.
 | |
|  */
 | |
| void
 | |
| QueueTouchEvents(DeviceIntPtr device, int type,
 | |
|                  uint32_t ddx_touchid, int flags, const ValuatorMask *mask)
 | |
| {
 | |
|     int nevents;
 | |
| 
 | |
|     nevents =
 | |
|         GetTouchEvents(InputEventList, device, ddx_touchid, type, flags, mask);
 | |
|     queueEventList(device, InputEventList, nevents);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Get events for a touch. Generates a TouchBegin event if end is not set and
 | |
|  * the touch id is not active. Generates a TouchUpdate event if end is not set
 | |
|  * and the touch id is active. Generates a TouchEnd event if end is set and the
 | |
|  * touch id is active.
 | |
|  *
 | |
|  * events is not NULL-terminated; the return value is the number of events.
 | |
|  * The DDX is responsible for allocating the event structure in the first
 | |
|  * place via GetMaximumEventsNum(), and for freeing it.
 | |
|  *
 | |
|  * @param[out] events The list of events generated
 | |
|  * @param dev The device to generate the events for
 | |
|  * @param ddx_touchid The touch ID as assigned by the DDX
 | |
|  * @param type XI_TouchBegin, XI_TouchUpdate or XI_TouchEnd
 | |
|  * @param flags Event flags
 | |
|  * @param mask_in Valuator information for this event
 | |
|  */
 | |
| int
 | |
| GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
 | |
|                uint16_t type, uint32_t flags, const ValuatorMask *mask_in)
 | |
| {
 | |
|     ScreenPtr scr;
 | |
|     TouchClassPtr t = dev->touch;
 | |
|     ValuatorClassPtr v = dev->valuator;
 | |
|     DeviceEvent *event;
 | |
|     CARD32 ms = GetTimeInMillis();
 | |
|     ValuatorMask mask;
 | |
|     double screenx = 0.0, screeny = 0.0;        /* desktop coordinate system */
 | |
|     double devx = 0.0, devy = 0.0;      /* desktop-wide in device coords */
 | |
|     int i;
 | |
|     int num_events = 0;
 | |
|     RawDeviceEvent *raw;
 | |
|     DDXTouchPointInfoPtr ti;
 | |
|     int need_rawevent = TRUE;
 | |
|     Bool emulate_pointer = FALSE;
 | |
|     int client_id = 0;
 | |
| 
 | |
| #ifdef XSERVER_DTRACE
 | |
|     if (XSERVER_INPUT_EVENT_ENABLED()) {
 | |
|         XSERVER_INPUT_EVENT(dev->id, type, ddx_touchid, flags,
 | |
|                             mask_in ? mask_in->last_bit + 1 : 0,
 | |
|                             mask_in ? mask_in->mask : NULL,
 | |
|                             mask_in ? mask_in->valuators : NULL);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     if (!dev->enabled || !t || !v)
 | |
|         return 0;
 | |
| 
 | |
|     /* Find and/or create the DDX touch info */
 | |
| 
 | |
|     ti = TouchFindByDDXID(dev, ddx_touchid, (type == XI_TouchBegin));
 | |
|     if (!ti) {
 | |
|         ErrorFSigSafe("[dix] %s: unable to %s touch point %u\n", dev->name,
 | |
|                       type == XI_TouchBegin ? "begin" : "find", ddx_touchid);
 | |
|         return 0;
 | |
|     }
 | |
|     client_id = ti->client_id;
 | |
| 
 | |
|     emulate_pointer = ti->emulate_pointer;
 | |
| 
 | |
|     if (!IsMaster(dev))
 | |
|         events =
 | |
|             UpdateFromMaster(events, dev, DEVCHANGE_POINTER_EVENT, &num_events);
 | |
| 
 | |
|     valuator_mask_copy(&mask, mask_in);
 | |
| 
 | |
|     if (need_rawevent) {
 | |
|         raw = &events->raw_event;
 | |
|         events++;
 | |
|         num_events++;
 | |
|         init_raw(dev, raw, ms, type, client_id);
 | |
|         set_raw_valuators(raw, &mask, TRUE, raw->valuators.data_raw);
 | |
|     }
 | |
| 
 | |
|     event = &events->device_event;
 | |
|     num_events++;
 | |
| 
 | |
|     init_device_event(event, dev, ms, EVENT_SOURCE_NORMAL);
 | |
| 
 | |
|     switch (type) {
 | |
|     case XI_TouchBegin:
 | |
|         event->type = ET_TouchBegin;
 | |
|         /* If we're starting a touch, we must have x & y coordinates. */
 | |
|         if (!mask_in ||
 | |
|             !valuator_mask_isset(mask_in, 0) ||
 | |
|             !valuator_mask_isset(mask_in, 1)) {
 | |
|             ErrorFSigSafe("%s: Attempted to start touch without x/y "
 | |
|                           "(driver bug)\n", dev->name);
 | |
|             return 0;
 | |
|         }
 | |
|         break;
 | |
|     case XI_TouchUpdate:
 | |
|         event->type = ET_TouchUpdate;
 | |
|         if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0) {
 | |
|             ErrorFSigSafe("%s: TouchUpdate with no valuators? Driver bug\n",
 | |
|                           dev->name);
 | |
|         }
 | |
|         break;
 | |
|     case XI_TouchEnd:
 | |
|         event->type = ET_TouchEnd;
 | |
|         /* We can end the DDX touch here, since we don't use the active
 | |
|          * field below */
 | |
|         TouchEndDDXTouch(dev, ti);
 | |
|         break;
 | |
|     default:
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     /* Get our screen event coordinates (root_x/root_y/event_x/event_y):
 | |
|      * these come from the touchpoint in Absolute mode, or the sprite in
 | |
|      * Relative. */
 | |
|     if (t->mode == XIDirectTouch) {
 | |
|         for (i = 0; i < max(valuator_mask_size(&mask), 2); i++) {
 | |
|             double val;
 | |
| 
 | |
|             if (valuator_mask_fetch_double(&mask, i, &val))
 | |
|                 valuator_mask_set_double(ti->valuators, i, val);
 | |
|             /* If the device doesn't post new X and Y axis values,
 | |
|              * use the last values posted.
 | |
|              */
 | |
|             else if (i < 2 &&
 | |
|                 valuator_mask_fetch_double(ti->valuators, i, &val))
 | |
|                 valuator_mask_set_double(&mask, i, val);
 | |
|         }
 | |
| 
 | |
|         transformAbsolute(dev, &mask);
 | |
|         clipAbsolute(dev, &mask);
 | |
|     }
 | |
|     else {
 | |
|         screenx = dev->spriteInfo->sprite->hotPhys.x;
 | |
|         screeny = dev->spriteInfo->sprite->hotPhys.y;
 | |
|     }
 | |
|     if (need_rawevent)
 | |
|         set_raw_valuators(raw, &mask, FALSE, raw->valuators.data);
 | |
| 
 | |
|     scr = dev->spriteInfo->sprite->hotPhys.pScreen;
 | |
| 
 | |
|     /* Indirect device touch coordinates are not used for cursor positioning.
 | |
|      * They are merely informational, and are provided in device coordinates.
 | |
|      * The device sprite is used for positioning instead, and it is already
 | |
|      * scaled. */
 | |
|     if (t->mode == XIDirectTouch)
 | |
|         scr = scale_to_desktop(dev, &mask, &devx, &devy, &screenx, &screeny);
 | |
|     if (emulate_pointer)
 | |
|         scr = positionSprite(dev, Absolute, &mask,
 | |
|                              &devx, &devy, &screenx, &screeny, NULL, NULL);
 | |
| 
 | |
|     /* see fill_pointer_events for coordinate systems */
 | |
|     if (emulate_pointer)
 | |
|         updateHistory(dev, &mask, ms);
 | |
| 
 | |
|     clipValuators(dev, &mask);
 | |
| 
 | |
|     if (emulate_pointer)
 | |
|         storeLastValuators(dev, &mask, devx, devy);
 | |
| 
 | |
|     /* Update the MD's coordinates, which are always in desktop space. */
 | |
|     if (emulate_pointer && !IsMaster(dev) && !IsFloating(dev)) {
 | |
| 	    DeviceIntPtr master = GetMaster(dev, MASTER_POINTER);
 | |
| 
 | |
| 	    master->last.valuators[0] = screenx;
 | |
| 	    master->last.valuators[1] = screeny;
 | |
|     }
 | |
| 
 | |
|     event->root = scr->root->drawable.id;
 | |
| 
 | |
|     event_set_root_coordinates(event, screenx - scr->x, screeny - scr->y);
 | |
|     event->touchid = client_id;
 | |
|     event->flags = flags;
 | |
| 
 | |
|     if (emulate_pointer) {
 | |
|         event->flags |= TOUCH_POINTER_EMULATED;
 | |
|         event->detail.button = 1;
 | |
|     }
 | |
| 
 | |
|     set_valuators(dev, event, &mask);
 | |
|     for (i = 0; i < v->numAxes; i++) {
 | |
|         if (valuator_mask_isset(&mask, i))
 | |
|             v->axisVal[i] = valuator_mask_get(&mask, i);
 | |
|     }
 | |
| 
 | |
|     return num_events;
 | |
| }
 | |
| 
 | |
| void
 | |
| GetDixTouchEnd(InternalEvent *ievent, DeviceIntPtr dev, TouchPointInfoPtr ti,
 | |
|                uint32_t flags)
 | |
| {
 | |
|     ScreenPtr scr = dev->spriteInfo->sprite->hotPhys.pScreen;
 | |
|     DeviceEvent *event = &ievent->device_event;
 | |
|     CARD32 ms = GetTimeInMillis();
 | |
| 
 | |
|     BUG_WARN(!dev->enabled);
 | |
| 
 | |
|     init_device_event(event, dev, ms, EVENT_SOURCE_NORMAL);
 | |
| 
 | |
|     event->sourceid = ti->sourceid;
 | |
|     event->type = ET_TouchEnd;
 | |
| 
 | |
|     event->root = scr->root->drawable.id;
 | |
| 
 | |
|     /* Get screen event coordinates from the sprite.  Is this really the best
 | |
|      * we can do? */
 | |
|     event_set_root_coordinates(event,
 | |
|                                dev->last.valuators[0] - scr->x,
 | |
|                                dev->last.valuators[1] - scr->y);
 | |
|     event->touchid = ti->client_id;
 | |
|     event->flags = flags;
 | |
| 
 | |
|     if (flags & TOUCH_POINTER_EMULATED) {
 | |
|         event->flags |= TOUCH_POINTER_EMULATED;
 | |
|         event->detail.button = 1;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Synthesize a single motion event for the core pointer.
 | |
|  *
 | |
|  * Used in cursor functions, e.g. when cursor confinement changes, and we need
 | |
|  * to shift the pointer to get it inside the new bounds.
 | |
|  */
 | |
| void
 | |
| PostSyntheticMotion(DeviceIntPtr pDev,
 | |
|                     int x, int y, int screen, unsigned long time)
 | |
| {
 | |
|     DeviceEvent ev;
 | |
| 
 | |
| #ifdef PANORAMIX
 | |
|     /* Translate back to the sprite screen since processInputProc
 | |
|        will translate from sprite screen to screen 0 upon reentry
 | |
|        to the DIX layer. */
 | |
|     if (!noPanoramiXExtension) {
 | |
|         x += screenInfo.screens[0]->x - screenInfo.screens[screen]->x;
 | |
|         y += screenInfo.screens[0]->y - screenInfo.screens[screen]->y;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     memset(&ev, 0, sizeof(DeviceEvent));
 | |
|     init_device_event(&ev, pDev, time, EVENT_SOURCE_NORMAL);
 | |
|     ev.root_x = x;
 | |
|     ev.root_y = y;
 | |
|     ev.type = ET_Motion;
 | |
|     ev.time = time;
 | |
| 
 | |
|     /* FIXME: MD/SD considerations? */
 | |
|     (*pDev->public.processInputProc) ((InternalEvent *) &ev, pDev);
 | |
| }
 | |
| 
 | |
| void
 | |
| InitGestureEvent(InternalEvent *ievent, DeviceIntPtr dev, CARD32 ms,
 | |
|                  int type, uint16_t num_touches, uint32_t flags,
 | |
|                  double delta_x, double delta_y,
 | |
|                  double delta_unaccel_x, double delta_unaccel_y,
 | |
|                  double scale, double delta_angle)
 | |
| {
 | |
|     ScreenPtr scr = dev->spriteInfo->sprite->hotPhys.pScreen;
 | |
|     GestureEvent *event = &ievent->gesture_event;
 | |
|     double screenx = 0.0, screeny = 0.0;        /* desktop coordinate system */
 | |
| 
 | |
|     init_gesture_event(event, dev, ms);
 | |
| 
 | |
|     screenx = dev->spriteInfo->sprite->hotPhys.x;
 | |
|     screeny = dev->spriteInfo->sprite->hotPhys.y;
 | |
| 
 | |
|     event->type = type;
 | |
|     event->root = scr->root->drawable.id;
 | |
|     event->root_x = screenx - scr->x;
 | |
|     event->root_y = screeny - scr->y;
 | |
|     event->num_touches = num_touches;
 | |
|     event->flags = flags;
 | |
| 
 | |
|     event->delta_x = delta_x;
 | |
|     event->delta_y = delta_y;
 | |
|     event->delta_unaccel_x = delta_unaccel_x;
 | |
|     event->delta_unaccel_y = delta_unaccel_y;
 | |
|     event->scale = scale;
 | |
|     event->delta_angle = delta_angle;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Get events for a pinch or swipe gesture.
 | |
|  *
 | |
|  * events is not NULL-terminated; the return value is the number of events.
 | |
|  * The DDX is responsible for allocating the event structure in the first
 | |
|  * place via GetMaximumEventsNum(), and for freeing it.
 | |
|  *
 | |
|  * @param[out] events The list of events generated
 | |
|  * @param dev The device to generate the events for
 | |
|  * @param type XI_Gesture{Pinch,Swipe}{Begin,Update,End}
 | |
|  * @prama num_touches The number of touches in the gesture
 | |
|  * @param flags Event flags
 | |
|  * @param delta_x,delta_y accelerated relative motion delta
 | |
|  * @param delta_unaccel_x,delta_unaccel_y unaccelerated relative motion delta
 | |
|  * @param scale (valid only to pinch events) absolute scale of a pinch gesture
 | |
|  * @param delta_angle (valid only to pinch events) the ange delta in degrees between the last and
 | |
|  *        the current pinch event.
 | |
|  */
 | |
| int
 | |
| GetGestureEvents(InternalEvent *events, DeviceIntPtr dev,
 | |
|                  uint16_t type, uint16_t num_touches, uint32_t flags,
 | |
|                  double delta_x, double delta_y,
 | |
|                  double delta_unaccel_x, double delta_unaccel_y,
 | |
|                  double scale, double delta_angle)
 | |
| 
 | |
| {
 | |
|     GestureClassPtr g = dev->gesture;
 | |
|     CARD32 ms = GetTimeInMillis();
 | |
|     enum EventType evtype;
 | |
|     int num_events = 0;
 | |
|     uint32_t evflags = 0;
 | |
| 
 | |
|     if (!dev->enabled || !g)
 | |
|         return 0;
 | |
| 
 | |
|     if (!IsMaster(dev))
 | |
|         events = UpdateFromMaster(events, dev, DEVCHANGE_POINTER_EVENT,
 | |
|                                   &num_events);
 | |
| 
 | |
|     switch (type) {
 | |
|     case XI_GesturePinchBegin:
 | |
|         evtype = ET_GesturePinchBegin;
 | |
|         break;
 | |
|     case XI_GesturePinchUpdate:
 | |
|         evtype = ET_GesturePinchUpdate;
 | |
|         break;
 | |
|     case XI_GesturePinchEnd:
 | |
|         evtype = ET_GesturePinchEnd;
 | |
|         if (flags & XIGesturePinchEventCancelled)
 | |
|             evflags |= GESTURE_CANCELLED;
 | |
|         break;
 | |
|     case XI_GestureSwipeBegin:
 | |
|         evtype = ET_GestureSwipeBegin;
 | |
|         break;
 | |
|     case XI_GestureSwipeUpdate:
 | |
|         evtype = ET_GestureSwipeUpdate;
 | |
|         break;
 | |
|     case XI_GestureSwipeEnd:
 | |
|         evtype = ET_GestureSwipeEnd;
 | |
|         if (flags & XIGestureSwipeEventCancelled)
 | |
|             evflags |= GESTURE_CANCELLED;
 | |
|         break;
 | |
|     default:
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     InitGestureEvent(events, dev, ms, evtype, num_touches, evflags,
 | |
|                      delta_x, delta_y, delta_unaccel_x, delta_unaccel_y,
 | |
|                      scale, delta_angle);
 | |
|     num_events++;
 | |
| 
 | |
|     return num_events;
 | |
| }
 | |
| 
 | |
| void
 | |
| QueueGesturePinchEvents(DeviceIntPtr dev, uint16_t type,
 | |
|                         uint16_t num_touches, uint32_t flags,
 | |
|                         double delta_x, double delta_y,
 | |
|                         double delta_unaccel_x,
 | |
|                         double delta_unaccel_y,
 | |
|                         double scale, double delta_angle)
 | |
| {
 | |
|     int nevents;
 | |
|     nevents = GetGestureEvents(InputEventList, dev, type, num_touches, flags,
 | |
|                                delta_x, delta_y,
 | |
|                                delta_unaccel_x, delta_unaccel_y,
 | |
|                                scale, delta_angle);
 | |
|     queueEventList(dev, InputEventList, nevents);
 | |
| }
 | |
| 
 | |
| void
 | |
| QueueGestureSwipeEvents(DeviceIntPtr dev, uint16_t type,
 | |
|                         uint16_t num_touches, uint32_t flags,
 | |
|                         double delta_x, double delta_y,
 | |
|                         double delta_unaccel_x,
 | |
|                         double delta_unaccel_y)
 | |
| {
 | |
|     int nevents;
 | |
|     nevents = GetGestureEvents(InputEventList, dev, type, num_touches, flags,
 | |
|                                delta_x, delta_y,
 | |
|                                delta_unaccel_x, delta_unaccel_y,
 | |
|                                0.0, 0.0);
 | |
|     queueEventList(dev, InputEventList, nevents);
 | |
| }
 |