105b261ecSmrg/* 205b261ecSmrg * Copyright © 2006 Nokia Corporation 305b261ecSmrg * Copyright © 2006-2007 Daniel Stone 44202a189Smrg * Copyright © 2008 Red Hat, Inc. 5f7df2e56Smrg * Copyright © 2011 The Chromium Authors 605b261ecSmrg * 705b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining a 805b261ecSmrg * copy of this software and associated documentation files (the "Software"), 905b261ecSmrg * to deal in the Software without restriction, including without limitation 1005b261ecSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1105b261ecSmrg * and/or sell copies of the Software, and to permit persons to whom the 1205b261ecSmrg * Software is furnished to do so, subject to the following conditions: 1305b261ecSmrg * 1405b261ecSmrg * The above copyright notice and this permission notice (including the next 1505b261ecSmrg * paragraph) shall be included in all copies or substantial portions of the 1605b261ecSmrg * Software. 1705b261ecSmrg * 1805b261ecSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1905b261ecSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2005b261ecSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2105b261ecSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2205b261ecSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2305b261ecSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2405b261ecSmrg * DEALINGS IN THE SOFTWARE. 2505b261ecSmrg * 264202a189Smrg * Authors: Daniel Stone <daniel@fooishbar.org> 274202a189Smrg * Peter Hutterer <peter.hutterer@who-t.net> 2805b261ecSmrg */ 2905b261ecSmrg 3005b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 3105b261ecSmrg#include <dix-config.h> 3205b261ecSmrg#endif 3305b261ecSmrg 3405b261ecSmrg#include <X11/X.h> 3505b261ecSmrg#include <X11/keysym.h> 3605b261ecSmrg#include <X11/Xproto.h> 374202a189Smrg#include <math.h> 38f7df2e56Smrg#include <limits.h> 3905b261ecSmrg 4005b261ecSmrg#include "misc.h" 4105b261ecSmrg#include "resource.h" 4205b261ecSmrg#include "inputstr.h" 4305b261ecSmrg#include "scrnintstr.h" 4405b261ecSmrg#include "cursorstr.h" 4505b261ecSmrg#include "dixstruct.h" 4605b261ecSmrg#include "globals.h" 4705b261ecSmrg#include "dixevents.h" 4805b261ecSmrg#include "mipointer.h" 494202a189Smrg#include "eventstr.h" 504202a189Smrg#include "eventconvert.h" 5165b04b38Smrg#include "inpututils.h" 52f7df2e56Smrg#include "mi.h" 53f7df2e56Smrg#include "windowstr.h" 5405b261ecSmrg 5505b261ecSmrg#include <X11/extensions/XKBproto.h> 564202a189Smrg#include "xkbsrv.h" 5705b261ecSmrg 5805b261ecSmrg#ifdef PANORAMIX 5905b261ecSmrg#include "panoramiX.h" 6005b261ecSmrg#include "panoramiXsrv.h" 6105b261ecSmrg#endif 6205b261ecSmrg 6305b261ecSmrg#include <X11/extensions/XI.h> 64f7df2e56Smrg#include <X11/extensions/XI2.h> 6505b261ecSmrg#include <X11/extensions/XIproto.h> 664202a189Smrg#include <pixman.h> 6705b261ecSmrg#include "exglobals.h" 6805b261ecSmrg#include "exevents.h" 6905b261ecSmrg#include "extnsionst.h" 70f7df2e56Smrg#include "listdev.h" /* for sizing up DeviceClassesChangedEvent */ 71f7df2e56Smrg#include "probes.h" 7205b261ecSmrg 7305b261ecSmrg/* Number of motion history events to store. */ 7405b261ecSmrg#define MOTION_HISTORY_SIZE 256 7505b261ecSmrg 76f7df2e56Smrg/** 77f7df2e56Smrg * InputEventList is the storage for input events generated by 78f7df2e56Smrg * QueuePointerEvents, QueueKeyboardEvents, and QueueProximityEvents. 79f7df2e56Smrg * This list is allocated on startup by the DIX. 804642e01fSmrg */ 81f7df2e56SmrgInternalEvent *InputEventList = NULL; 8205b261ecSmrg 8305b261ecSmrg/** 8405b261ecSmrg * Pick some arbitrary size for Xi motion history. 8505b261ecSmrg */ 864202a189Smrgint 8705b261ecSmrgGetMotionHistorySize(void) 8805b261ecSmrg{ 8905b261ecSmrg return MOTION_HISTORY_SIZE; 9005b261ecSmrg} 9105b261ecSmrg 924202a189Smrgvoid 934202a189Smrgset_button_down(DeviceIntPtr pDev, int button, int type) 9405b261ecSmrg{ 954202a189Smrg if (type == BUTTON_PROCESSED) 964202a189Smrg SetBit(pDev->button->down, button); 974202a189Smrg else 984202a189Smrg SetBit(pDev->button->postdown, button); 9905b261ecSmrg} 10005b261ecSmrg 1014202a189Smrgvoid 1024202a189Smrgset_button_up(DeviceIntPtr pDev, int button, int type) 10305b261ecSmrg{ 1044202a189Smrg if (type == BUTTON_PROCESSED) 1054202a189Smrg ClearBit(pDev->button->down, button); 1064202a189Smrg else 1074202a189Smrg ClearBit(pDev->button->postdown, button); 10805b261ecSmrg} 10905b261ecSmrg 1104202a189SmrgBool 1114202a189Smrgbutton_is_down(DeviceIntPtr pDev, int button, int type) 1124202a189Smrg{ 1131b684552Smrg Bool ret = FALSE; 1144202a189Smrg 1154202a189Smrg if (type & BUTTON_PROCESSED) 1161b684552Smrg ret = ret || BitIsOn(pDev->button->down, button); 1174202a189Smrg if (type & BUTTON_POSTED) 1181b684552Smrg ret = ret || BitIsOn(pDev->button->postdown, button); 1194202a189Smrg 1204202a189Smrg return ret; 1214202a189Smrg} 1224202a189Smrg 1234202a189Smrgvoid 1244202a189Smrgset_key_down(DeviceIntPtr pDev, int key_code, int type) 12505b261ecSmrg{ 1264202a189Smrg if (type == KEY_PROCESSED) 1274202a189Smrg SetBit(pDev->key->down, key_code); 1284202a189Smrg else 1294202a189Smrg SetBit(pDev->key->postdown, key_code); 1304202a189Smrg} 1314202a189Smrg 1324202a189Smrgvoid 1334202a189Smrgset_key_up(DeviceIntPtr pDev, int key_code, int type) 1344202a189Smrg{ 1354202a189Smrg if (type == KEY_PROCESSED) 1364202a189Smrg ClearBit(pDev->key->down, key_code); 1374202a189Smrg else 1384202a189Smrg ClearBit(pDev->key->postdown, key_code); 1394202a189Smrg} 1404202a189Smrg 1414202a189SmrgBool 1424202a189Smrgkey_is_down(DeviceIntPtr pDev, int key_code, int type) 1434202a189Smrg{ 1441b684552Smrg Bool ret = FALSE; 1454202a189Smrg 1464202a189Smrg if (type & KEY_PROCESSED) 1471b684552Smrg ret = ret || BitIsOn(pDev->key->down, key_code); 1484202a189Smrg if (type & KEY_POSTED) 1491b684552Smrg ret = ret || BitIsOn(pDev->key->postdown, key_code); 1504202a189Smrg 1514202a189Smrg return ret; 15205b261ecSmrg} 15305b261ecSmrg 15405b261ecSmrgstatic Bool 15505b261ecSmrgkey_autorepeats(DeviceIntPtr pDev, int key_code) 15605b261ecSmrg{ 157f7df2e56Smrg return ! !(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3] & 158f7df2e56Smrg (1 << (key_code & 7))); 15905b261ecSmrg} 16005b261ecSmrg 1614202a189Smrgstatic void 162f7df2e56Smrginit_touch_ownership(DeviceIntPtr dev, TouchOwnershipEvent *event, Time ms) 1634202a189Smrg{ 164f7df2e56Smrg memset(event, 0, sizeof(TouchOwnershipEvent)); 1654202a189Smrg event->header = ET_Internal; 166f7df2e56Smrg event->type = ET_TouchOwnership; 167f7df2e56Smrg event->length = sizeof(TouchOwnershipEvent); 1684202a189Smrg event->time = ms; 1694202a189Smrg event->deviceid = dev->id; 1704202a189Smrg} 1714202a189Smrg 1724202a189Smrgstatic void 1734202a189Smrginit_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail) 1744202a189Smrg{ 1754202a189Smrg memset(event, 0, sizeof(RawDeviceEvent)); 1764202a189Smrg event->header = ET_Internal; 1774202a189Smrg event->length = sizeof(RawDeviceEvent); 178f7df2e56Smrg switch (type) { 179f7df2e56Smrg case MotionNotify: 180f7df2e56Smrg event->type = ET_RawMotion; 181f7df2e56Smrg break; 182f7df2e56Smrg case ButtonPress: 183f7df2e56Smrg event->type = ET_RawButtonPress; 184f7df2e56Smrg break; 185f7df2e56Smrg case ButtonRelease: 186f7df2e56Smrg event->type = ET_RawButtonRelease; 187f7df2e56Smrg break; 188f7df2e56Smrg case KeyPress: 189f7df2e56Smrg event->type = ET_RawKeyPress; 190f7df2e56Smrg break; 191f7df2e56Smrg case KeyRelease: 192f7df2e56Smrg event->type = ET_RawKeyRelease; 193f7df2e56Smrg break; 194f7df2e56Smrg case XI_TouchBegin: 195f7df2e56Smrg event->type = ET_RawTouchBegin; 196f7df2e56Smrg break; 197f7df2e56Smrg case XI_TouchUpdate: 198f7df2e56Smrg event->type = ET_RawTouchUpdate; 199f7df2e56Smrg break; 200f7df2e56Smrg case XI_TouchEnd: 201f7df2e56Smrg event->type = ET_RawTouchEnd; 202f7df2e56Smrg break; 203f7df2e56Smrg } 2044202a189Smrg event->time = ms; 2054202a189Smrg event->deviceid = dev->id; 2064202a189Smrg event->sourceid = dev->id; 2074202a189Smrg event->detail.button = detail; 2084202a189Smrg} 2094202a189Smrg 2104202a189Smrgstatic void 211f7df2e56Smrgset_raw_valuators(RawDeviceEvent *event, ValuatorMask *mask, 212f7df2e56Smrg BOOL use_unaccel, double *data) 2134202a189Smrg{ 2144202a189Smrg int i; 2154202a189Smrg 216f7df2e56Smrg use_unaccel = use_unaccel && valuator_mask_has_unaccelerated(mask); 217f7df2e56Smrg 218f7df2e56Smrg for (i = 0; i < valuator_mask_size(mask); i++) { 219f7df2e56Smrg if (valuator_mask_isset(mask, i)) { 220f7df2e56Smrg double v; 221f7df2e56Smrg 22265b04b38Smrg SetBit(event->valuators.mask, i); 223f7df2e56Smrg 224f7df2e56Smrg if (use_unaccel) 225f7df2e56Smrg v = valuator_mask_get_unaccelerated(mask, i); 226f7df2e56Smrg else 227f7df2e56Smrg v = valuator_mask_get_double(mask, i); 228f7df2e56Smrg 229f7df2e56Smrg data[i] = v; 23065b04b38Smrg } 23165b04b38Smrg } 2324202a189Smrg} 2334202a189Smrg 2344202a189Smrgstatic void 235f7df2e56Smrgset_valuators(DeviceIntPtr dev, DeviceEvent *event, ValuatorMask *mask) 2364202a189Smrg{ 2374202a189Smrg int i; 2384202a189Smrg 23965b04b38Smrg /* Set the data to the previous value for unset absolute axes. The values 24065b04b38Smrg * may be used when sent as part of an XI 1.x valuator event. */ 241f7df2e56Smrg for (i = 0; i < valuator_mask_size(mask); i++) { 242f7df2e56Smrg if (valuator_mask_isset(mask, i)) { 24365b04b38Smrg SetBit(event->valuators.mask, i); 24465b04b38Smrg if (valuator_get_mode(dev, i) == Absolute) 24565b04b38Smrg SetBit(event->valuators.mode, i); 246f7df2e56Smrg event->valuators.data[i] = valuator_mask_get_double(mask, i); 24765b04b38Smrg } 248f7df2e56Smrg else 24965b04b38Smrg event->valuators.data[i] = dev->valuator->axisVal[i]; 2504202a189Smrg } 2514202a189Smrg} 2524202a189Smrg 2534202a189Smrgvoid 254f7df2e56SmrgCreateClassesChangedEvent(InternalEvent *event, 255f7df2e56Smrg DeviceIntPtr master, DeviceIntPtr slave, int flags) 2564202a189Smrg{ 2574202a189Smrg int i; 2584202a189Smrg DeviceChangedEvent *dce; 2594202a189Smrg CARD32 ms = GetTimeInMillis(); 2604202a189Smrg 261f7df2e56Smrg dce = &event->changed_event; 2624202a189Smrg memset(dce, 0, sizeof(DeviceChangedEvent)); 2634202a189Smrg dce->deviceid = slave->id; 264f7df2e56Smrg dce->masterid = master ? master->id : 0; 2654202a189Smrg dce->header = ET_Internal; 2664202a189Smrg dce->length = sizeof(DeviceChangedEvent); 2674202a189Smrg dce->type = ET_DeviceChanged; 2684202a189Smrg dce->time = ms; 269f7df2e56Smrg dce->flags = flags; 2704202a189Smrg dce->sourceid = slave->id; 2714202a189Smrg 272f7df2e56Smrg if (slave->button) { 2734202a189Smrg dce->buttons.num_buttons = slave->button->numButtons; 2744202a189Smrg for (i = 0; i < dce->buttons.num_buttons; i++) 2754202a189Smrg dce->buttons.names[i] = slave->button->labels[i]; 2764202a189Smrg } 277f7df2e56Smrg if (slave->valuator) { 2784202a189Smrg dce->num_valuators = slave->valuator->numAxes; 279f7df2e56Smrg for (i = 0; i < dce->num_valuators; i++) { 2804202a189Smrg dce->valuators[i].min = slave->valuator->axes[i].min_value; 2814202a189Smrg dce->valuators[i].max = slave->valuator->axes[i].max_value; 2824202a189Smrg dce->valuators[i].resolution = slave->valuator->axes[i].resolution; 28365b04b38Smrg dce->valuators[i].mode = slave->valuator->axes[i].mode; 2844202a189Smrg dce->valuators[i].name = slave->valuator->axes[i].label; 285f7df2e56Smrg dce->valuators[i].scroll = slave->valuator->axes[i].scroll; 286f7df2e56Smrg dce->valuators[i].value = slave->valuator->axisVal[i]; 2874202a189Smrg } 2884202a189Smrg } 289f7df2e56Smrg if (slave->key) { 2904202a189Smrg dce->keys.min_keycode = slave->key->xkbInfo->desc->min_key_code; 2914202a189Smrg dce->keys.max_keycode = slave->key->xkbInfo->desc->max_key_code; 2924202a189Smrg } 2934202a189Smrg} 2944202a189Smrg 2954642e01fSmrg/** 2964642e01fSmrg * Rescale the coord between the two axis ranges. 2974642e01fSmrg */ 298f7df2e56Smrgstatic double 299f7df2e56SmrgrescaleValuatorAxis(double coord, AxisInfoPtr from, AxisInfoPtr to, 300f7df2e56Smrg double defmin, double defmax) 3014642e01fSmrg{ 302f7df2e56Smrg double fmin = defmin, fmax = defmax; 303f7df2e56Smrg double tmin = defmin, tmax = defmax; 3044642e01fSmrg 305f7df2e56Smrg if (from && from->min_value < from->max_value) { 3064642e01fSmrg fmin = from->min_value; 307f7df2e56Smrg fmax = from->max_value + 1; 3084642e01fSmrg } 309f7df2e56Smrg if (to && to->min_value < to->max_value) { 3104642e01fSmrg tmin = to->min_value; 311f7df2e56Smrg tmax = to->max_value + 1; 3124642e01fSmrg } 3134642e01fSmrg 314f7df2e56Smrg if (fmin == tmin && fmax == tmax) 3154642e01fSmrg return coord; 3164642e01fSmrg 317f7df2e56Smrg if (fmax == fmin) /* avoid division by 0 */ 318f7df2e56Smrg return 0.0; 3194642e01fSmrg 320f7df2e56Smrg return (coord - fmin) * (tmax - tmin) / (fmax - fmin) + tmin; 3214642e01fSmrg} 3224642e01fSmrg 3234642e01fSmrg/** 3244642e01fSmrg * Update all coordinates when changing to a different SD 3254642e01fSmrg * to ensure that relative reporting will work as expected 3264642e01fSmrg * without loss of precision. 3274642e01fSmrg * 3284642e01fSmrg * pDev->last.valuators will be in absolute device coordinates after this 3294642e01fSmrg * function. 3304642e01fSmrg */ 3314642e01fSmrgstatic void 3324642e01fSmrgupdateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev) 3334642e01fSmrg{ 334f7df2e56Smrg /* master->last.valuators[0]/[1] is in desktop-wide coords and the actual 3354642e01fSmrg * position of the pointer */ 3364642e01fSmrg pDev->last.valuators[0] = master->last.valuators[0]; 3374642e01fSmrg pDev->last.valuators[1] = master->last.valuators[1]; 3384642e01fSmrg 3394642e01fSmrg if (!pDev->valuator) 3404642e01fSmrg return; 3414642e01fSmrg 3424642e01fSmrg /* scale back to device coordinates */ 343f7df2e56Smrg if (pDev->valuator->numAxes > 0) { 344f7df2e56Smrg pDev->last.valuators[0] = rescaleValuatorAxis(pDev->last.valuators[0], 345f7df2e56Smrg NULL, 346f7df2e56Smrg pDev->valuator->axes + 0, 347f7df2e56Smrg screenInfo.x, 348f7df2e56Smrg screenInfo.width); 349f7df2e56Smrg } 350f7df2e56Smrg if (pDev->valuator->numAxes > 1) { 351f7df2e56Smrg pDev->last.valuators[1] = rescaleValuatorAxis(pDev->last.valuators[1], 352f7df2e56Smrg NULL, 353f7df2e56Smrg pDev->valuator->axes + 1, 354f7df2e56Smrg screenInfo.y, 355f7df2e56Smrg screenInfo.height); 356f7df2e56Smrg } 3574642e01fSmrg 35815af7600Smrg /* other axes are left as-is */ 3594642e01fSmrg} 3604642e01fSmrg 36105b261ecSmrg/** 36205b261ecSmrg * Allocate the motion history buffer. 36305b261ecSmrg */ 3644202a189Smrgvoid 36505b261ecSmrgAllocateMotionHistory(DeviceIntPtr pDev) 36605b261ecSmrg{ 3674642e01fSmrg int size; 368f7df2e56Smrg 3694202a189Smrg free(pDev->valuator->motion); 37005b261ecSmrg 37105b261ecSmrg if (pDev->valuator->numMotionEvents < 1) 37205b261ecSmrg return; 37305b261ecSmrg 3744642e01fSmrg /* An MD must have a motion history size large enough to keep all 3754642e01fSmrg * potential valuators, plus the respective range of the valuators. 3764642e01fSmrg * 3 * INT32 for (min_val, max_val, curr_val)) 3774642e01fSmrg */ 3784202a189Smrg if (IsMaster(pDev)) 3794642e01fSmrg size = sizeof(INT32) * 3 * MAX_VALUATORS; 38065b04b38Smrg else { 38165b04b38Smrg ValuatorClassPtr v = pDev->valuator; 38265b04b38Smrg int numAxes; 383f7df2e56Smrg 38465b04b38Smrg /* XI1 doesn't understand mixed mode devices */ 38565b04b38Smrg for (numAxes = 0; numAxes < v->numAxes; numAxes++) 38665b04b38Smrg if (valuator_get_mode(pDev, numAxes) != valuator_get_mode(pDev, 0)) 38765b04b38Smrg break; 38865b04b38Smrg size = sizeof(INT32) * numAxes; 38965b04b38Smrg } 3904642e01fSmrg 3914642e01fSmrg size += sizeof(Time); 3924642e01fSmrg 3934202a189Smrg pDev->valuator->motion = calloc(pDev->valuator->numMotionEvents, size); 39405b261ecSmrg pDev->valuator->first_motion = 0; 39505b261ecSmrg pDev->valuator->last_motion = 0; 3964642e01fSmrg if (!pDev->valuator->motion) 3974642e01fSmrg ErrorF("[dix] %s: Failed to alloc motion history (%d bytes).\n", 398f7df2e56Smrg pDev->name, size * pDev->valuator->numMotionEvents); 39905b261ecSmrg} 40005b261ecSmrg 40105b261ecSmrg/** 40205b261ecSmrg * Dump the motion history between start and stop into the supplied buffer. 40305b261ecSmrg * Only records the event for a given screen in theory, but in practice, we 40405b261ecSmrg * sort of ignore this. 4054642e01fSmrg * 4064642e01fSmrg * If core is set, we only generate x/y, in INT16, scaled to screen coords. 40705b261ecSmrg */ 4084202a189Smrgint 409f7df2e56SmrgGetMotionHistory(DeviceIntPtr pDev, xTimecoord ** buff, unsigned long start, 4104642e01fSmrg unsigned long stop, ScreenPtr pScreen, BOOL core) 41105b261ecSmrg{ 4124642e01fSmrg char *ibuff = NULL, *obuff; 41305b261ecSmrg int i = 0, ret = 0; 4144642e01fSmrg int j, coord; 41505b261ecSmrg Time current; 416f7df2e56Smrg 41705b261ecSmrg /* The size of a single motion event. */ 4184642e01fSmrg int size; 419f7df2e56Smrg AxisInfo from, *to; /* for scaling */ 420f7df2e56Smrg INT32 *ocbuf, *icbuf; /* pointer to coordinates for copying */ 4214642e01fSmrg INT16 *corebuf; 422f7df2e56Smrg AxisInfo core_axis = { 0 }; 42305b261ecSmrg 42405b261ecSmrg if (!pDev->valuator || !pDev->valuator->numMotionEvents) 42505b261ecSmrg return 0; 42605b261ecSmrg 4274642e01fSmrg if (core && !pScreen) 4284642e01fSmrg return 0; 4294642e01fSmrg 4304202a189Smrg if (IsMaster(pDev)) 4314642e01fSmrg size = (sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(Time); 4324642e01fSmrg else 4334642e01fSmrg size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time); 4344642e01fSmrg 4354202a189Smrg *buff = malloc(size * pDev->valuator->numMotionEvents); 4364642e01fSmrg if (!(*buff)) 4374642e01fSmrg return 0; 438f7df2e56Smrg obuff = (char *) *buff; 4394642e01fSmrg 44005b261ecSmrg for (i = pDev->valuator->first_motion; 44105b261ecSmrg i != pDev->valuator->last_motion; 44205b261ecSmrg i = (i + 1) % pDev->valuator->numMotionEvents) { 44305b261ecSmrg /* We index the input buffer by which element we're accessing, which 44405b261ecSmrg * is not monotonic, and the output buffer by how many events we've 44505b261ecSmrg * written so far. */ 44605b261ecSmrg ibuff = (char *) pDev->valuator->motion + (i * size); 44705b261ecSmrg memcpy(¤t, ibuff, sizeof(Time)); 44805b261ecSmrg 44905b261ecSmrg if (current > stop) { 45005b261ecSmrg return ret; 45105b261ecSmrg } 45205b261ecSmrg else if (current >= start) { 453f7df2e56Smrg if (core) { 454f7df2e56Smrg memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */ 4554642e01fSmrg 456f7df2e56Smrg icbuf = (INT32 *) (ibuff + sizeof(Time)); 457f7df2e56Smrg corebuf = (INT16 *) (obuff + sizeof(Time)); 4584642e01fSmrg 4594642e01fSmrg /* fetch x coordinate + range */ 4604642e01fSmrg memcpy(&from.min_value, icbuf++, sizeof(INT32)); 4614642e01fSmrg memcpy(&from.max_value, icbuf++, sizeof(INT32)); 4624642e01fSmrg memcpy(&coord, icbuf++, sizeof(INT32)); 4634642e01fSmrg 4644642e01fSmrg /* scale to screen coords */ 4654642e01fSmrg to = &core_axis; 4664642e01fSmrg to->max_value = pScreen->width; 467f7df2e56Smrg coord = 468f7df2e56Smrg rescaleValuatorAxis(coord, &from, to, 0, pScreen->width); 4694642e01fSmrg 4704642e01fSmrg memcpy(corebuf, &coord, sizeof(INT16)); 4714642e01fSmrg corebuf++; 4724642e01fSmrg 4734642e01fSmrg /* fetch y coordinate + range */ 4744642e01fSmrg memcpy(&from.min_value, icbuf++, sizeof(INT32)); 4754642e01fSmrg memcpy(&from.max_value, icbuf++, sizeof(INT32)); 4764642e01fSmrg memcpy(&coord, icbuf++, sizeof(INT32)); 4774642e01fSmrg 4784642e01fSmrg to->max_value = pScreen->height; 479f7df2e56Smrg coord = 480f7df2e56Smrg rescaleValuatorAxis(coord, &from, to, 0, pScreen->height); 4814642e01fSmrg memcpy(corebuf, &coord, sizeof(INT16)); 4824642e01fSmrg 483f7df2e56Smrg } 484f7df2e56Smrg else if (IsMaster(pDev)) { 485f7df2e56Smrg memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */ 4864642e01fSmrg 487f7df2e56Smrg ocbuf = (INT32 *) (obuff + sizeof(Time)); 488f7df2e56Smrg icbuf = (INT32 *) (ibuff + sizeof(Time)); 489f7df2e56Smrg for (j = 0; j < MAX_VALUATORS; j++) { 4904642e01fSmrg if (j >= pDev->valuator->numAxes) 4914642e01fSmrg break; 4924642e01fSmrg 4934642e01fSmrg /* fetch min/max/coordinate */ 4944642e01fSmrg memcpy(&from.min_value, icbuf++, sizeof(INT32)); 4954642e01fSmrg memcpy(&from.max_value, icbuf++, sizeof(INT32)); 4964642e01fSmrg memcpy(&coord, icbuf++, sizeof(INT32)); 4974642e01fSmrg 498f7df2e56Smrg to = (j < 499f7df2e56Smrg pDev->valuator->numAxes) ? &pDev->valuator-> 500f7df2e56Smrg axes[j] : NULL; 5014642e01fSmrg 5024642e01fSmrg /* x/y scaled to screen if no range is present */ 5034642e01fSmrg if (j == 0 && (from.max_value < from.min_value)) 5044642e01fSmrg from.max_value = pScreen->width; 5054642e01fSmrg else if (j == 1 && (from.max_value < from.min_value)) 5064642e01fSmrg from.max_value = pScreen->height; 5074642e01fSmrg 5084642e01fSmrg /* scale from stored range into current range */ 509f7df2e56Smrg coord = rescaleValuatorAxis(coord, &from, to, 0, 0); 5104642e01fSmrg memcpy(ocbuf, &coord, sizeof(INT32)); 5114642e01fSmrg ocbuf++; 5124642e01fSmrg } 513f7df2e56Smrg } 514f7df2e56Smrg else 5154642e01fSmrg memcpy(obuff, ibuff, size); 5164642e01fSmrg 5174642e01fSmrg /* don't advance by size here. size may be different to the 5184642e01fSmrg * actually written size if the MD has less valuators than MAX */ 5194642e01fSmrg if (core) 5204642e01fSmrg obuff += sizeof(INT32) + sizeof(Time); 5214642e01fSmrg else 522f7df2e56Smrg obuff += 523f7df2e56Smrg (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time); 52405b261ecSmrg ret++; 52505b261ecSmrg } 52605b261ecSmrg } 52705b261ecSmrg 52805b261ecSmrg return ret; 52905b261ecSmrg} 53005b261ecSmrg 53105b261ecSmrg/** 53205b261ecSmrg * Update the motion history for a specific device, with the list of 53305b261ecSmrg * valuators. 5344642e01fSmrg * 5354642e01fSmrg * Layout of the history buffer: 5364642e01fSmrg * for SDs: [time] [val0] [val1] ... [valn] 5374642e01fSmrg * for MDs: [time] [min_val0] [max_val0] [val0] [min_val1] ... [valn] 5384642e01fSmrg * 53965b04b38Smrg * For events that have some valuators unset: 5404642e01fSmrg * min_val == max_val == val == 0. 54105b261ecSmrg */ 54205b261ecSmrgstatic void 54365b04b38SmrgupdateMotionHistory(DeviceIntPtr pDev, CARD32 ms, ValuatorMask *mask, 544f7df2e56Smrg double *valuators) 54505b261ecSmrg{ 54605b261ecSmrg char *buff = (char *) pDev->valuator->motion; 5474642e01fSmrg ValuatorClassPtr v; 5484642e01fSmrg int i; 54905b261ecSmrg 55005b261ecSmrg if (!pDev->valuator->numMotionEvents) 55105b261ecSmrg return; 55205b261ecSmrg 5534642e01fSmrg v = pDev->valuator; 554f7df2e56Smrg if (IsMaster(pDev)) { 5554642e01fSmrg buff += ((sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(CARD32)) * 556f7df2e56Smrg v->last_motion; 5574642e01fSmrg 5584642e01fSmrg memcpy(buff, &ms, sizeof(Time)); 5594642e01fSmrg buff += sizeof(Time); 5604642e01fSmrg 5614642e01fSmrg memset(buff, 0, sizeof(INT32) * 3 * MAX_VALUATORS); 5624642e01fSmrg 563f7df2e56Smrg for (i = 0; i < v->numAxes; i++) { 564f7df2e56Smrg int val; 565f7df2e56Smrg 56665b04b38Smrg /* XI1 doesn't support mixed mode devices */ 56765b04b38Smrg if (valuator_get_mode(pDev, i) != valuator_get_mode(pDev, 0)) 5684642e01fSmrg break; 569f7df2e56Smrg if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i)) { 57065b04b38Smrg buff += 3 * sizeof(INT32); 57165b04b38Smrg continue; 57265b04b38Smrg } 5734642e01fSmrg memcpy(buff, &v->axes[i].min_value, sizeof(INT32)); 5744642e01fSmrg buff += sizeof(INT32); 5754642e01fSmrg memcpy(buff, &v->axes[i].max_value, sizeof(INT32)); 5764642e01fSmrg buff += sizeof(INT32); 577f7df2e56Smrg val = valuators[i]; 578f7df2e56Smrg memcpy(buff, &val, sizeof(INT32)); 5794642e01fSmrg buff += sizeof(INT32); 5804642e01fSmrg } 581f7df2e56Smrg } 582f7df2e56Smrg else { 5834642e01fSmrg 5844642e01fSmrg buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) * 58505b261ecSmrg pDev->valuator->last_motion; 58605b261ecSmrg 5874642e01fSmrg memcpy(buff, &ms, sizeof(Time)); 5884642e01fSmrg buff += sizeof(Time); 58905b261ecSmrg 5904642e01fSmrg memset(buff, 0, sizeof(INT32) * pDev->valuator->numAxes); 59105b261ecSmrg 592f7df2e56Smrg for (i = 0; i < MAX_VALUATORS; i++) { 593f7df2e56Smrg int val; 594f7df2e56Smrg 595f7df2e56Smrg if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i)) { 59665b04b38Smrg buff += sizeof(INT32); 59765b04b38Smrg continue; 59865b04b38Smrg } 599f7df2e56Smrg val = valuators[i]; 600f7df2e56Smrg memcpy(buff, &val, sizeof(INT32)); 60165b04b38Smrg buff += sizeof(INT32); 60265b04b38Smrg } 6034642e01fSmrg } 60405b261ecSmrg 6054642e01fSmrg pDev->valuator->last_motion = (pDev->valuator->last_motion + 1) % 6064642e01fSmrg pDev->valuator->numMotionEvents; 60705b261ecSmrg /* If we're wrapping around, just keep the circular buffer going. */ 60805b261ecSmrg if (pDev->valuator->first_motion == pDev->valuator->last_motion) 60905b261ecSmrg pDev->valuator->first_motion = (pDev->valuator->first_motion + 1) % 610f7df2e56Smrg pDev->valuator->numMotionEvents; 61105b261ecSmrg 61205b261ecSmrg return; 61305b261ecSmrg} 61405b261ecSmrg 61505b261ecSmrg/** 616f7df2e56Smrg * Returns the maximum number of events GetKeyboardEvents 617f7df2e56Smrg * and GetPointerEvents will ever return. 61805b261ecSmrg * 6194642e01fSmrg * This MUST be absolutely constant, from init until exit. 62005b261ecSmrg */ 6214202a189Smrgint 622f7df2e56SmrgGetMaximumEventsNum(void) 623f7df2e56Smrg{ 6244202a189Smrg /* One raw event 6254202a189Smrg * One device event 6264202a189Smrg * One possible device changed event 627f7df2e56Smrg * Lots of possible separate button scroll events (horiz + vert) 628f7df2e56Smrg * Lots of possible separate raw button scroll events (horiz + vert) 6294202a189Smrg */ 630f7df2e56Smrg return 100; 63105b261ecSmrg} 63205b261ecSmrg 63305b261ecSmrg/** 63405b261ecSmrg * Clip an axis to its bounds, which are declared in the call to 63505b261ecSmrg * InitValuatorAxisClassStruct. 63605b261ecSmrg */ 63705b261ecSmrgstatic void 638f7df2e56SmrgclipAxis(DeviceIntPtr pDev, int axisNum, double *val) 63905b261ecSmrg{ 6404202a189Smrg AxisInfoPtr axis; 6414202a189Smrg 6424202a189Smrg if (axisNum >= pDev->valuator->numAxes) 6434202a189Smrg return; 6444202a189Smrg 6454202a189Smrg axis = pDev->valuator->axes + axisNum; 6464642e01fSmrg 6474642e01fSmrg /* If a value range is defined, clip. If not, do nothing */ 6484642e01fSmrg if (axis->max_value <= axis->min_value) 6494642e01fSmrg return; 6504642e01fSmrg 6514642e01fSmrg if (*val < axis->min_value) 6524642e01fSmrg *val = axis->min_value; 6534642e01fSmrg if (*val > axis->max_value) 6544642e01fSmrg *val = axis->max_value; 65505b261ecSmrg} 65605b261ecSmrg 65705b261ecSmrg/** 65805b261ecSmrg * Clip every axis in the list of valuators to its bounds. 65905b261ecSmrg */ 66005b261ecSmrgstatic void 66165b04b38SmrgclipValuators(DeviceIntPtr pDev, ValuatorMask *mask) 66205b261ecSmrg{ 66305b261ecSmrg int i; 66405b261ecSmrg 66565b04b38Smrg for (i = 0; i < valuator_mask_size(mask); i++) 666f7df2e56Smrg if (valuator_mask_isset(mask, i)) { 667f7df2e56Smrg double val = valuator_mask_get_double(mask, i); 668f7df2e56Smrg 66965b04b38Smrg clipAxis(pDev, i, &val); 670f7df2e56Smrg valuator_mask_set_double(mask, i, val); 67165b04b38Smrg } 67205b261ecSmrg} 67305b261ecSmrg 6744642e01fSmrg/** 6754642e01fSmrg * Create the DCCE event (does not update the master's device state yet, this 6764642e01fSmrg * is done in the event processing). 6774642e01fSmrg * Pull in the coordinates from the MD if necessary. 6784642e01fSmrg * 679f7df2e56Smrg * @param events Pointer to a pre-allocated event array. 6804642e01fSmrg * @param dev The slave device that generated an event. 6814202a189Smrg * @param type Either DEVCHANGE_POINTER_EVENT and/or DEVCHANGE_KEYBOARD_EVENT 6824642e01fSmrg * @param num_events The current number of events, returns the number of 6834642e01fSmrg * events if a DCCE was generated. 6844642e01fSmrg * @return The updated @events pointer. 6854642e01fSmrg */ 686f7df2e56SmrgInternalEvent * 687f7df2e56SmrgUpdateFromMaster(InternalEvent *events, DeviceIntPtr dev, int type, 688f7df2e56Smrg int *num_events) 6894642e01fSmrg{ 6904202a189Smrg DeviceIntPtr master; 6914202a189Smrg 692f7df2e56Smrg master = 693f7df2e56Smrg GetMaster(dev, 694f7df2e56Smrg (type & DEVCHANGE_POINTER_EVENT) ? MASTER_POINTER : 695f7df2e56Smrg MASTER_KEYBOARD); 6964202a189Smrg 697f7df2e56Smrg if (master && master->last.slave != dev) { 698f7df2e56Smrg CreateClassesChangedEvent(events, master, dev, 699f7df2e56Smrg type | DEVCHANGE_SLAVE_SWITCH); 700f7df2e56Smrg if (IsPointerDevice(master)) { 7014202a189Smrg updateSlaveDeviceCoords(master, dev); 7024202a189Smrg master->last.numValuators = dev->last.numValuators; 7034202a189Smrg } 7044202a189Smrg master->last.slave = dev; 7054202a189Smrg (*num_events)++; 7064202a189Smrg events++; 7074642e01fSmrg } 7084642e01fSmrg return events; 7094642e01fSmrg} 7104642e01fSmrg 7114642e01fSmrg/** 7124642e01fSmrg * Move the device's pointer to the position given in the valuators. 7134642e01fSmrg * 714f7df2e56Smrg * @param dev The device whose pointer is to be moved. 715f7df2e56Smrg * @param mask Valuator data for this event. 7164642e01fSmrg */ 7174642e01fSmrgstatic void 718f7df2e56SmrgclipAbsolute(DeviceIntPtr dev, ValuatorMask *mask) 7194642e01fSmrg{ 7204642e01fSmrg int i; 7214642e01fSmrg 722f7df2e56Smrg for (i = 0; i < valuator_mask_size(mask); i++) { 723f7df2e56Smrg double val; 7244642e01fSmrg 725f7df2e56Smrg if (!valuator_mask_isset(mask, i)) 726f7df2e56Smrg continue; 727f7df2e56Smrg val = valuator_mask_get_double(mask, i); 728f7df2e56Smrg clipAxis(dev, i, &val); 729f7df2e56Smrg valuator_mask_set_double(mask, i, val); 730f7df2e56Smrg } 731f7df2e56Smrg} 732f7df2e56Smrg 733f7df2e56Smrgstatic void 734f7df2e56Smrgadd_to_scroll_valuator(DeviceIntPtr dev, ValuatorMask *mask, int valuator, double value) 735f7df2e56Smrg{ 736f7df2e56Smrg double v; 7374642e01fSmrg 738f7df2e56Smrg if (!valuator_mask_fetch_double(mask, valuator, &v)) 739f7df2e56Smrg return; 7404642e01fSmrg 741f7df2e56Smrg /* protect against scrolling overflow. INT_MAX for double, because 742f7df2e56Smrg * we'll eventually write this as 32.32 fixed point */ 743f7df2e56Smrg if ((value > 0 && v > INT_MAX - value) || (value < 0 && v < INT_MIN - value)) { 744f7df2e56Smrg v = 0; 745f7df2e56Smrg 746f7df2e56Smrg /* reset last.scroll to avoid a button storm */ 747f7df2e56Smrg valuator_mask_set_double(dev->last.scroll, valuator, 0); 7484642e01fSmrg } 749f7df2e56Smrg else 750f7df2e56Smrg v += value; 751f7df2e56Smrg 752f7df2e56Smrg valuator_mask_set_double(mask, valuator, v); 753f7df2e56Smrg} 754f7df2e56Smrg 755f7df2e56Smrg 756f7df2e56Smrgstatic void 757f7df2e56Smrgscale_for_device_resolution(DeviceIntPtr dev, ValuatorMask *mask) 758f7df2e56Smrg{ 759f7df2e56Smrg double y; 760f7df2e56Smrg ValuatorClassPtr v = dev->valuator; 761f7df2e56Smrg int xrange = v->axes[0].max_value - v->axes[0].min_value + 1; 762f7df2e56Smrg int yrange = v->axes[1].max_value - v->axes[1].min_value + 1; 763f7df2e56Smrg 764f7df2e56Smrg double screen_ratio = 1.0 * screenInfo.width/screenInfo.height; 765f7df2e56Smrg double device_ratio = 1.0 * xrange/yrange; 766f7df2e56Smrg double resolution_ratio = 1.0; 767f7df2e56Smrg double ratio; 768f7df2e56Smrg 769f7df2e56Smrg if (!valuator_mask_fetch_double(mask, 1, &y)) 770f7df2e56Smrg return; 771f7df2e56Smrg 772f7df2e56Smrg if (v->axes[0].resolution != 0 && v->axes[1].resolution != 0) 773f7df2e56Smrg resolution_ratio = 1.0 * v->axes[0].resolution/v->axes[1].resolution; 774f7df2e56Smrg 775f7df2e56Smrg ratio = device_ratio/resolution_ratio/screen_ratio; 776f7df2e56Smrg valuator_mask_set_double(mask, 1, y / ratio); 7774642e01fSmrg} 7784642e01fSmrg 7794642e01fSmrg/** 7804642e01fSmrg * Move the device's pointer by the values given in @valuators. 7814642e01fSmrg * 782f7df2e56Smrg * @param dev The device whose pointer is to be moved. 783f7df2e56Smrg * @param[in,out] mask Valuator data for this event, modified in-place. 7844642e01fSmrg */ 7854642e01fSmrgstatic void 786f7df2e56SmrgmoveRelative(DeviceIntPtr dev, int flags, ValuatorMask *mask) 7874642e01fSmrg{ 7884642e01fSmrg int i; 789f7df2e56Smrg Bool clip_xy = IsMaster(dev) || !IsFloating(dev); 790f7df2e56Smrg ValuatorClassPtr v = dev->valuator; 791f7df2e56Smrg 792f7df2e56Smrg /* for abs devices in relative mode, we've just scaled wrong, since we 793f7df2e56Smrg mapped the device's shape into the screen shape. Undo this. */ 794f7df2e56Smrg if ((flags & POINTER_ABSOLUTE) == 0 && v && v->numAxes > 1 && 795f7df2e56Smrg v->axes[0].min_value < v->axes[0].max_value && 796f7df2e56Smrg v->axes[1].min_value < v->axes[1].max_value) { 797f7df2e56Smrg scale_for_device_resolution(dev, mask); 798f7df2e56Smrg } 7994642e01fSmrg 800f7df2e56Smrg /* calc other axes, clip, drop back into valuators */ 801f7df2e56Smrg for (i = 0; i < valuator_mask_size(mask); i++) { 802f7df2e56Smrg double val = dev->last.valuators[i]; 8034642e01fSmrg 804f7df2e56Smrg if (!valuator_mask_isset(mask, i)) 805f7df2e56Smrg continue; 8064642e01fSmrg 807f7df2e56Smrg add_to_scroll_valuator(dev, mask, i, val); 8084642e01fSmrg 809f7df2e56Smrg /* x & y need to go over the limits to cross screens if the SD 810f7df2e56Smrg * isn't currently attached; otherwise, clip to screen bounds. */ 811f7df2e56Smrg if (valuator_get_mode(dev, i) == Absolute && 812f7df2e56Smrg ((i != 0 && i != 1) || clip_xy)) { 813f7df2e56Smrg val = valuator_mask_get_double(mask, i); 814f7df2e56Smrg clipAxis(dev, i, &val); 815f7df2e56Smrg valuator_mask_set_double(mask, i, val); 81665b04b38Smrg } 8174642e01fSmrg } 8184642e01fSmrg} 8194642e01fSmrg 8204642e01fSmrg/** 8214642e01fSmrg * Accelerate the data in valuators based on the device's acceleration scheme. 8224642e01fSmrg * 8234642e01fSmrg * @param dev The device which's pointer is to be moved. 824f7df2e56Smrg * @param valuators Valuator mask 8254642e01fSmrg * @param ms Current time. 8264642e01fSmrg */ 8274642e01fSmrgstatic void 828f7df2e56SmrgaccelPointer(DeviceIntPtr dev, ValuatorMask *valuators, CARD32 ms) 8294642e01fSmrg{ 8304642e01fSmrg if (dev->valuator->accelScheme.AccelSchemeProc) 831f7df2e56Smrg dev->valuator->accelScheme.AccelSchemeProc(dev, valuators, ms); 832f7df2e56Smrg} 833f7df2e56Smrg 834f7df2e56Smrg/** 835f7df2e56Smrg * Scale from absolute screen coordinates to absolute coordinates in the 836f7df2e56Smrg * device's coordinate range. 837f7df2e56Smrg * 838f7df2e56Smrg * @param dev The device to scale for. 839f7df2e56Smrg * @param[in, out] mask The mask in desktop/screen coordinates, modified in place 840f7df2e56Smrg * to contain device coordinate range. 841f7df2e56Smrg * @param flags If POINTER_SCREEN is set, mask is in per-screen coordinates. 842f7df2e56Smrg * Otherwise, mask is in desktop coords. 843f7df2e56Smrg */ 844f7df2e56Smrgstatic void 845f7df2e56Smrgscale_from_screen(DeviceIntPtr dev, ValuatorMask *mask, int flags) 846f7df2e56Smrg{ 847f7df2e56Smrg double scaled; 848f7df2e56Smrg ScreenPtr scr = miPointerGetScreen(dev); 849f7df2e56Smrg 850f7df2e56Smrg if (valuator_mask_isset(mask, 0)) { 851f7df2e56Smrg scaled = valuator_mask_get_double(mask, 0); 852f7df2e56Smrg if (flags & POINTER_SCREEN) 853f7df2e56Smrg scaled += scr->x; 854f7df2e56Smrg scaled = rescaleValuatorAxis(scaled, 855f7df2e56Smrg NULL, dev->valuator->axes + 0, 856f7df2e56Smrg screenInfo.x, screenInfo.width); 857f7df2e56Smrg valuator_mask_set_double(mask, 0, scaled); 858f7df2e56Smrg } 859f7df2e56Smrg if (valuator_mask_isset(mask, 1)) { 860f7df2e56Smrg scaled = valuator_mask_get_double(mask, 1); 861f7df2e56Smrg if (flags & POINTER_SCREEN) 862f7df2e56Smrg scaled += scr->y; 863f7df2e56Smrg scaled = rescaleValuatorAxis(scaled, 864f7df2e56Smrg NULL, dev->valuator->axes + 1, 865f7df2e56Smrg screenInfo.y, screenInfo.height); 866f7df2e56Smrg valuator_mask_set_double(mask, 1, scaled); 867f7df2e56Smrg } 868f7df2e56Smrg} 869f7df2e56Smrg 870f7df2e56Smrg/** 871f7df2e56Smrg * Scale from (absolute) device to screen coordinates here, 872f7df2e56Smrg * 873f7df2e56Smrg * The coordinates provided are always absolute. see fill_pointer_events for 874f7df2e56Smrg * information on coordinate systems. 875f7df2e56Smrg * 876f7df2e56Smrg * @param dev The device to be moved. 877f7df2e56Smrg * @param mask Mask of axis values for this event 878f7df2e56Smrg * @param[out] devx x desktop-wide coordinate in device coordinate system 879f7df2e56Smrg * @param[out] devy y desktop-wide coordinate in device coordinate system 880f7df2e56Smrg * @param[out] screenx x coordinate in desktop coordinate system 881f7df2e56Smrg * @param[out] screeny y coordinate in desktop coordinate system 882f7df2e56Smrg */ 883f7df2e56Smrgstatic ScreenPtr 884f7df2e56Smrgscale_to_desktop(DeviceIntPtr dev, ValuatorMask *mask, 885f7df2e56Smrg double *devx, double *devy, double *screenx, double *screeny) 886f7df2e56Smrg{ 887f7df2e56Smrg ScreenPtr scr = miPointerGetScreen(dev); 888f7df2e56Smrg double x, y; 889f7df2e56Smrg 890f7df2e56Smrg BUG_WARN(dev->valuator && dev->valuator->numAxes < 2); 891f7df2e56Smrg if (!dev->valuator || dev->valuator->numAxes < 2) { 892f7df2e56Smrg /* if we have no axes, last.valuators must be in screen coords 893f7df2e56Smrg * anyway */ 894f7df2e56Smrg *devx = *screenx = dev->last.valuators[0]; 895f7df2e56Smrg *devy = *screeny = dev->last.valuators[1]; 896f7df2e56Smrg return scr; 897f7df2e56Smrg } 898f7df2e56Smrg 899f7df2e56Smrg if (valuator_mask_isset(mask, 0)) 900f7df2e56Smrg x = valuator_mask_get_double(mask, 0); 901f7df2e56Smrg else 902f7df2e56Smrg x = dev->last.valuators[0]; 903f7df2e56Smrg if (valuator_mask_isset(mask, 1)) 904f7df2e56Smrg y = valuator_mask_get_double(mask, 1); 905f7df2e56Smrg else 906f7df2e56Smrg y = dev->last.valuators[1]; 907f7df2e56Smrg 908f7df2e56Smrg /* scale x&y to desktop coordinates */ 909f7df2e56Smrg *screenx = rescaleValuatorAxis(x, dev->valuator->axes + 0, NULL, 910f7df2e56Smrg screenInfo.x, screenInfo.width); 911f7df2e56Smrg *screeny = rescaleValuatorAxis(y, dev->valuator->axes + 1, NULL, 912f7df2e56Smrg screenInfo.y, screenInfo.height); 913f7df2e56Smrg 914f7df2e56Smrg *devx = x; 915f7df2e56Smrg *devy = y; 916f7df2e56Smrg 917f7df2e56Smrg return scr; 9184642e01fSmrg} 9194642e01fSmrg 9204642e01fSmrg/** 9214642e01fSmrg * If we have HW cursors, this actually moves the visible sprite. If not, we 9224642e01fSmrg * just do all the screen crossing, etc. 9234642e01fSmrg * 924f7df2e56Smrg * We use the screen coordinates here, call miPointerSetPosition() and then 925f7df2e56Smrg * scale back into device coordinates (if needed). miPSP will change x/y if 926f7df2e56Smrg * the screen was crossed. 927f7df2e56Smrg * 928f7df2e56Smrg * The coordinates provided are always absolute. The parameter mode 929f7df2e56Smrg * specifies whether it was relative or absolute movement that landed us at 930f7df2e56Smrg * those coordinates. see fill_pointer_events for information on coordinate 931f7df2e56Smrg * systems. 9324642e01fSmrg * 9334642e01fSmrg * @param dev The device to be moved. 934f7df2e56Smrg * @param mode Movement mode (Absolute or Relative) 935f7df2e56Smrg * @param[out] mask Mask of axis values for this event, returns the 936f7df2e56Smrg * per-screen device coordinates after confinement 937f7df2e56Smrg * @param[in,out] devx x desktop-wide coordinate in device coordinate system 938f7df2e56Smrg * @param[in,out] devy y desktop-wide coordinate in device coordinate system 939f7df2e56Smrg * @param[in,out] screenx x coordinate in desktop coordinate system 940f7df2e56Smrg * @param[in,out] screeny y coordinate in desktop coordinate system 941f7df2e56Smrg * @param[out] nevents Number of barrier events added to events 942f7df2e56Smrg * @param[in,out] events List of events barrier events are added to 9434642e01fSmrg */ 944f7df2e56Smrgstatic ScreenPtr 945f7df2e56SmrgpositionSprite(DeviceIntPtr dev, int mode, ValuatorMask *mask, 946f7df2e56Smrg double *devx, double *devy, double *screenx, double *screeny, 947f7df2e56Smrg int *nevents, InternalEvent* events) 9484642e01fSmrg{ 949f7df2e56Smrg ScreenPtr scr = miPointerGetScreen(dev); 950f7df2e56Smrg double tmpx, tmpy; 9514202a189Smrg 952f7df2e56Smrg if (!dev->valuator || dev->valuator->numAxes < 2) 953f7df2e56Smrg return scr; 9544202a189Smrg 955f7df2e56Smrg tmpx = *screenx; 956f7df2e56Smrg tmpy = *screeny; 9574202a189Smrg 958f7df2e56Smrg /* miPointerSetPosition takes care of crossing screens for us, as well as 959f7df2e56Smrg * clipping to the current screen. Coordinates returned are in desktop 960f7df2e56Smrg * coord system */ 961f7df2e56Smrg scr = miPointerSetPosition(dev, mode, screenx, screeny, nevents, events); 962f7df2e56Smrg 963f7df2e56Smrg /* If we were constrained, rescale x/y from the screen coordinates so 964f7df2e56Smrg * the device valuators reflect the correct position. For screen 965f7df2e56Smrg * crossing this doesn't matter much, the coords would be 0 or max. 966f7df2e56Smrg */ 967f7df2e56Smrg if (tmpx != *screenx) 968f7df2e56Smrg *devx = rescaleValuatorAxis(*screenx, NULL, dev->valuator->axes + 0, 969f7df2e56Smrg screenInfo.x, screenInfo.width); 9704642e01fSmrg 971f7df2e56Smrg if (tmpy != *screeny) 972f7df2e56Smrg *devy = rescaleValuatorAxis(*screeny, NULL, dev->valuator->axes + 1, 973f7df2e56Smrg screenInfo.y, screenInfo.height); 9744642e01fSmrg 975f7df2e56Smrg /* Recalculate the per-screen device coordinates */ 976f7df2e56Smrg if (valuator_mask_isset(mask, 0)) { 977f7df2e56Smrg double x; 978f7df2e56Smrg 979f7df2e56Smrg x = rescaleValuatorAxis(*screenx - scr->x, NULL, 980f7df2e56Smrg dev->valuator->axes + 0, 0, scr->width); 981f7df2e56Smrg valuator_mask_set_double(mask, 0, x); 9824642e01fSmrg } 983f7df2e56Smrg if (valuator_mask_isset(mask, 1)) { 984f7df2e56Smrg double y; 9854642e01fSmrg 986f7df2e56Smrg y = rescaleValuatorAxis(*screeny - scr->y, NULL, 987f7df2e56Smrg dev->valuator->axes + 1, 0, scr->height); 988f7df2e56Smrg valuator_mask_set_double(mask, 1, y); 9894642e01fSmrg } 9904642e01fSmrg 991f7df2e56Smrg return scr; 9924642e01fSmrg} 9934642e01fSmrg 9944642e01fSmrg/** 9954642e01fSmrg * Update the motion history for the device and (if appropriate) for its 9964642e01fSmrg * master device. 9974642e01fSmrg * @param dev Slave device to update. 99865b04b38Smrg * @param mask Bit mask of valid valuators to append to history. 9994642e01fSmrg * @param num Total number of valuators to append to history. 10004642e01fSmrg * @param ms Current time 10014642e01fSmrg */ 10024642e01fSmrgstatic void 100365b04b38SmrgupdateHistory(DeviceIntPtr dev, ValuatorMask *mask, CARD32 ms) 10044642e01fSmrg{ 100565b04b38Smrg if (!dev->valuator) 100665b04b38Smrg return; 100765b04b38Smrg 100865b04b38Smrg updateMotionHistory(dev, ms, mask, dev->last.valuators); 1009f7df2e56Smrg if (!IsMaster(dev) && !IsFloating(dev)) { 10104202a189Smrg DeviceIntPtr master = GetMaster(dev, MASTER_POINTER); 1011f7df2e56Smrg 101265b04b38Smrg updateMotionHistory(master, ms, mask, dev->last.valuators); 10134202a189Smrg } 10144642e01fSmrg} 101505b261ecSmrg 1016f7df2e56Smrgstatic void 1017f7df2e56SmrgqueueEventList(DeviceIntPtr device, InternalEvent *events, int nevents) 1018f7df2e56Smrg{ 1019f7df2e56Smrg int i; 1020f7df2e56Smrg 1021f7df2e56Smrg for (i = 0; i < nevents; i++) 1022f7df2e56Smrg mieqEnqueue(device, &events[i]); 1023f7df2e56Smrg} 1024f7df2e56Smrg 1025f7df2e56Smrgstatic void 1026f7df2e56Smrgevent_set_root_coordinates(DeviceEvent *event, double x, double y) 1027f7df2e56Smrg{ 1028f7df2e56Smrg event->root_x = trunc(x); 1029f7df2e56Smrg event->root_y = trunc(y); 1030f7df2e56Smrg event->root_x_frac = x - trunc(x); 1031f7df2e56Smrg event->root_y_frac = y - trunc(y); 1032f7df2e56Smrg} 1033f7df2e56Smrg 103405b261ecSmrg/** 1035f7df2e56Smrg * Generate internal events representing this keyboard event and enqueue 1036f7df2e56Smrg * them on the event queue. 1037f7df2e56Smrg * 1038f7df2e56Smrg * This function is not reentrant. Disable signals before calling. 1039f7df2e56Smrg * 1040f7df2e56Smrg * @param device The device to generate the event for 1041f7df2e56Smrg * @param type Event type, one of KeyPress or KeyRelease 1042f7df2e56Smrg * @param keycode Key code of the pressed/released key 1043f7df2e56Smrg * 104405b261ecSmrg */ 1045f7df2e56Smrgvoid 1046f7df2e56SmrgQueueKeyboardEvents(DeviceIntPtr device, int type, 1047f7df2e56Smrg int keycode) 1048f7df2e56Smrg{ 1049f7df2e56Smrg int nevents; 105065b04b38Smrg 1051f7df2e56Smrg nevents = GetKeyboardEvents(InputEventList, device, type, keycode); 1052f7df2e56Smrg queueEventList(device, InputEventList, nevents); 105305b261ecSmrg} 105405b261ecSmrg 105505b261ecSmrg/** 105665b04b38Smrg * Returns a set of InternalEvents for KeyPress/KeyRelease, optionally 105765b04b38Smrg * also with valuator events. 10584642e01fSmrg * 1059f7df2e56Smrg * The DDX is responsible for allocating the event list in the first 1060f7df2e56Smrg * place via InitEventList(), and for freeing it. 1061f7df2e56Smrg * 1062f7df2e56Smrg * @return the number of events written into events. 106305b261ecSmrg */ 10644202a189Smrgint 1065f7df2e56SmrgGetKeyboardEvents(InternalEvent *events, DeviceIntPtr pDev, int type, 1066f7df2e56Smrg int key_code) 1067f7df2e56Smrg{ 10684202a189Smrg int num_events = 0; 106905b261ecSmrg CARD32 ms = 0; 10704202a189Smrg DeviceEvent *event; 10714202a189Smrg RawDeviceEvent *raw; 10727e31ba66Smrg enum DeviceEventSource source_type = EVENT_SOURCE_NORMAL; 1073f7df2e56Smrg 10745a112b11Smrg#ifdef XSERVER_DTRACE 1075f7df2e56Smrg if (XSERVER_INPUT_EVENT_ENABLED()) { 1076f7df2e56Smrg XSERVER_INPUT_EVENT(pDev->id, type, key_code, 0, 0, 1077f7df2e56Smrg NULL, NULL); 1078f7df2e56Smrg } 1079f7df2e56Smrg#endif 10804202a189Smrg 10817e31ba66Smrg if (type == EnterNotify) { 10827e31ba66Smrg source_type = EVENT_SOURCE_FOCUS; 10837e31ba66Smrg type = KeyPress; 10847e31ba66Smrg } else if (type == LeaveNotify) { 10857e31ba66Smrg source_type = EVENT_SOURCE_FOCUS; 10867e31ba66Smrg type = KeyRelease; 10877e31ba66Smrg } 10887e31ba66Smrg 10894202a189Smrg /* refuse events from disabled devices */ 10904202a189Smrg if (!pDev->enabled) 10914202a189Smrg return 0; 109205b261ecSmrg 1093f7df2e56Smrg if (!events || !pDev->key || !pDev->focus || !pDev->kbdfeed || 1094f7df2e56Smrg (type != KeyPress && type != KeyRelease) || 1095f7df2e56Smrg (key_code < 8 || key_code > 255)) 109605b261ecSmrg return 0; 109705b261ecSmrg 10984202a189Smrg num_events = 1; 109905b261ecSmrg 1100f7df2e56Smrg events = 1101f7df2e56Smrg UpdateFromMaster(events, pDev, DEVCHANGE_KEYBOARD_EVENT, &num_events); 110205b261ecSmrg 11034202a189Smrg /* Handle core repeating, via press/release/press/release. */ 11044202a189Smrg if (type == KeyPress && key_is_down(pDev, key_code, KEY_POSTED)) { 110505b261ecSmrg /* If autorepeating is disabled either globally or just for that key, 110605b261ecSmrg * or we have a modifier, don't generate a repeat event. */ 110705b261ecSmrg if (!pDev->kbdfeed->ctrl.autoRepeat || 110805b261ecSmrg !key_autorepeats(pDev, key_code) || 11094202a189Smrg pDev->key->xkbInfo->desc->map->modmap[key_code]) 111005b261ecSmrg return 0; 111105b261ecSmrg } 111205b261ecSmrg 111305b261ecSmrg ms = GetTimeInMillis(); 111405b261ecSmrg 11157e31ba66Smrg if (source_type == EVENT_SOURCE_NORMAL) { 11167e31ba66Smrg raw = &events->raw_event; 11177e31ba66Smrg init_raw(pDev, raw, ms, type, key_code); 11187e31ba66Smrg events++; 11197e31ba66Smrg num_events++; 11207e31ba66Smrg } 11214202a189Smrg 1122f7df2e56Smrg event = &events->device_event; 11237e31ba66Smrg init_device_event(event, pDev, ms, source_type); 11244202a189Smrg event->detail.key = key_code; 11254202a189Smrg 112605b261ecSmrg if (type == KeyPress) { 11274202a189Smrg event->type = ET_KeyPress; 1128f7df2e56Smrg set_key_down(pDev, key_code, KEY_POSTED); 112905b261ecSmrg } 113005b261ecSmrg else if (type == KeyRelease) { 11314202a189Smrg event->type = ET_KeyRelease; 1132f7df2e56Smrg set_key_up(pDev, key_code, KEY_POSTED); 113305b261ecSmrg } 113405b261ecSmrg 11354202a189Smrg return num_events; 113605b261ecSmrg} 113705b261ecSmrg 11384642e01fSmrg/** 1139f7df2e56Smrg * Initialize an event array large enough for num_events arrays. 11404642e01fSmrg * This event list is to be passed into GetPointerEvents() and 11414642e01fSmrg * GetKeyboardEvents(). 11424642e01fSmrg * 11434642e01fSmrg * @param num_events Number of elements in list. 11444642e01fSmrg */ 1145f7df2e56SmrgInternalEvent * 11464642e01fSmrgInitEventList(int num_events) 11474642e01fSmrg{ 1148f7df2e56Smrg InternalEvent *events = calloc(num_events, sizeof(InternalEvent)); 11494642e01fSmrg 11504642e01fSmrg return events; 11514642e01fSmrg} 11524642e01fSmrg 11534642e01fSmrg/** 11544642e01fSmrg * Free an event list. 11554642e01fSmrg * 11564642e01fSmrg * @param list The list to be freed. 11574642e01fSmrg * @param num_events Number of elements in list. 11584642e01fSmrg */ 11594202a189Smrgvoid 1160f7df2e56SmrgFreeEventList(InternalEvent *list, int num_events) 11614642e01fSmrg{ 11624202a189Smrg free(list); 11634202a189Smrg} 11644202a189Smrg 1165f7df2e56Smrg/** 1166f7df2e56Smrg * Transform vector x/y according to matrix m and drop the rounded coords 1167f7df2e56Smrg * back into x/y. 1168f7df2e56Smrg */ 1169f7df2e56Smrgstatic void 1170f7df2e56Smrgtransform(struct pixman_f_transform *m, double *x, double *y) 1171f7df2e56Smrg{ 1172f7df2e56Smrg struct pixman_f_vector p = {.v = {*x, *y, 1} }; 1173f7df2e56Smrg pixman_f_transform_point(m, &p); 1174f7df2e56Smrg 1175f7df2e56Smrg *x = p.v[0]; 1176f7df2e56Smrg *y = p.v[1]; 1177f7df2e56Smrg} 1178f7df2e56Smrg 1179f7df2e56Smrgstatic void 1180f7df2e56SmrgtransformRelative(DeviceIntPtr dev, ValuatorMask *mask) 1181f7df2e56Smrg{ 1182f7df2e56Smrg double x = 0, y = 0; 1183f7df2e56Smrg 1184f7df2e56Smrg valuator_mask_fetch_double(mask, 0, &x); 1185f7df2e56Smrg valuator_mask_fetch_double(mask, 1, &y); 1186f7df2e56Smrg 1187f7df2e56Smrg transform(&dev->relative_transform, &x, &y); 1188f7df2e56Smrg 1189f7df2e56Smrg if (x) 1190f7df2e56Smrg valuator_mask_set_double(mask, 0, x); 1191f7df2e56Smrg else 1192f7df2e56Smrg valuator_mask_unset(mask, 0); 1193f7df2e56Smrg 1194f7df2e56Smrg if (y) 1195f7df2e56Smrg valuator_mask_set_double(mask, 1, y); 1196f7df2e56Smrg else 1197f7df2e56Smrg valuator_mask_unset(mask, 1); 1198f7df2e56Smrg} 1199f7df2e56Smrg 1200f7df2e56Smrg/** 1201f7df2e56Smrg * Apply the device's transformation matrix to the valuator mask and replace 1202f7df2e56Smrg * the scaled values in mask. This transformation only applies to valuators 1203f7df2e56Smrg * 0 and 1, others will be untouched. 1204f7df2e56Smrg * 1205f7df2e56Smrg * @param dev The device the valuators came from 1206f7df2e56Smrg * @param[in,out] mask The valuator mask. 1207f7df2e56Smrg */ 12084202a189Smrgstatic void 120965b04b38SmrgtransformAbsolute(DeviceIntPtr dev, ValuatorMask *mask) 12104202a189Smrg{ 12117e31ba66Smrg double x, y, ox = 0.0, oy = 0.0; 1212f7df2e56Smrg int has_x, has_y; 12134202a189Smrg 1214f7df2e56Smrg has_x = valuator_mask_isset(mask, 0); 1215f7df2e56Smrg has_y = valuator_mask_isset(mask, 1); 12164202a189Smrg 1217f7df2e56Smrg if (!has_x && !has_y) 1218f7df2e56Smrg return; 12194202a189Smrg 1220f7df2e56Smrg if (!has_x || !has_y) { 1221f7df2e56Smrg struct pixman_f_transform invert; 1222f7df2e56Smrg 1223f7df2e56Smrg /* undo transformation from last event */ 1224f7df2e56Smrg ox = dev->last.valuators[0]; 1225f7df2e56Smrg oy = dev->last.valuators[1]; 1226f7df2e56Smrg 1227f7df2e56Smrg pixman_f_transform_invert(&invert, &dev->scale_and_transform); 1228f7df2e56Smrg transform(&invert, &ox, &oy); 1229f7df2e56Smrg } 1230f7df2e56Smrg 1231f7df2e56Smrg if (has_x) 1232f7df2e56Smrg ox = valuator_mask_get_double(mask, 0); 1233f7df2e56Smrg 1234f7df2e56Smrg if (has_y) 1235f7df2e56Smrg oy = valuator_mask_get_double(mask, 1); 1236f7df2e56Smrg 1237f7df2e56Smrg x = ox; 1238f7df2e56Smrg y = oy; 1239f7df2e56Smrg 1240f7df2e56Smrg transform(&dev->scale_and_transform, &x, &y); 1241f7df2e56Smrg 1242f7df2e56Smrg if (has_x || ox != x) 1243f7df2e56Smrg valuator_mask_set_double(mask, 0, x); 1244f7df2e56Smrg 1245f7df2e56Smrg if (has_y || oy != y) 1246f7df2e56Smrg valuator_mask_set_double(mask, 1, y); 1247f7df2e56Smrg} 1248f7df2e56Smrg 1249f7df2e56Smrgstatic void 1250f7df2e56SmrgstoreLastValuators(DeviceIntPtr dev, ValuatorMask *mask, 1251f7df2e56Smrg int xaxis, int yaxis, double devx, double devy) 1252f7df2e56Smrg{ 1253f7df2e56Smrg int i; 1254f7df2e56Smrg 1255f7df2e56Smrg /* store desktop-wide in last.valuators */ 1256f7df2e56Smrg if (valuator_mask_isset(mask, xaxis)) 1257f7df2e56Smrg dev->last.valuators[0] = devx; 1258f7df2e56Smrg if (valuator_mask_isset(mask, yaxis)) 1259f7df2e56Smrg dev->last.valuators[1] = devy; 1260f7df2e56Smrg 1261f7df2e56Smrg for (i = 0; i < valuator_mask_size(mask); i++) { 1262f7df2e56Smrg if (i == xaxis || i == yaxis) 1263f7df2e56Smrg continue; 1264f7df2e56Smrg 1265f7df2e56Smrg if (valuator_mask_isset(mask, i)) 1266f7df2e56Smrg dev->last.valuators[i] = valuator_mask_get_double(mask, i); 1267f7df2e56Smrg } 126845bb0b75Smrg 12694642e01fSmrg} 127005b261ecSmrg 127105b261ecSmrg/** 1272f7df2e56Smrg * Generate internal events representing this pointer event and enqueue them 1273f7df2e56Smrg * on the event queue. 127405b261ecSmrg * 1275f7df2e56Smrg * This function is not reentrant. Disable signals before calling. 12764642e01fSmrg * 1277f7df2e56Smrg * @param device The device to generate the event for 1278f7df2e56Smrg * @param type Event type, one of ButtonPress, ButtonRelease, MotionNotify 1279f7df2e56Smrg * @param buttons Button number of the buttons modified. Must be 0 for 1280f7df2e56Smrg * MotionNotify 1281f7df2e56Smrg * @param flags Event modification flags 1282f7df2e56Smrg * @param mask Valuator mask for valuators present for this event. 1283f7df2e56Smrg */ 1284f7df2e56Smrgvoid 1285f7df2e56SmrgQueuePointerEvents(DeviceIntPtr device, int type, 1286f7df2e56Smrg int buttons, int flags, const ValuatorMask *mask) 1287f7df2e56Smrg{ 1288f7df2e56Smrg int nevents; 1289f7df2e56Smrg 1290f7df2e56Smrg nevents = 1291f7df2e56Smrg GetPointerEvents(InputEventList, device, type, buttons, flags, mask); 1292f7df2e56Smrg queueEventList(device, InputEventList, nevents); 1293f7df2e56Smrg} 1294f7df2e56Smrg 1295f7df2e56Smrg/** 1296f7df2e56Smrg * Helper function for GetPointerEvents, which only generates motion and 1297f7df2e56Smrg * raw motion events for the slave device: does not update the master device. 12984642e01fSmrg * 1299f7df2e56Smrg * Should not be called by anyone other than GetPointerEvents. 13004642e01fSmrg * 1301f7df2e56Smrg * We use several different coordinate systems and need to switch between 1302f7df2e56Smrg * the three in fill_pointer_events, positionSprite and 1303f7df2e56Smrg * miPointerSetPosition. "desktop" refers to the width/height of all 1304f7df2e56Smrg * screenInfo.screens[n]->width/height added up. "screen" is ScreenRec, not 1305f7df2e56Smrg * output. 1306f7df2e56Smrg * 1307f7df2e56Smrg * Coordinate systems: 1308f7df2e56Smrg * - relative events have a mask_in in relative coordinates, mapped to 1309f7df2e56Smrg * pixels. These events are mapped to the current position±delta. 1310f7df2e56Smrg * - absolute events have a mask_in in absolute device coordinates in 1311f7df2e56Smrg * device-specific range. This range is mapped to the desktop. 1312f7df2e56Smrg * - POINTER_SCREEN absolute events (x86WarpCursor) are in screen-relative 1313f7df2e56Smrg * screen coordinate range. 1314f7df2e56Smrg * - rootx/rooty in events must be be relative to the current screen's 1315f7df2e56Smrg * origin (screen coordinate system) 1316f7df2e56Smrg * - XI2 valuators must be relative to the current screen's origin. On 1317f7df2e56Smrg * the protocol the device min/max range maps to the current screen. 1318f7df2e56Smrg * 1319f7df2e56Smrg * For screen switching we need to get the desktop coordinates for each 1320f7df2e56Smrg * event, then map that to the respective position on each screen and 1321f7df2e56Smrg * position the cursor there. 1322f7df2e56Smrg * The device's last.valuator[] stores the last position in desktop-wide 1323f7df2e56Smrg * coordinates (in device range for slave devices, desktop range for master 1324f7df2e56Smrg * devices). 1325f7df2e56Smrg * 1326f7df2e56Smrg * screen-relative device coordinates requires scaling: A device coordinate 1327f7df2e56Smrg * x/y of range [n..m] that maps to positions Sx/Sy on Screen S must be 1328f7df2e56Smrg * rescaled to match Sx/Sy for [n..m]. In the simplest example, x of (m/2-1) 1329f7df2e56Smrg * is the last coordinate on the first screen and must be rescaled for the 1330f7df2e56Smrg * event to be m. XI2 clients that do their own coordinate mapping would 13315a112b11Smrg * otherwise interpret the position of the device elsewhere to the cursor. 1332f7df2e56Smrg * However, this scaling leads to losses: 1333f7df2e56Smrg * if we have two ScreenRecs we scale from e.g. [0..44704] (Wacom I4) to 1334f7df2e56Smrg * [0..2048[. that gives us 2047.954 as desktop coord, or the per-screen 1335f7df2e56Smrg * coordinate 1023.954. Scaling that back into the device coordinate range 1336f7df2e56Smrg * gives us 44703. So off by one device unit. It's a bug, but we'll have to 1337f7df2e56Smrg * live with it because with all this scaling, we just cannot win. 1338f7df2e56Smrg * 1339f7df2e56Smrg * @return the number of events written into events. 134005b261ecSmrg */ 1341f7df2e56Smrgstatic int 1342f7df2e56Smrgfill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type, 1343f7df2e56Smrg int buttons, CARD32 ms, int flags, 1344f7df2e56Smrg const ValuatorMask *mask_in) 1345f7df2e56Smrg{ 13465a112b11Smrg int num_events = 0; 13474202a189Smrg DeviceEvent *event; 1348f7df2e56Smrg RawDeviceEvent *raw = NULL; 1349f7df2e56Smrg double screenx = 0.0, screeny = 0.0; /* desktop coordinate system */ 1350f7df2e56Smrg double devx = 0.0, devy = 0.0; /* desktop-wide in device coords */ 1351f7df2e56Smrg int sx = 0, sy = 0; /* for POINTER_SCREEN */ 135265b04b38Smrg ValuatorMask mask; 1353f7df2e56Smrg ScreenPtr scr; 1354f7df2e56Smrg int num_barrier_events = 0; 1355f7df2e56Smrg 1356f7df2e56Smrg switch (type) { 1357f7df2e56Smrg case MotionNotify: 1358f7df2e56Smrg if (!pDev->valuator) { 1359f7df2e56Smrg ErrorF("[dix] motion events from device %d without valuators\n", 1360f7df2e56Smrg pDev->id); 1361f7df2e56Smrg return 0; 1362f7df2e56Smrg } 1363f7df2e56Smrg if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0) 1364f7df2e56Smrg return 0; 1365f7df2e56Smrg break; 1366f7df2e56Smrg case ButtonPress: 1367f7df2e56Smrg case ButtonRelease: 1368f7df2e56Smrg if (!pDev->button || !buttons) 1369f7df2e56Smrg return 0; 1370f7df2e56Smrg if (mask_in && valuator_mask_size(mask_in) > 0 && !pDev->valuator) { 1371f7df2e56Smrg ErrorF 1372f7df2e56Smrg ("[dix] button event with valuator from device %d without valuators\n", 1373f7df2e56Smrg pDev->id); 1374f7df2e56Smrg return 0; 1375f7df2e56Smrg } 1376f7df2e56Smrg break; 1377f7df2e56Smrg default: 13784202a189Smrg return 0; 1379f7df2e56Smrg } 138005b261ecSmrg 1381f7df2e56Smrg valuator_mask_copy(&mask, mask_in); 138205b261ecSmrg 1383f7df2e56Smrg if ((flags & POINTER_NORAW) == 0) { 1384f7df2e56Smrg raw = &events->raw_event; 1385f7df2e56Smrg events++; 1386f7df2e56Smrg num_events++; 1387f7df2e56Smrg 1388f7df2e56Smrg init_raw(pDev, raw, ms, type, buttons); 13895a112b11Smrg 13905a112b11Smrg if (flags & POINTER_EMULATED) 13915a112b11Smrg raw->flags = XIPointerEmulated; 13925a112b11Smrg 1393f7df2e56Smrg set_raw_valuators(raw, &mask, TRUE, raw->valuators.data_raw); 139465b04b38Smrg } 139565b04b38Smrg 1396f7df2e56Smrg valuator_mask_drop_unaccelerated(&mask); 139765b04b38Smrg 1398f7df2e56Smrg /* valuators are in driver-native format (rel or abs) */ 13994202a189Smrg 1400f7df2e56Smrg if (flags & POINTER_ABSOLUTE) { 1401f7df2e56Smrg if (flags & (POINTER_SCREEN | POINTER_DESKTOP)) { /* valuators are in screen/desktop coords */ 1402f7df2e56Smrg sx = valuator_mask_get(&mask, 0); 1403f7df2e56Smrg sy = valuator_mask_get(&mask, 1); 1404f7df2e56Smrg scale_from_screen(pDev, &mask, flags); 1405f7df2e56Smrg } 14064202a189Smrg 1407f7df2e56Smrg transformAbsolute(pDev, &mask); 1408f7df2e56Smrg clipAbsolute(pDev, &mask); 1409f7df2e56Smrg if ((flags & POINTER_NORAW) == 0 && raw) 1410f7df2e56Smrg set_raw_valuators(raw, &mask, FALSE, raw->valuators.data); 1411f7df2e56Smrg } 1412f7df2e56Smrg else { 1413f7df2e56Smrg transformRelative(pDev, &mask); 1414f7df2e56Smrg 1415f7df2e56Smrg if (flags & POINTER_ACCELERATE) 1416f7df2e56Smrg accelPointer(pDev, &mask, ms); 1417f7df2e56Smrg if ((flags & POINTER_NORAW) == 0 && raw) 1418f7df2e56Smrg set_raw_valuators(raw, &mask, FALSE, raw->valuators.data); 141945bb0b75Smrg 1420f7df2e56Smrg moveRelative(pDev, flags, &mask); 142145bb0b75Smrg } 142205b261ecSmrg 1423f7df2e56Smrg /* valuators are in device coordinate system in absolute coordinates */ 1424f7df2e56Smrg scale_to_desktop(pDev, &mask, &devx, &devy, &screenx, &screeny); 142505b261ecSmrg 1426f7df2e56Smrg /* #53037 XWarpPointer's scaling back and forth between screen and 1427f7df2e56Smrg device may leave us with rounding errors. End result is that the 1428f7df2e56Smrg pointer doesn't end up on the pixel it should. 1429f7df2e56Smrg Avoid this by forcing screenx/screeny back to what the input 1430f7df2e56Smrg coordinates were. 1431f7df2e56Smrg */ 1432f7df2e56Smrg if (flags & POINTER_SCREEN) { 1433f7df2e56Smrg scr = miPointerGetScreen(pDev); 1434f7df2e56Smrg screenx = sx + scr->x; 1435f7df2e56Smrg screeny = sy + scr->y; 143605b261ecSmrg } 143705b261ecSmrg 1438f7df2e56Smrg scr = positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative, 1439f7df2e56Smrg &mask, &devx, &devy, &screenx, &screeny, 1440f7df2e56Smrg &num_barrier_events, events); 1441f7df2e56Smrg num_events += num_barrier_events; 1442f7df2e56Smrg events += num_barrier_events; 144305b261ecSmrg 1444f7df2e56Smrg /* screenx, screeny are in desktop coordinates, 1445f7df2e56Smrg mask is in device coordinates per-screen (the event data) 1446f7df2e56Smrg devx/devy is in device coordinate desktop-wide */ 144765b04b38Smrg updateHistory(pDev, &mask, ms); 144805b261ecSmrg 144965b04b38Smrg clipValuators(pDev, &mask); 14504202a189Smrg 1451f7df2e56Smrg storeLastValuators(pDev, &mask, 0, 1, devx, devy); 1452f7df2e56Smrg 14535a112b11Smrg /* Update the MD's coordinates, which are always in desktop space. */ 1454f7df2e56Smrg if (!IsMaster(pDev) && !IsFloating(pDev)) { 1455f7df2e56Smrg DeviceIntPtr master = GetMaster(pDev, MASTER_POINTER); 1456f7df2e56Smrg 1457f7df2e56Smrg master->last.valuators[0] = screenx; 1458f7df2e56Smrg master->last.valuators[1] = screeny; 1459f7df2e56Smrg } 1460f7df2e56Smrg 14615a112b11Smrg if ((flags & POINTER_RAWONLY) == 0) { 14625a112b11Smrg num_events++; 146305b261ecSmrg 14645a112b11Smrg event = &events->device_event; 14655a112b11Smrg init_device_event(event, pDev, ms, EVENT_SOURCE_NORMAL); 14665a112b11Smrg 14675a112b11Smrg if (type == MotionNotify) { 14685a112b11Smrg event->type = ET_Motion; 14695a112b11Smrg event->detail.button = 0; 14704202a189Smrg } 14715a112b11Smrg else { 14725a112b11Smrg if (type == ButtonPress) { 14735a112b11Smrg event->type = ET_ButtonPress; 14745a112b11Smrg set_button_down(pDev, buttons, BUTTON_POSTED); 14755a112b11Smrg } 14765a112b11Smrg else if (type == ButtonRelease) { 14775a112b11Smrg event->type = ET_ButtonRelease; 14785a112b11Smrg set_button_up(pDev, buttons, BUTTON_POSTED); 14795a112b11Smrg } 14805a112b11Smrg event->detail.button = buttons; 14814202a189Smrg } 148205b261ecSmrg 14835a112b11Smrg /* root_x and root_y must be in per-screen coordinates */ 14845a112b11Smrg event_set_root_coordinates(event, screenx - scr->x, screeny - scr->y); 1485f7df2e56Smrg 14865a112b11Smrg if (flags & POINTER_EMULATED) 14875a112b11Smrg event->flags = XIPointerEmulated; 148805b261ecSmrg 14895a112b11Smrg set_valuators(pDev, event, &mask); 14905a112b11Smrg } 149105b261ecSmrg 149205b261ecSmrg return num_events; 149305b261ecSmrg} 149405b261ecSmrg 1495f7df2e56Smrg/** 1496f7df2e56Smrg * Generate events for each scroll axis that changed between before/after 1497f7df2e56Smrg * for the device. 1498f7df2e56Smrg * 1499f7df2e56Smrg * @param events The pointer to the event list to fill the events 1500f7df2e56Smrg * @param dev The device to generate the events for 1501f7df2e56Smrg * @param type The real type of the event 1502f7df2e56Smrg * @param axis The axis number to generate events for 1503f7df2e56Smrg * @param mask State before this event in absolute coords 1504f7df2e56Smrg * @param[in,out] last Last scroll state posted in absolute coords (modified 1505f7df2e56Smrg * in-place) 1506f7df2e56Smrg * @param ms Current time in ms 1507f7df2e56Smrg * @param max_events Max number of events to be generated 1508f7df2e56Smrg * @return The number of events generated 1509f7df2e56Smrg */ 1510f7df2e56Smrgstatic int 1511f7df2e56Smrgemulate_scroll_button_events(InternalEvent *events, 1512f7df2e56Smrg DeviceIntPtr dev, 1513f7df2e56Smrg int type, 1514f7df2e56Smrg int axis, 1515f7df2e56Smrg const ValuatorMask *mask, 1516f7df2e56Smrg ValuatorMask *last, CARD32 ms, int max_events) 1517f7df2e56Smrg{ 1518f7df2e56Smrg AxisInfoPtr ax; 1519f7df2e56Smrg double delta; 1520f7df2e56Smrg double incr; 1521f7df2e56Smrg int num_events = 0; 1522f7df2e56Smrg double total; 1523f7df2e56Smrg int b; 1524f7df2e56Smrg int flags = 0; 1525f7df2e56Smrg 1526f7df2e56Smrg if (dev->valuator->axes[axis].scroll.type == SCROLL_TYPE_NONE) 1527f7df2e56Smrg return 0; 1528f7df2e56Smrg 1529f7df2e56Smrg if (!valuator_mask_isset(mask, axis)) 1530f7df2e56Smrg return 0; 1531f7df2e56Smrg 1532f7df2e56Smrg ax = &dev->valuator->axes[axis]; 1533f7df2e56Smrg incr = ax->scroll.increment; 1534f7df2e56Smrg 1535f7df2e56Smrg BUG_WARN_MSG(incr == 0, "for device %s\n", dev->name); 1536f7df2e56Smrg if (incr == 0) 1537f7df2e56Smrg return 0; 1538f7df2e56Smrg 1539f7df2e56Smrg if (type != ButtonPress && type != ButtonRelease) 1540f7df2e56Smrg flags |= POINTER_EMULATED; 1541f7df2e56Smrg 1542f7df2e56Smrg if (!valuator_mask_isset(last, axis)) 1543f7df2e56Smrg valuator_mask_set_double(last, axis, 0); 1544f7df2e56Smrg 1545f7df2e56Smrg delta = 1546f7df2e56Smrg valuator_mask_get_double(mask, axis) - valuator_mask_get_double(last, 1547f7df2e56Smrg axis); 1548f7df2e56Smrg total = delta; 1549f7df2e56Smrg b = (ax->scroll.type == SCROLL_TYPE_VERTICAL) ? 5 : 7; 1550f7df2e56Smrg 1551f7df2e56Smrg if ((incr > 0 && delta < 0) || (incr < 0 && delta > 0)) 1552f7df2e56Smrg b--; /* we're scrolling up or left → button 4 or 6 */ 1553f7df2e56Smrg 1554f7df2e56Smrg while (fabs(delta) >= fabs(incr)) { 1555f7df2e56Smrg int nev_tmp; 1556f7df2e56Smrg 1557f7df2e56Smrg if (delta > 0) 1558f7df2e56Smrg delta -= fabs(incr); 1559f7df2e56Smrg else if (delta < 0) 1560f7df2e56Smrg delta += fabs(incr); 1561f7df2e56Smrg 1562f7df2e56Smrg /* fill_pointer_events() generates four events: one normal and one raw 1563f7df2e56Smrg * event for button press and button release. 1564f7df2e56Smrg * We may get a bigger scroll delta than we can generate events 1565f7df2e56Smrg * for. In that case, we keep decreasing delta, but skip events. 1566f7df2e56Smrg */ 1567f7df2e56Smrg if (num_events + 4 < max_events) { 1568f7df2e56Smrg if (type != ButtonRelease) { 1569f7df2e56Smrg nev_tmp = fill_pointer_events(events, dev, ButtonPress, b, ms, 1570f7df2e56Smrg flags, NULL); 1571f7df2e56Smrg events += nev_tmp; 1572f7df2e56Smrg num_events += nev_tmp; 1573f7df2e56Smrg } 1574f7df2e56Smrg if (type != ButtonPress) { 1575f7df2e56Smrg nev_tmp = fill_pointer_events(events, dev, ButtonRelease, b, ms, 1576f7df2e56Smrg flags, NULL); 1577f7df2e56Smrg events += nev_tmp; 1578f7df2e56Smrg num_events += nev_tmp; 1579f7df2e56Smrg } 1580f7df2e56Smrg } 1581f7df2e56Smrg } 1582f7df2e56Smrg 1583f7df2e56Smrg /* We emulated, update last.scroll */ 1584f7df2e56Smrg if (total != delta) { 1585f7df2e56Smrg total -= delta; 1586f7df2e56Smrg valuator_mask_set_double(last, axis, 1587f7df2e56Smrg valuator_mask_get_double(last, axis) + total); 1588f7df2e56Smrg } 1589f7df2e56Smrg 1590f7df2e56Smrg return num_events; 1591f7df2e56Smrg} 1592f7df2e56Smrg 159305b261ecSmrg 159405b261ecSmrg/** 1595f7df2e56Smrg * Generate a complete series of InternalEvents (filled into the EventList) 1596f7df2e56Smrg * representing pointer motion, or button presses. If the device is a slave 1597f7df2e56Smrg * device, also potentially generate a DeviceClassesChangedEvent to update 1598f7df2e56Smrg * the master device. 159905b261ecSmrg * 160005b261ecSmrg * events is not NULL-terminated; the return value is the number of events. 160105b261ecSmrg * The DDX is responsible for allocating the event structure in the first 1602f7df2e56Smrg * place via InitEventList() and GetMaximumEventsNum(), and for freeing it. 1603f7df2e56Smrg * 1604f7df2e56Smrg * In the generated events rootX/Y will be in absolute screen coords and 1605f7df2e56Smrg * the valuator information in the absolute or relative device coords. 1606f7df2e56Smrg * 1607f7df2e56Smrg * last.valuators[x] of the device is always in absolute device coords. 1608f7df2e56Smrg * last.valuators[x] of the master device is in absolute screen coords. 1609f7df2e56Smrg * 1610f7df2e56Smrg * master->last.valuators[x] for x > 2 is undefined. 1611f7df2e56Smrg */ 1612f7df2e56Smrgint 1613f7df2e56SmrgGetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type, 1614f7df2e56Smrg int buttons, int flags, const ValuatorMask *mask_in) 1615f7df2e56Smrg{ 1616f7df2e56Smrg CARD32 ms = GetTimeInMillis(); 1617f7df2e56Smrg int num_events = 0, nev_tmp; 1618f7df2e56Smrg ValuatorMask mask; 1619f7df2e56Smrg ValuatorMask scroll; 1620f7df2e56Smrg int i; 1621f7df2e56Smrg int realtype = type; 1622f7df2e56Smrg 16235a112b11Smrg#ifdef XSERVER_DTRACE 1624f7df2e56Smrg if (XSERVER_INPUT_EVENT_ENABLED()) { 1625f7df2e56Smrg XSERVER_INPUT_EVENT(pDev->id, type, buttons, flags, 1626f7df2e56Smrg mask_in ? mask_in->last_bit + 1 : 0, 1627f7df2e56Smrg mask_in ? mask_in->mask : NULL, 1628f7df2e56Smrg mask_in ? mask_in->valuators : NULL); 1629f7df2e56Smrg } 1630f7df2e56Smrg#endif 1631f7df2e56Smrg 1632f7df2e56Smrg BUG_RETURN_VAL(buttons >= MAX_BUTTONS, 0); 1633f7df2e56Smrg 1634f7df2e56Smrg /* refuse events from disabled devices */ 1635f7df2e56Smrg if (!pDev->enabled) 1636f7df2e56Smrg return 0; 1637f7df2e56Smrg 1638f7df2e56Smrg if (!miPointerGetScreen(pDev)) 1639f7df2e56Smrg return 0; 1640f7df2e56Smrg 1641f7df2e56Smrg events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, 1642f7df2e56Smrg &num_events); 1643f7df2e56Smrg 1644f7df2e56Smrg valuator_mask_copy(&mask, mask_in); 1645f7df2e56Smrg 1646f7df2e56Smrg /* Turn a scroll button press into a smooth-scrolling event if 1647f7df2e56Smrg * necessary. This only needs to cater for the XIScrollFlagPreferred 1648f7df2e56Smrg * axis (if more than one scrolling axis is present) */ 1649f7df2e56Smrg if (type == ButtonPress) { 1650f7df2e56Smrg double adj; 1651f7df2e56Smrg int axis; 1652f7df2e56Smrg int h_scroll_axis = -1; 1653f7df2e56Smrg int v_scroll_axis = -1; 1654f7df2e56Smrg 1655f7df2e56Smrg if (pDev->valuator) { 1656f7df2e56Smrg h_scroll_axis = pDev->valuator->h_scroll_axis; 1657f7df2e56Smrg v_scroll_axis = pDev->valuator->v_scroll_axis; 1658f7df2e56Smrg } 1659f7df2e56Smrg 1660f7df2e56Smrg /* Up is negative on valuators, down positive */ 1661f7df2e56Smrg switch (buttons) { 1662f7df2e56Smrg case 4: 1663f7df2e56Smrg adj = -1.0; 1664f7df2e56Smrg axis = v_scroll_axis; 1665f7df2e56Smrg break; 1666f7df2e56Smrg case 5: 1667f7df2e56Smrg adj = 1.0; 1668f7df2e56Smrg axis = v_scroll_axis; 1669f7df2e56Smrg break; 1670f7df2e56Smrg case 6: 1671f7df2e56Smrg adj = -1.0; 1672f7df2e56Smrg axis = h_scroll_axis; 1673f7df2e56Smrg break; 1674f7df2e56Smrg case 7: 1675f7df2e56Smrg adj = 1.0; 1676f7df2e56Smrg axis = h_scroll_axis; 1677f7df2e56Smrg break; 1678f7df2e56Smrg default: 1679f7df2e56Smrg adj = 0.0; 1680f7df2e56Smrg axis = -1; 1681f7df2e56Smrg break; 1682f7df2e56Smrg } 1683f7df2e56Smrg 1684f7df2e56Smrg if (adj != 0.0 && axis != -1) { 1685f7df2e56Smrg adj *= pDev->valuator->axes[axis].scroll.increment; 1686f7df2e56Smrg if (!valuator_mask_isset(&mask, axis)) 1687f7df2e56Smrg valuator_mask_set(&mask, axis, 0); 1688f7df2e56Smrg add_to_scroll_valuator(pDev, &mask, axis, adj); 1689f7df2e56Smrg type = MotionNotify; 1690f7df2e56Smrg buttons = 0; 1691f7df2e56Smrg flags |= POINTER_EMULATED; 1692f7df2e56Smrg } 1693f7df2e56Smrg } 1694f7df2e56Smrg 1695f7df2e56Smrg /* First fill out the original event set, with smooth-scrolling axes. */ 1696f7df2e56Smrg nev_tmp = fill_pointer_events(events, pDev, type, buttons, ms, flags, 1697f7df2e56Smrg &mask); 1698f7df2e56Smrg events += nev_tmp; 1699f7df2e56Smrg num_events += nev_tmp; 1700f7df2e56Smrg 1701f7df2e56Smrg valuator_mask_zero(&scroll); 1702f7df2e56Smrg 1703f7df2e56Smrg /* Now turn the smooth-scrolling axes back into emulated button presses 1704f7df2e56Smrg * for legacy clients, based on the integer delta between before and now */ 1705f7df2e56Smrg for (i = 0; i < valuator_mask_size(&mask); i++) { 1706f7df2e56Smrg if ( !pDev->valuator || (i >= pDev->valuator->numAxes)) 1707f7df2e56Smrg break; 1708f7df2e56Smrg 1709f7df2e56Smrg if (!valuator_mask_isset(&mask, i)) 1710f7df2e56Smrg continue; 1711f7df2e56Smrg 1712f7df2e56Smrg valuator_mask_set_double(&scroll, i, pDev->last.valuators[i]); 1713f7df2e56Smrg 1714f7df2e56Smrg nev_tmp = 1715f7df2e56Smrg emulate_scroll_button_events(events, pDev, realtype, i, &scroll, 1716f7df2e56Smrg pDev->last.scroll, ms, 1717f7df2e56Smrg GetMaximumEventsNum() - num_events); 1718f7df2e56Smrg events += nev_tmp; 1719f7df2e56Smrg num_events += nev_tmp; 1720f7df2e56Smrg } 1721f7df2e56Smrg 1722f7df2e56Smrg return num_events; 1723f7df2e56Smrg} 1724f7df2e56Smrg 1725f7df2e56Smrg/** 1726f7df2e56Smrg * Generate internal events representing this proximity event and enqueue 1727f7df2e56Smrg * them on the event queue. 1728f7df2e56Smrg * 1729f7df2e56Smrg * This function is not reentrant. Disable signals before calling. 1730f7df2e56Smrg * 1731f7df2e56Smrg * @param device The device to generate the event for 1732f7df2e56Smrg * @param type Event type, one of ProximityIn or ProximityOut 1733f7df2e56Smrg * @param keycode Key code of the pressed/released key 1734f7df2e56Smrg * @param mask Valuator mask for valuators present for this event. 1735f7df2e56Smrg * 1736f7df2e56Smrg */ 1737f7df2e56Smrgvoid 1738f7df2e56SmrgQueueProximityEvents(DeviceIntPtr device, int type, const ValuatorMask *mask) 1739f7df2e56Smrg{ 1740f7df2e56Smrg int nevents; 1741f7df2e56Smrg 1742f7df2e56Smrg nevents = GetProximityEvents(InputEventList, device, type, mask); 1743f7df2e56Smrg queueEventList(device, InputEventList, nevents); 1744f7df2e56Smrg} 1745f7df2e56Smrg 1746f7df2e56Smrg/** 1747f7df2e56Smrg * Generate ProximityIn/ProximityOut InternalEvents, accompanied by 1748f7df2e56Smrg * valuators. 1749f7df2e56Smrg * 1750f7df2e56Smrg * The DDX is responsible for allocating the events in the first place via 1751f7df2e56Smrg * InitEventList(), and for freeing it. 1752f7df2e56Smrg * 1753f7df2e56Smrg * @return the number of events written into events. 175405b261ecSmrg */ 17554202a189Smrgint 1756f7df2e56SmrgGetProximityEvents(InternalEvent *events, DeviceIntPtr pDev, int type, 1757f7df2e56Smrg const ValuatorMask *mask_in) 175805b261ecSmrg{ 175965b04b38Smrg int num_events = 1, i; 17604202a189Smrg DeviceEvent *event; 176165b04b38Smrg ValuatorMask mask; 17624202a189Smrg 17635a112b11Smrg#ifdef XSERVER_DTRACE 1764f7df2e56Smrg if (XSERVER_INPUT_EVENT_ENABLED()) { 1765f7df2e56Smrg XSERVER_INPUT_EVENT(pDev->id, type, 0, 0, 1766f7df2e56Smrg mask_in ? mask_in->last_bit + 1 : 0, 1767f7df2e56Smrg mask_in ? mask_in->mask : NULL, 1768f7df2e56Smrg mask_in ? mask_in->valuators : NULL); 1769f7df2e56Smrg } 1770f7df2e56Smrg#endif 1771f7df2e56Smrg 17724202a189Smrg /* refuse events from disabled devices */ 17734202a189Smrg if (!pDev->enabled) 17744202a189Smrg return 0; 177505b261ecSmrg 177605b261ecSmrg /* Sanity checks. */ 177765b04b38Smrg if ((type != ProximityIn && type != ProximityOut) || !mask_in) 177805b261ecSmrg return 0; 1779f7df2e56Smrg if (!pDev->valuator || !pDev->proximity) 178005b261ecSmrg return 0; 178105b261ecSmrg 178265b04b38Smrg valuator_mask_copy(&mask, mask_in); 178365b04b38Smrg 178465b04b38Smrg /* ignore relative axes for proximity. */ 1785f7df2e56Smrg for (i = 0; i < valuator_mask_size(&mask); i++) { 178665b04b38Smrg if (valuator_mask_isset(&mask, i) && 178765b04b38Smrg valuator_get_mode(pDev, i) == Relative) 178865b04b38Smrg valuator_mask_unset(&mask, i); 178965b04b38Smrg } 179065b04b38Smrg 179165b04b38Smrg /* FIXME: posting proximity events with relative valuators only results 179265b04b38Smrg * in an empty event, EventToXI() will fail to convert → no event sent 179365b04b38Smrg * to client. */ 179405b261ecSmrg 1795f7df2e56Smrg events = 1796f7df2e56Smrg UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events); 17974642e01fSmrg 1798f7df2e56Smrg event = &events->device_event; 17997e31ba66Smrg init_device_event(event, pDev, GetTimeInMillis(), EVENT_SOURCE_NORMAL); 18004202a189Smrg event->type = (type == ProximityIn) ? ET_ProximityIn : ET_ProximityOut; 180105b261ecSmrg 180265b04b38Smrg clipValuators(pDev, &mask); 180305b261ecSmrg 180465b04b38Smrg set_valuators(pDev, event, &mask); 18054202a189Smrg 180605b261ecSmrg return num_events; 180705b261ecSmrg} 180805b261ecSmrg 1809f7df2e56Smrgint 1810f7df2e56SmrgGetTouchOwnershipEvents(InternalEvent *events, DeviceIntPtr pDev, 1811f7df2e56Smrg TouchPointInfoPtr ti, uint8_t reason, XID resource, 1812f7df2e56Smrg uint32_t flags) 1813f7df2e56Smrg{ 1814f7df2e56Smrg TouchClassPtr t = pDev->touch; 1815f7df2e56Smrg TouchOwnershipEvent *event; 1816f7df2e56Smrg CARD32 ms = GetTimeInMillis(); 1817f7df2e56Smrg 1818f7df2e56Smrg if (!pDev->enabled || !t || !ti) 1819f7df2e56Smrg return 0; 1820f7df2e56Smrg 1821f7df2e56Smrg event = &events->touch_ownership_event; 1822f7df2e56Smrg init_touch_ownership(pDev, event, ms); 1823f7df2e56Smrg 1824f7df2e56Smrg event->touchid = ti->client_id; 1825f7df2e56Smrg event->sourceid = ti->sourceid; 1826f7df2e56Smrg event->resource = resource; 1827f7df2e56Smrg event->flags = flags; 1828f7df2e56Smrg event->reason = reason; 1829f7df2e56Smrg 1830f7df2e56Smrg return 1; 1831f7df2e56Smrg} 1832f7df2e56Smrg 1833f7df2e56Smrg/** 1834f7df2e56Smrg * Generate internal events representing this touch event and enqueue them 1835f7df2e56Smrg * on the event queue. 1836f7df2e56Smrg * 1837f7df2e56Smrg * This function is not reentrant. Disable signals before calling. 1838f7df2e56Smrg * 1839f7df2e56Smrg * @param device The device to generate the event for 1840f7df2e56Smrg * @param type Event type, one of XI_TouchBegin, XI_TouchUpdate, XI_TouchEnd 1841f7df2e56Smrg * @param touchid Touch point ID 1842f7df2e56Smrg * @param flags Event modification flags 1843f7df2e56Smrg * @param mask Valuator mask for valuators present for this event. 1844f7df2e56Smrg */ 1845f7df2e56Smrgvoid 1846f7df2e56SmrgQueueTouchEvents(DeviceIntPtr device, int type, 1847f7df2e56Smrg uint32_t ddx_touchid, int flags, const ValuatorMask *mask) 1848f7df2e56Smrg{ 1849f7df2e56Smrg int nevents; 1850f7df2e56Smrg 1851f7df2e56Smrg nevents = 1852f7df2e56Smrg GetTouchEvents(InputEventList, device, ddx_touchid, type, flags, mask); 1853f7df2e56Smrg queueEventList(device, InputEventList, nevents); 1854f7df2e56Smrg} 1855f7df2e56Smrg 1856f7df2e56Smrg/** 1857f7df2e56Smrg * Get events for a touch. Generates a TouchBegin event if end is not set and 1858f7df2e56Smrg * the touch id is not active. Generates a TouchUpdate event if end is not set 1859f7df2e56Smrg * and the touch id is active. Generates a TouchEnd event if end is set and the 1860f7df2e56Smrg * touch id is active. 1861f7df2e56Smrg * 1862f7df2e56Smrg * events is not NULL-terminated; the return value is the number of events. 1863f7df2e56Smrg * The DDX is responsible for allocating the event structure in the first 1864f7df2e56Smrg * place via GetMaximumEventsNum(), and for freeing it. 1865f7df2e56Smrg * 1866f7df2e56Smrg * @param[out] events The list of events generated 1867f7df2e56Smrg * @param dev The device to generate the events for 1868f7df2e56Smrg * @param ddx_touchid The touch ID as assigned by the DDX 1869f7df2e56Smrg * @param type XI_TouchBegin, XI_TouchUpdate or XI_TouchEnd 1870f7df2e56Smrg * @param flags Event flags 1871f7df2e56Smrg * @param mask_in Valuator information for this event 1872f7df2e56Smrg */ 1873f7df2e56Smrgint 1874f7df2e56SmrgGetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid, 1875f7df2e56Smrg uint16_t type, uint32_t flags, const ValuatorMask *mask_in) 1876f7df2e56Smrg{ 18775a112b11Smrg ScreenPtr scr; 1878f7df2e56Smrg TouchClassPtr t = dev->touch; 1879f7df2e56Smrg ValuatorClassPtr v = dev->valuator; 1880f7df2e56Smrg DeviceEvent *event; 1881f7df2e56Smrg CARD32 ms = GetTimeInMillis(); 1882f7df2e56Smrg ValuatorMask mask; 1883f7df2e56Smrg double screenx = 0.0, screeny = 0.0; /* desktop coordinate system */ 1884f7df2e56Smrg double devx = 0.0, devy = 0.0; /* desktop-wide in device coords */ 1885f7df2e56Smrg int i; 1886f7df2e56Smrg int num_events = 0; 1887f7df2e56Smrg RawDeviceEvent *raw; 1888f7df2e56Smrg DDXTouchPointInfoPtr ti; 1889f7df2e56Smrg int need_rawevent = TRUE; 1890f7df2e56Smrg Bool emulate_pointer = FALSE; 1891f7df2e56Smrg int client_id = 0; 1892f7df2e56Smrg 18935a112b11Smrg#ifdef XSERVER_DTRACE 1894f7df2e56Smrg if (XSERVER_INPUT_EVENT_ENABLED()) { 1895f7df2e56Smrg XSERVER_INPUT_EVENT(dev->id, type, ddx_touchid, flags, 1896f7df2e56Smrg mask_in ? mask_in->last_bit + 1 : 0, 1897f7df2e56Smrg mask_in ? mask_in->mask : NULL, 1898f7df2e56Smrg mask_in ? mask_in->valuators : NULL); 1899f7df2e56Smrg } 1900f7df2e56Smrg#endif 1901f7df2e56Smrg 1902f7df2e56Smrg if (!dev->enabled || !t || !v) 1903f7df2e56Smrg return 0; 1904f7df2e56Smrg 1905f7df2e56Smrg /* Find and/or create the DDX touch info */ 1906f7df2e56Smrg 1907f7df2e56Smrg ti = TouchFindByDDXID(dev, ddx_touchid, (type == XI_TouchBegin)); 1908f7df2e56Smrg if (!ti) { 1909f7df2e56Smrg ErrorFSigSafe("[dix] %s: unable to %s touch point %u\n", dev->name, 1910f7df2e56Smrg type == XI_TouchBegin ? "begin" : "find", ddx_touchid); 1911f7df2e56Smrg return 0; 1912f7df2e56Smrg } 1913f7df2e56Smrg client_id = ti->client_id; 1914f7df2e56Smrg 1915f7df2e56Smrg emulate_pointer = ti->emulate_pointer; 1916f7df2e56Smrg 1917f7df2e56Smrg if (!IsMaster(dev)) 1918f7df2e56Smrg events = 1919f7df2e56Smrg UpdateFromMaster(events, dev, DEVCHANGE_POINTER_EVENT, &num_events); 1920f7df2e56Smrg 1921f7df2e56Smrg valuator_mask_copy(&mask, mask_in); 1922f7df2e56Smrg 1923f7df2e56Smrg if (need_rawevent) { 1924f7df2e56Smrg raw = &events->raw_event; 1925f7df2e56Smrg events++; 1926f7df2e56Smrg num_events++; 1927f7df2e56Smrg init_raw(dev, raw, ms, type, client_id); 1928f7df2e56Smrg set_raw_valuators(raw, &mask, TRUE, raw->valuators.data_raw); 1929f7df2e56Smrg } 1930f7df2e56Smrg 1931f7df2e56Smrg event = &events->device_event; 1932f7df2e56Smrg num_events++; 1933f7df2e56Smrg 19347e31ba66Smrg init_device_event(event, dev, ms, EVENT_SOURCE_NORMAL); 1935f7df2e56Smrg 1936f7df2e56Smrg switch (type) { 1937f7df2e56Smrg case XI_TouchBegin: 1938f7df2e56Smrg event->type = ET_TouchBegin; 19395a112b11Smrg /* If we're starting a touch, we must have x & y coordinates. */ 1940f7df2e56Smrg if (!mask_in || 1941f7df2e56Smrg !valuator_mask_isset(mask_in, 0) || 1942f7df2e56Smrg !valuator_mask_isset(mask_in, 1)) { 1943f7df2e56Smrg ErrorFSigSafe("%s: Attempted to start touch without x/y " 1944f7df2e56Smrg "(driver bug)\n", dev->name); 1945f7df2e56Smrg return 0; 1946f7df2e56Smrg } 1947f7df2e56Smrg break; 1948f7df2e56Smrg case XI_TouchUpdate: 1949f7df2e56Smrg event->type = ET_TouchUpdate; 1950f7df2e56Smrg if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0) { 1951f7df2e56Smrg ErrorFSigSafe("%s: TouchUpdate with no valuators? Driver bug\n", 1952f7df2e56Smrg dev->name); 1953f7df2e56Smrg } 1954f7df2e56Smrg break; 1955f7df2e56Smrg case XI_TouchEnd: 1956f7df2e56Smrg event->type = ET_TouchEnd; 1957f7df2e56Smrg /* We can end the DDX touch here, since we don't use the active 1958f7df2e56Smrg * field below */ 1959f7df2e56Smrg TouchEndDDXTouch(dev, ti); 1960f7df2e56Smrg break; 1961f7df2e56Smrg default: 1962f7df2e56Smrg return 0; 1963f7df2e56Smrg } 1964f7df2e56Smrg 19655a112b11Smrg /* Get our screen event coordinates (root_x/root_y/event_x/event_y): 1966f7df2e56Smrg * these come from the touchpoint in Absolute mode, or the sprite in 1967f7df2e56Smrg * Relative. */ 1968f7df2e56Smrg if (t->mode == XIDirectTouch) { 1969f7df2e56Smrg for (i = 0; i < max(valuator_mask_size(&mask), 2); i++) { 1970f7df2e56Smrg double val; 1971f7df2e56Smrg 1972f7df2e56Smrg if (valuator_mask_fetch_double(&mask, i, &val)) 1973f7df2e56Smrg valuator_mask_set_double(ti->valuators, i, val); 1974f7df2e56Smrg /* If the device doesn't post new X and Y axis values, 1975f7df2e56Smrg * use the last values posted. 1976f7df2e56Smrg */ 1977f7df2e56Smrg else if (i < 2 && 1978f7df2e56Smrg valuator_mask_fetch_double(ti->valuators, i, &val)) 1979f7df2e56Smrg valuator_mask_set_double(&mask, i, val); 1980f7df2e56Smrg } 1981f7df2e56Smrg 1982f7df2e56Smrg transformAbsolute(dev, &mask); 1983f7df2e56Smrg clipAbsolute(dev, &mask); 1984f7df2e56Smrg } 1985f7df2e56Smrg else { 1986f7df2e56Smrg screenx = dev->spriteInfo->sprite->hotPhys.x; 1987f7df2e56Smrg screeny = dev->spriteInfo->sprite->hotPhys.y; 1988f7df2e56Smrg } 1989f7df2e56Smrg if (need_rawevent) 1990f7df2e56Smrg set_raw_valuators(raw, &mask, FALSE, raw->valuators.data); 1991f7df2e56Smrg 19925a112b11Smrg scr = dev->spriteInfo->sprite->hotPhys.pScreen; 19935a112b11Smrg 1994f7df2e56Smrg /* Indirect device touch coordinates are not used for cursor positioning. 1995f7df2e56Smrg * They are merely informational, and are provided in device coordinates. 1996f7df2e56Smrg * The device sprite is used for positioning instead, and it is already 1997f7df2e56Smrg * scaled. */ 1998f7df2e56Smrg if (t->mode == XIDirectTouch) 1999f7df2e56Smrg scr = scale_to_desktop(dev, &mask, &devx, &devy, &screenx, &screeny); 2000f7df2e56Smrg if (emulate_pointer) 2001f7df2e56Smrg scr = positionSprite(dev, Absolute, &mask, 2002f7df2e56Smrg &devx, &devy, &screenx, &screeny, NULL, NULL); 2003f7df2e56Smrg 2004f7df2e56Smrg /* see fill_pointer_events for coordinate systems */ 2005f7df2e56Smrg if (emulate_pointer) 2006f7df2e56Smrg updateHistory(dev, &mask, ms); 2007f7df2e56Smrg 2008f7df2e56Smrg clipValuators(dev, &mask); 2009f7df2e56Smrg 2010f7df2e56Smrg if (emulate_pointer) 2011f7df2e56Smrg storeLastValuators(dev, &mask, 0, 1, devx, devy); 2012f7df2e56Smrg 20135a112b11Smrg /* Update the MD's coordinates, which are always in desktop space. */ 2014f7df2e56Smrg if (emulate_pointer && !IsMaster(dev) && !IsFloating(dev)) { 2015f7df2e56Smrg DeviceIntPtr master = GetMaster(dev, MASTER_POINTER); 2016f7df2e56Smrg 2017f7df2e56Smrg master->last.valuators[0] = screenx; 2018f7df2e56Smrg master->last.valuators[1] = screeny; 2019f7df2e56Smrg } 2020f7df2e56Smrg 2021f7df2e56Smrg event->root = scr->root->drawable.id; 2022f7df2e56Smrg 2023f7df2e56Smrg event_set_root_coordinates(event, screenx - scr->x, screeny - scr->y); 2024f7df2e56Smrg event->touchid = client_id; 2025f7df2e56Smrg event->flags = flags; 2026f7df2e56Smrg 2027f7df2e56Smrg if (emulate_pointer) { 2028f7df2e56Smrg event->flags |= TOUCH_POINTER_EMULATED; 2029f7df2e56Smrg event->detail.button = 1; 2030f7df2e56Smrg } 2031f7df2e56Smrg 2032f7df2e56Smrg set_valuators(dev, event, &mask); 2033f7df2e56Smrg for (i = 0; i < v->numAxes; i++) { 2034f7df2e56Smrg if (valuator_mask_isset(&mask, i)) 2035f7df2e56Smrg v->axisVal[i] = valuator_mask_get(&mask, i); 2036f7df2e56Smrg } 2037f7df2e56Smrg 2038f7df2e56Smrg return num_events; 2039f7df2e56Smrg} 2040f7df2e56Smrg 2041f7df2e56Smrgvoid 2042f7df2e56SmrgGetDixTouchEnd(InternalEvent *ievent, DeviceIntPtr dev, TouchPointInfoPtr ti, 2043f7df2e56Smrg uint32_t flags) 2044f7df2e56Smrg{ 2045f7df2e56Smrg ScreenPtr scr = dev->spriteInfo->sprite->hotPhys.pScreen; 2046f7df2e56Smrg DeviceEvent *event = &ievent->device_event; 2047f7df2e56Smrg CARD32 ms = GetTimeInMillis(); 2048f7df2e56Smrg 2049f7df2e56Smrg BUG_WARN(!dev->enabled); 2050f7df2e56Smrg 20517e31ba66Smrg init_device_event(event, dev, ms, EVENT_SOURCE_NORMAL); 2052f7df2e56Smrg 2053f7df2e56Smrg event->sourceid = ti->sourceid; 2054f7df2e56Smrg event->type = ET_TouchEnd; 2055f7df2e56Smrg 2056f7df2e56Smrg event->root = scr->root->drawable.id; 2057f7df2e56Smrg 2058f7df2e56Smrg /* Get screen event coordinates from the sprite. Is this really the best 2059f7df2e56Smrg * we can do? */ 2060f7df2e56Smrg event_set_root_coordinates(event, 2061f7df2e56Smrg dev->last.valuators[0] - scr->x, 2062f7df2e56Smrg dev->last.valuators[1] - scr->y); 2063f7df2e56Smrg event->touchid = ti->client_id; 2064f7df2e56Smrg event->flags = flags; 2065f7df2e56Smrg 2066f7df2e56Smrg if (flags & TOUCH_POINTER_EMULATED) { 2067f7df2e56Smrg event->flags |= TOUCH_POINTER_EMULATED; 2068f7df2e56Smrg event->detail.button = 1; 2069f7df2e56Smrg } 2070f7df2e56Smrg} 2071f7df2e56Smrg 207205b261ecSmrg/** 207305b261ecSmrg * Synthesize a single motion event for the core pointer. 207405b261ecSmrg * 207505b261ecSmrg * Used in cursor functions, e.g. when cursor confinement changes, and we need 207605b261ecSmrg * to shift the pointer to get it inside the new bounds. 207705b261ecSmrg */ 207805b261ecSmrgvoid 20794642e01fSmrgPostSyntheticMotion(DeviceIntPtr pDev, 2080f7df2e56Smrg int x, int y, int screen, unsigned long time) 208105b261ecSmrg{ 20824202a189Smrg DeviceEvent ev; 208305b261ecSmrg 208405b261ecSmrg#ifdef PANORAMIX 208505b261ecSmrg /* Translate back to the sprite screen since processInputProc 208605b261ecSmrg will translate from sprite screen to screen 0 upon reentry 208705b261ecSmrg to the DIX layer. */ 208805b261ecSmrg if (!noPanoramiXExtension) { 20894202a189Smrg x += screenInfo.screens[0]->x - screenInfo.screens[screen]->x; 20904202a189Smrg y += screenInfo.screens[0]->y - screenInfo.screens[screen]->y; 209105b261ecSmrg } 209205b261ecSmrg#endif 209305b261ecSmrg 20944202a189Smrg memset(&ev, 0, sizeof(DeviceEvent)); 20957e31ba66Smrg init_device_event(&ev, pDev, time, EVENT_SOURCE_NORMAL); 20964202a189Smrg ev.root_x = x; 20974202a189Smrg ev.root_y = y; 20984202a189Smrg ev.type = ET_Motion; 20994202a189Smrg ev.time = time; 210005b261ecSmrg 21014202a189Smrg /* FIXME: MD/SD considerations? */ 2102f7df2e56Smrg (*pDev->public.processInputProc) ((InternalEvent *) &ev, pDev); 210305b261ecSmrg} 21045a112b11Smrg 21055a112b11Smrgvoid 21065a112b11SmrgInitGestureEvent(InternalEvent *ievent, DeviceIntPtr dev, CARD32 ms, 21075a112b11Smrg int type, uint16_t num_touches, uint32_t flags, 21085a112b11Smrg double delta_x, double delta_y, 21095a112b11Smrg double delta_unaccel_x, double delta_unaccel_y, 21105a112b11Smrg double scale, double delta_angle) 21115a112b11Smrg{ 21125a112b11Smrg ScreenPtr scr = dev->spriteInfo->sprite->hotPhys.pScreen; 21135a112b11Smrg GestureEvent *event = &ievent->gesture_event; 21145a112b11Smrg double screenx = 0.0, screeny = 0.0; /* desktop coordinate system */ 21155a112b11Smrg 21165a112b11Smrg init_gesture_event(event, dev, ms); 21175a112b11Smrg 21185a112b11Smrg screenx = dev->spriteInfo->sprite->hotPhys.x; 21195a112b11Smrg screeny = dev->spriteInfo->sprite->hotPhys.y; 21205a112b11Smrg 21215a112b11Smrg event->type = type; 21225a112b11Smrg event->root = scr->root->drawable.id; 21235a112b11Smrg event->root_x = screenx - scr->x; 21245a112b11Smrg event->root_y = screeny - scr->y; 21255a112b11Smrg event->num_touches = num_touches; 21265a112b11Smrg event->flags = flags; 21275a112b11Smrg 21285a112b11Smrg event->delta_x = delta_x; 21295a112b11Smrg event->delta_y = delta_y; 21305a112b11Smrg event->delta_unaccel_x = delta_unaccel_x; 21315a112b11Smrg event->delta_unaccel_y = delta_unaccel_y; 21325a112b11Smrg event->scale = scale; 21335a112b11Smrg event->delta_angle = delta_angle; 21345a112b11Smrg} 21355a112b11Smrg 21365a112b11Smrg/** 21375a112b11Smrg * Get events for a pinch or swipe gesture. 21385a112b11Smrg * 21395a112b11Smrg * events is not NULL-terminated; the return value is the number of events. 21405a112b11Smrg * The DDX is responsible for allocating the event structure in the first 21415a112b11Smrg * place via GetMaximumEventsNum(), and for freeing it. 21425a112b11Smrg * 21435a112b11Smrg * @param[out] events The list of events generated 21445a112b11Smrg * @param dev The device to generate the events for 21455a112b11Smrg * @param type XI_Gesture{Pinch,Swipe}{Begin,Update,End} 21465a112b11Smrg * @prama num_touches The number of touches in the gesture 21475a112b11Smrg * @param flags Event flags 21485a112b11Smrg * @param delta_x,delta_y accelerated relative motion delta 21495a112b11Smrg * @param delta_unaccel_x,delta_unaccel_y unaccelerated relative motion delta 21505a112b11Smrg * @param scale (valid only to pinch events) absolute scale of a pinch gesture 21515a112b11Smrg * @param delta_angle (valid only to pinch events) the ange delta in degrees between the last and 21525a112b11Smrg * the current pinch event. 21535a112b11Smrg */ 21545a112b11Smrgint 21555a112b11SmrgGetGestureEvents(InternalEvent *events, DeviceIntPtr dev, 21565a112b11Smrg uint16_t type, uint16_t num_touches, uint32_t flags, 21575a112b11Smrg double delta_x, double delta_y, 21585a112b11Smrg double delta_unaccel_x, double delta_unaccel_y, 21595a112b11Smrg double scale, double delta_angle) 21605a112b11Smrg 21615a112b11Smrg{ 21625a112b11Smrg GestureClassPtr g = dev->gesture; 21635a112b11Smrg CARD32 ms = GetTimeInMillis(); 21645a112b11Smrg enum EventType evtype; 21655a112b11Smrg int num_events = 0; 21665a112b11Smrg uint32_t evflags = 0; 21675a112b11Smrg 21685a112b11Smrg if (!dev->enabled || !g) 21695a112b11Smrg return 0; 21705a112b11Smrg 21715a112b11Smrg if (!IsMaster(dev)) 21725a112b11Smrg events = UpdateFromMaster(events, dev, DEVCHANGE_POINTER_EVENT, 21735a112b11Smrg &num_events); 21745a112b11Smrg 21755a112b11Smrg switch (type) { 21765a112b11Smrg case XI_GesturePinchBegin: 21775a112b11Smrg evtype = ET_GesturePinchBegin; 21785a112b11Smrg break; 21795a112b11Smrg case XI_GesturePinchUpdate: 21805a112b11Smrg evtype = ET_GesturePinchUpdate; 21815a112b11Smrg break; 21825a112b11Smrg case XI_GesturePinchEnd: 21835a112b11Smrg evtype = ET_GesturePinchEnd; 21845a112b11Smrg if (flags & XIGesturePinchEventCancelled) 21855a112b11Smrg evflags |= GESTURE_CANCELLED; 21865a112b11Smrg break; 21875a112b11Smrg case XI_GestureSwipeBegin: 21885a112b11Smrg evtype = ET_GestureSwipeBegin; 21895a112b11Smrg break; 21905a112b11Smrg case XI_GestureSwipeUpdate: 21915a112b11Smrg evtype = ET_GestureSwipeUpdate; 21925a112b11Smrg break; 21935a112b11Smrg case XI_GestureSwipeEnd: 21945a112b11Smrg evtype = ET_GestureSwipeEnd; 21955a112b11Smrg if (flags & XIGestureSwipeEventCancelled) 21965a112b11Smrg evflags |= GESTURE_CANCELLED; 21975a112b11Smrg break; 21985a112b11Smrg default: 21995a112b11Smrg return 0; 22005a112b11Smrg } 22015a112b11Smrg 22025a112b11Smrg InitGestureEvent(events, dev, ms, evtype, num_touches, evflags, 22035a112b11Smrg delta_x, delta_y, delta_unaccel_x, delta_unaccel_y, 22045a112b11Smrg scale, delta_angle); 22055a112b11Smrg num_events++; 22065a112b11Smrg 22075a112b11Smrg return num_events; 22085a112b11Smrg} 22095a112b11Smrg 22105a112b11Smrgvoid 22115a112b11SmrgQueueGesturePinchEvents(DeviceIntPtr dev, uint16_t type, 22125a112b11Smrg uint16_t num_touches, uint32_t flags, 22135a112b11Smrg double delta_x, double delta_y, 22145a112b11Smrg double delta_unaccel_x, 22155a112b11Smrg double delta_unaccel_y, 22165a112b11Smrg double scale, double delta_angle) 22175a112b11Smrg{ 22185a112b11Smrg int nevents; 22195a112b11Smrg nevents = GetGestureEvents(InputEventList, dev, type, num_touches, flags, 22205a112b11Smrg delta_x, delta_y, 22215a112b11Smrg delta_unaccel_x, delta_unaccel_y, 22225a112b11Smrg scale, delta_angle); 22235a112b11Smrg queueEventList(dev, InputEventList, nevents); 22245a112b11Smrg} 22255a112b11Smrg 22265a112b11Smrgvoid 22275a112b11SmrgQueueGestureSwipeEvents(DeviceIntPtr dev, uint16_t type, 22285a112b11Smrg uint16_t num_touches, uint32_t flags, 22295a112b11Smrg double delta_x, double delta_y, 22305a112b11Smrg double delta_unaccel_x, 22315a112b11Smrg double delta_unaccel_y) 22325a112b11Smrg{ 22335a112b11Smrg int nevents; 22345a112b11Smrg nevents = GetGestureEvents(InputEventList, dev, type, num_touches, flags, 22355a112b11Smrg delta_x, delta_y, 22365a112b11Smrg delta_unaccel_x, delta_unaccel_y, 22375a112b11Smrg 0.0, 0.0); 22385a112b11Smrg queueEventList(dev, InputEventList, nevents); 22395a112b11Smrg} 2240