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(&current, 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