getevents.c revision f7df2e56
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{
3344642e01fSmrg    int i;
3354642e01fSmrg    DeviceIntPtr lastSlave;
3364642e01fSmrg
337f7df2e56Smrg    /* master->last.valuators[0]/[1] is in desktop-wide coords and the actual
3384642e01fSmrg     * position of the pointer */
3394642e01fSmrg    pDev->last.valuators[0] = master->last.valuators[0];
3404642e01fSmrg    pDev->last.valuators[1] = master->last.valuators[1];
3414642e01fSmrg
3424642e01fSmrg    if (!pDev->valuator)
3434642e01fSmrg        return;
3444642e01fSmrg
3454642e01fSmrg    /* scale back to device coordinates */
346f7df2e56Smrg    if (pDev->valuator->numAxes > 0) {
347f7df2e56Smrg        pDev->last.valuators[0] = rescaleValuatorAxis(pDev->last.valuators[0],
348f7df2e56Smrg                                                      NULL,
349f7df2e56Smrg                                                      pDev->valuator->axes + 0,
350f7df2e56Smrg                                                      screenInfo.x,
351f7df2e56Smrg                                                      screenInfo.width);
352f7df2e56Smrg    }
353f7df2e56Smrg    if (pDev->valuator->numAxes > 1) {
354f7df2e56Smrg        pDev->last.valuators[1] = rescaleValuatorAxis(pDev->last.valuators[1],
355f7df2e56Smrg                                                      NULL,
356f7df2e56Smrg                                                      pDev->valuator->axes + 1,
357f7df2e56Smrg                                                      screenInfo.y,
358f7df2e56Smrg                                                      screenInfo.height);
359f7df2e56Smrg    }
3604642e01fSmrg
3614642e01fSmrg    /* calculate the other axis as well based on info from the old
3624642e01fSmrg     * slave-device. If the old slave had less axes than this one,
3634642e01fSmrg     * last.valuators is reset to 0.
3644642e01fSmrg     */
3654202a189Smrg    if ((lastSlave = master->last.slave) && lastSlave->valuator) {
3664642e01fSmrg        for (i = 2; i < pDev->valuator->numAxes; i++) {
367f7df2e56Smrg            if (i >= lastSlave->valuator->numAxes) {
3684642e01fSmrg                pDev->last.valuators[i] = 0;
369f7df2e56Smrg                valuator_mask_set_double(pDev->last.scroll, i, 0);
370f7df2e56Smrg            }
371f7df2e56Smrg            else {
372f7df2e56Smrg                double val = pDev->last.valuators[i];
373f7df2e56Smrg
374f7df2e56Smrg                val = rescaleValuatorAxis(val, lastSlave->valuator->axes + i,
375f7df2e56Smrg                                          pDev->valuator->axes + i, 0, 0);
376f7df2e56Smrg                pDev->last.valuators[i] = val;
377f7df2e56Smrg                valuator_mask_set_double(pDev->last.scroll, i, val);
378f7df2e56Smrg            }
3794642e01fSmrg        }
3804642e01fSmrg    }
3814642e01fSmrg
3824642e01fSmrg}
3834642e01fSmrg
38405b261ecSmrg/**
38505b261ecSmrg * Allocate the motion history buffer.
38605b261ecSmrg */
3874202a189Smrgvoid
38805b261ecSmrgAllocateMotionHistory(DeviceIntPtr pDev)
38905b261ecSmrg{
3904642e01fSmrg    int size;
391f7df2e56Smrg
3924202a189Smrg    free(pDev->valuator->motion);
39305b261ecSmrg
39405b261ecSmrg    if (pDev->valuator->numMotionEvents < 1)
39505b261ecSmrg        return;
39605b261ecSmrg
3974642e01fSmrg    /* An MD must have a motion history size large enough to keep all
3984642e01fSmrg     * potential valuators, plus the respective range of the valuators.
3994642e01fSmrg     * 3 * INT32 for (min_val, max_val, curr_val))
4004642e01fSmrg     */
4014202a189Smrg    if (IsMaster(pDev))
4024642e01fSmrg        size = sizeof(INT32) * 3 * MAX_VALUATORS;
40365b04b38Smrg    else {
40465b04b38Smrg        ValuatorClassPtr v = pDev->valuator;
40565b04b38Smrg        int numAxes;
406f7df2e56Smrg
40765b04b38Smrg        /* XI1 doesn't understand mixed mode devices */
40865b04b38Smrg        for (numAxes = 0; numAxes < v->numAxes; numAxes++)
40965b04b38Smrg            if (valuator_get_mode(pDev, numAxes) != valuator_get_mode(pDev, 0))
41065b04b38Smrg                break;
41165b04b38Smrg        size = sizeof(INT32) * numAxes;
41265b04b38Smrg    }
4134642e01fSmrg
4144642e01fSmrg    size += sizeof(Time);
4154642e01fSmrg
4164202a189Smrg    pDev->valuator->motion = calloc(pDev->valuator->numMotionEvents, size);
41705b261ecSmrg    pDev->valuator->first_motion = 0;
41805b261ecSmrg    pDev->valuator->last_motion = 0;
4194642e01fSmrg    if (!pDev->valuator->motion)
4204642e01fSmrg        ErrorF("[dix] %s: Failed to alloc motion history (%d bytes).\n",
421f7df2e56Smrg               pDev->name, size * pDev->valuator->numMotionEvents);
42205b261ecSmrg}
42305b261ecSmrg
42405b261ecSmrg/**
42505b261ecSmrg * Dump the motion history between start and stop into the supplied buffer.
42605b261ecSmrg * Only records the event for a given screen in theory, but in practice, we
42705b261ecSmrg * sort of ignore this.
4284642e01fSmrg *
4294642e01fSmrg * If core is set, we only generate x/y, in INT16, scaled to screen coords.
43005b261ecSmrg */
4314202a189Smrgint
432f7df2e56SmrgGetMotionHistory(DeviceIntPtr pDev, xTimecoord ** buff, unsigned long start,
4334642e01fSmrg                 unsigned long stop, ScreenPtr pScreen, BOOL core)
43405b261ecSmrg{
4354642e01fSmrg    char *ibuff = NULL, *obuff;
43605b261ecSmrg    int i = 0, ret = 0;
4374642e01fSmrg    int j, coord;
43805b261ecSmrg    Time current;
439f7df2e56Smrg
44005b261ecSmrg    /* The size of a single motion event. */
4414642e01fSmrg    int size;
442f7df2e56Smrg    AxisInfo from, *to;         /* for scaling */
443f7df2e56Smrg    INT32 *ocbuf, *icbuf;       /* pointer to coordinates for copying */
4444642e01fSmrg    INT16 *corebuf;
445f7df2e56Smrg    AxisInfo core_axis = { 0 };
44605b261ecSmrg
44705b261ecSmrg    if (!pDev->valuator || !pDev->valuator->numMotionEvents)
44805b261ecSmrg        return 0;
44905b261ecSmrg
4504642e01fSmrg    if (core && !pScreen)
4514642e01fSmrg        return 0;
4524642e01fSmrg
4534202a189Smrg    if (IsMaster(pDev))
4544642e01fSmrg        size = (sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(Time);
4554642e01fSmrg    else
4564642e01fSmrg        size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
4574642e01fSmrg
4584202a189Smrg    *buff = malloc(size * pDev->valuator->numMotionEvents);
4594642e01fSmrg    if (!(*buff))
4604642e01fSmrg        return 0;
461f7df2e56Smrg    obuff = (char *) *buff;
4624642e01fSmrg
46305b261ecSmrg    for (i = pDev->valuator->first_motion;
46405b261ecSmrg         i != pDev->valuator->last_motion;
46505b261ecSmrg         i = (i + 1) % pDev->valuator->numMotionEvents) {
46605b261ecSmrg        /* We index the input buffer by which element we're accessing, which
46705b261ecSmrg         * is not monotonic, and the output buffer by how many events we've
46805b261ecSmrg         * written so far. */
46905b261ecSmrg        ibuff = (char *) pDev->valuator->motion + (i * size);
47005b261ecSmrg        memcpy(&current, ibuff, sizeof(Time));
47105b261ecSmrg
47205b261ecSmrg        if (current > stop) {
47305b261ecSmrg            return ret;
47405b261ecSmrg        }
47505b261ecSmrg        else if (current >= start) {
476f7df2e56Smrg            if (core) {
477f7df2e56Smrg                memcpy(obuff, ibuff, sizeof(Time));     /* copy timestamp */
4784642e01fSmrg
479f7df2e56Smrg                icbuf = (INT32 *) (ibuff + sizeof(Time));
480f7df2e56Smrg                corebuf = (INT16 *) (obuff + sizeof(Time));
4814642e01fSmrg
4824642e01fSmrg                /* fetch x coordinate + range */
4834642e01fSmrg                memcpy(&from.min_value, icbuf++, sizeof(INT32));
4844642e01fSmrg                memcpy(&from.max_value, icbuf++, sizeof(INT32));
4854642e01fSmrg                memcpy(&coord, icbuf++, sizeof(INT32));
4864642e01fSmrg
4874642e01fSmrg                /* scale to screen coords */
4884642e01fSmrg                to = &core_axis;
4894642e01fSmrg                to->max_value = pScreen->width;
490f7df2e56Smrg                coord =
491f7df2e56Smrg                    rescaleValuatorAxis(coord, &from, to, 0, pScreen->width);
4924642e01fSmrg
4934642e01fSmrg                memcpy(corebuf, &coord, sizeof(INT16));
4944642e01fSmrg                corebuf++;
4954642e01fSmrg
4964642e01fSmrg                /* fetch y coordinate + range */
4974642e01fSmrg                memcpy(&from.min_value, icbuf++, sizeof(INT32));
4984642e01fSmrg                memcpy(&from.max_value, icbuf++, sizeof(INT32));
4994642e01fSmrg                memcpy(&coord, icbuf++, sizeof(INT32));
5004642e01fSmrg
5014642e01fSmrg                to->max_value = pScreen->height;
502f7df2e56Smrg                coord =
503f7df2e56Smrg                    rescaleValuatorAxis(coord, &from, to, 0, pScreen->height);
5044642e01fSmrg                memcpy(corebuf, &coord, sizeof(INT16));
5054642e01fSmrg
506f7df2e56Smrg            }
507f7df2e56Smrg            else if (IsMaster(pDev)) {
508f7df2e56Smrg                memcpy(obuff, ibuff, sizeof(Time));     /* copy timestamp */
5094642e01fSmrg
510f7df2e56Smrg                ocbuf = (INT32 *) (obuff + sizeof(Time));
511f7df2e56Smrg                icbuf = (INT32 *) (ibuff + sizeof(Time));
512f7df2e56Smrg                for (j = 0; j < MAX_VALUATORS; j++) {
5134642e01fSmrg                    if (j >= pDev->valuator->numAxes)
5144642e01fSmrg                        break;
5154642e01fSmrg
5164642e01fSmrg                    /* fetch min/max/coordinate */
5174642e01fSmrg                    memcpy(&from.min_value, icbuf++, sizeof(INT32));
5184642e01fSmrg                    memcpy(&from.max_value, icbuf++, sizeof(INT32));
5194642e01fSmrg                    memcpy(&coord, icbuf++, sizeof(INT32));
5204642e01fSmrg
521f7df2e56Smrg                    to = (j <
522f7df2e56Smrg                          pDev->valuator->numAxes) ? &pDev->valuator->
523f7df2e56Smrg                        axes[j] : NULL;
5244642e01fSmrg
5254642e01fSmrg                    /* x/y scaled to screen if no range is present */
5264642e01fSmrg                    if (j == 0 && (from.max_value < from.min_value))
5274642e01fSmrg                        from.max_value = pScreen->width;
5284642e01fSmrg                    else if (j == 1 && (from.max_value < from.min_value))
5294642e01fSmrg                        from.max_value = pScreen->height;
5304642e01fSmrg
5314642e01fSmrg                    /* scale from stored range into current range */
532f7df2e56Smrg                    coord = rescaleValuatorAxis(coord, &from, to, 0, 0);
5334642e01fSmrg                    memcpy(ocbuf, &coord, sizeof(INT32));
5344642e01fSmrg                    ocbuf++;
5354642e01fSmrg                }
536f7df2e56Smrg            }
537f7df2e56Smrg            else
5384642e01fSmrg                memcpy(obuff, ibuff, size);
5394642e01fSmrg
5404642e01fSmrg            /* don't advance by size here. size may be different to the
5414642e01fSmrg             * actually written size if the MD has less valuators than MAX */
5424642e01fSmrg            if (core)
5434642e01fSmrg                obuff += sizeof(INT32) + sizeof(Time);
5444642e01fSmrg            else
545f7df2e56Smrg                obuff +=
546f7df2e56Smrg                    (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
54705b261ecSmrg            ret++;
54805b261ecSmrg        }
54905b261ecSmrg    }
55005b261ecSmrg
55105b261ecSmrg    return ret;
55205b261ecSmrg}
55305b261ecSmrg
55405b261ecSmrg/**
55505b261ecSmrg * Update the motion history for a specific device, with the list of
55605b261ecSmrg * valuators.
5574642e01fSmrg *
5584642e01fSmrg * Layout of the history buffer:
5594642e01fSmrg *   for SDs: [time] [val0] [val1] ... [valn]
5604642e01fSmrg *   for MDs: [time] [min_val0] [max_val0] [val0] [min_val1] ... [valn]
5614642e01fSmrg *
56265b04b38Smrg * For events that have some valuators unset:
5634642e01fSmrg *      min_val == max_val == val == 0.
56405b261ecSmrg */
56505b261ecSmrgstatic void
56665b04b38SmrgupdateMotionHistory(DeviceIntPtr pDev, CARD32 ms, ValuatorMask *mask,
567f7df2e56Smrg                    double *valuators)
56805b261ecSmrg{
56905b261ecSmrg    char *buff = (char *) pDev->valuator->motion;
5704642e01fSmrg    ValuatorClassPtr v;
5714642e01fSmrg    int i;
57205b261ecSmrg
57305b261ecSmrg    if (!pDev->valuator->numMotionEvents)
57405b261ecSmrg        return;
57505b261ecSmrg
5764642e01fSmrg    v = pDev->valuator;
577f7df2e56Smrg    if (IsMaster(pDev)) {
5784642e01fSmrg        buff += ((sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(CARD32)) *
579f7df2e56Smrg            v->last_motion;
5804642e01fSmrg
5814642e01fSmrg        memcpy(buff, &ms, sizeof(Time));
5824642e01fSmrg        buff += sizeof(Time);
5834642e01fSmrg
5844642e01fSmrg        memset(buff, 0, sizeof(INT32) * 3 * MAX_VALUATORS);
5854642e01fSmrg
586f7df2e56Smrg        for (i = 0; i < v->numAxes; i++) {
587f7df2e56Smrg            int val;
588f7df2e56Smrg
58965b04b38Smrg            /* XI1 doesn't support mixed mode devices */
59065b04b38Smrg            if (valuator_get_mode(pDev, i) != valuator_get_mode(pDev, 0))
5914642e01fSmrg                break;
592f7df2e56Smrg            if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i)) {
59365b04b38Smrg                buff += 3 * sizeof(INT32);
59465b04b38Smrg                continue;
59565b04b38Smrg            }
5964642e01fSmrg            memcpy(buff, &v->axes[i].min_value, sizeof(INT32));
5974642e01fSmrg            buff += sizeof(INT32);
5984642e01fSmrg            memcpy(buff, &v->axes[i].max_value, sizeof(INT32));
5994642e01fSmrg            buff += sizeof(INT32);
600f7df2e56Smrg            val = valuators[i];
601f7df2e56Smrg            memcpy(buff, &val, sizeof(INT32));
6024642e01fSmrg            buff += sizeof(INT32);
6034642e01fSmrg        }
604f7df2e56Smrg    }
605f7df2e56Smrg    else {
6064642e01fSmrg
6074642e01fSmrg        buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) *
60805b261ecSmrg            pDev->valuator->last_motion;
60905b261ecSmrg
6104642e01fSmrg        memcpy(buff, &ms, sizeof(Time));
6114642e01fSmrg        buff += sizeof(Time);
61205b261ecSmrg
6134642e01fSmrg        memset(buff, 0, sizeof(INT32) * pDev->valuator->numAxes);
61405b261ecSmrg
615f7df2e56Smrg        for (i = 0; i < MAX_VALUATORS; i++) {
616f7df2e56Smrg            int val;
617f7df2e56Smrg
618f7df2e56Smrg            if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i)) {
61965b04b38Smrg                buff += sizeof(INT32);
62065b04b38Smrg                continue;
62165b04b38Smrg            }
622f7df2e56Smrg            val = valuators[i];
623f7df2e56Smrg            memcpy(buff, &val, sizeof(INT32));
62465b04b38Smrg            buff += sizeof(INT32);
62565b04b38Smrg        }
6264642e01fSmrg    }
62705b261ecSmrg
6284642e01fSmrg    pDev->valuator->last_motion = (pDev->valuator->last_motion + 1) %
6294642e01fSmrg        pDev->valuator->numMotionEvents;
63005b261ecSmrg    /* If we're wrapping around, just keep the circular buffer going. */
63105b261ecSmrg    if (pDev->valuator->first_motion == pDev->valuator->last_motion)
63205b261ecSmrg        pDev->valuator->first_motion = (pDev->valuator->first_motion + 1) %
633f7df2e56Smrg            pDev->valuator->numMotionEvents;
63405b261ecSmrg
63505b261ecSmrg    return;
63605b261ecSmrg}
63705b261ecSmrg
63805b261ecSmrg/**
639f7df2e56Smrg * Returns the maximum number of events GetKeyboardEvents
640f7df2e56Smrg * and GetPointerEvents will ever return.
64105b261ecSmrg *
6424642e01fSmrg * This MUST be absolutely constant, from init until exit.
64305b261ecSmrg */
6444202a189Smrgint
645f7df2e56SmrgGetMaximumEventsNum(void)
646f7df2e56Smrg{
6474202a189Smrg    /* One raw event
6484202a189Smrg     * One device event
6494202a189Smrg     * One possible device changed event
650f7df2e56Smrg     * Lots of possible separate button scroll events (horiz + vert)
651f7df2e56Smrg     * Lots of possible separate raw button scroll events (horiz + vert)
6524202a189Smrg     */
653f7df2e56Smrg    return 100;
65405b261ecSmrg}
65505b261ecSmrg
65605b261ecSmrg/**
65705b261ecSmrg * Clip an axis to its bounds, which are declared in the call to
65805b261ecSmrg * InitValuatorAxisClassStruct.
65905b261ecSmrg */
66005b261ecSmrgstatic void
661f7df2e56SmrgclipAxis(DeviceIntPtr pDev, int axisNum, double *val)
66205b261ecSmrg{
6634202a189Smrg    AxisInfoPtr axis;
6644202a189Smrg
6654202a189Smrg    if (axisNum >= pDev->valuator->numAxes)
6664202a189Smrg        return;
6674202a189Smrg
6684202a189Smrg    axis = pDev->valuator->axes + axisNum;
6694642e01fSmrg
6704642e01fSmrg    /* If a value range is defined, clip. If not, do nothing */
6714642e01fSmrg    if (axis->max_value <= axis->min_value)
6724642e01fSmrg        return;
6734642e01fSmrg
6744642e01fSmrg    if (*val < axis->min_value)
6754642e01fSmrg        *val = axis->min_value;
6764642e01fSmrg    if (*val > axis->max_value)
6774642e01fSmrg        *val = axis->max_value;
67805b261ecSmrg}
67905b261ecSmrg
68005b261ecSmrg/**
68105b261ecSmrg * Clip every axis in the list of valuators to its bounds.
68205b261ecSmrg */
68305b261ecSmrgstatic void
68465b04b38SmrgclipValuators(DeviceIntPtr pDev, ValuatorMask *mask)
68505b261ecSmrg{
68605b261ecSmrg    int i;
68705b261ecSmrg
68865b04b38Smrg    for (i = 0; i < valuator_mask_size(mask); i++)
689f7df2e56Smrg        if (valuator_mask_isset(mask, i)) {
690f7df2e56Smrg            double val = valuator_mask_get_double(mask, i);
691f7df2e56Smrg
69265b04b38Smrg            clipAxis(pDev, i, &val);
693f7df2e56Smrg            valuator_mask_set_double(mask, i, val);
69465b04b38Smrg        }
69505b261ecSmrg}
69605b261ecSmrg
6974642e01fSmrg/**
6984642e01fSmrg * Create the DCCE event (does not update the master's device state yet, this
6994642e01fSmrg * is done in the event processing).
7004642e01fSmrg * Pull in the coordinates from the MD if necessary.
7014642e01fSmrg *
702f7df2e56Smrg * @param events Pointer to a pre-allocated event array.
7034642e01fSmrg * @param dev The slave device that generated an event.
7044202a189Smrg * @param type Either DEVCHANGE_POINTER_EVENT and/or DEVCHANGE_KEYBOARD_EVENT
7054642e01fSmrg * @param num_events The current number of events, returns the number of
7064642e01fSmrg *        events if a DCCE was generated.
7074642e01fSmrg * @return The updated @events pointer.
7084642e01fSmrg */
709f7df2e56SmrgInternalEvent *
710f7df2e56SmrgUpdateFromMaster(InternalEvent *events, DeviceIntPtr dev, int type,
711f7df2e56Smrg                 int *num_events)
7124642e01fSmrg{
7134202a189Smrg    DeviceIntPtr master;
7144202a189Smrg
715f7df2e56Smrg    master =
716f7df2e56Smrg        GetMaster(dev,
717f7df2e56Smrg                  (type & DEVCHANGE_POINTER_EVENT) ? MASTER_POINTER :
718f7df2e56Smrg                  MASTER_KEYBOARD);
7194202a189Smrg
720f7df2e56Smrg    if (master && master->last.slave != dev) {
721f7df2e56Smrg        CreateClassesChangedEvent(events, master, dev,
722f7df2e56Smrg                                  type | DEVCHANGE_SLAVE_SWITCH);
723f7df2e56Smrg        if (IsPointerDevice(master)) {
7244202a189Smrg            updateSlaveDeviceCoords(master, dev);
7254202a189Smrg            master->last.numValuators = dev->last.numValuators;
7264202a189Smrg        }
7274202a189Smrg        master->last.slave = dev;
7284202a189Smrg        (*num_events)++;
7294202a189Smrg        events++;
7304642e01fSmrg    }
7314642e01fSmrg    return events;
7324642e01fSmrg}
7334642e01fSmrg
7344642e01fSmrg/**
7354642e01fSmrg * Move the device's pointer to the position given in the valuators.
7364642e01fSmrg *
737f7df2e56Smrg * @param dev The device whose pointer is to be moved.
738f7df2e56Smrg * @param mask Valuator data for this event.
7394642e01fSmrg */
7404642e01fSmrgstatic void
741f7df2e56SmrgclipAbsolute(DeviceIntPtr dev, ValuatorMask *mask)
7424642e01fSmrg{
7434642e01fSmrg    int i;
7444642e01fSmrg
745f7df2e56Smrg    for (i = 0; i < valuator_mask_size(mask); i++) {
746f7df2e56Smrg        double val;
7474642e01fSmrg
748f7df2e56Smrg        if (!valuator_mask_isset(mask, i))
749f7df2e56Smrg            continue;
750f7df2e56Smrg        val = valuator_mask_get_double(mask, i);
751f7df2e56Smrg        clipAxis(dev, i, &val);
752f7df2e56Smrg        valuator_mask_set_double(mask, i, val);
753f7df2e56Smrg    }
754f7df2e56Smrg}
755f7df2e56Smrg
756f7df2e56Smrgstatic void
757f7df2e56Smrgadd_to_scroll_valuator(DeviceIntPtr dev, ValuatorMask *mask, int valuator, double value)
758f7df2e56Smrg{
759f7df2e56Smrg    double v;
7604642e01fSmrg
761f7df2e56Smrg    if (!valuator_mask_fetch_double(mask, valuator, &v))
762f7df2e56Smrg        return;
7634642e01fSmrg
764f7df2e56Smrg    /* protect against scrolling overflow. INT_MAX for double, because
765f7df2e56Smrg     * we'll eventually write this as 32.32 fixed point */
766f7df2e56Smrg    if ((value > 0 && v > INT_MAX - value) || (value < 0 && v < INT_MIN - value)) {
767f7df2e56Smrg        v = 0;
768f7df2e56Smrg
769f7df2e56Smrg        /* reset last.scroll to avoid a button storm */
770f7df2e56Smrg        valuator_mask_set_double(dev->last.scroll, valuator, 0);
7714642e01fSmrg    }
772f7df2e56Smrg    else
773f7df2e56Smrg        v += value;
774f7df2e56Smrg
775f7df2e56Smrg    valuator_mask_set_double(mask, valuator, v);
776f7df2e56Smrg}
777f7df2e56Smrg
778f7df2e56Smrg
779f7df2e56Smrgstatic void
780f7df2e56Smrgscale_for_device_resolution(DeviceIntPtr dev, ValuatorMask *mask)
781f7df2e56Smrg{
782f7df2e56Smrg    double y;
783f7df2e56Smrg    ValuatorClassPtr v = dev->valuator;
784f7df2e56Smrg    int xrange = v->axes[0].max_value - v->axes[0].min_value + 1;
785f7df2e56Smrg    int yrange = v->axes[1].max_value - v->axes[1].min_value + 1;
786f7df2e56Smrg
787f7df2e56Smrg    double screen_ratio = 1.0 * screenInfo.width/screenInfo.height;
788f7df2e56Smrg    double device_ratio = 1.0 * xrange/yrange;
789f7df2e56Smrg    double resolution_ratio = 1.0;
790f7df2e56Smrg    double ratio;
791f7df2e56Smrg
792f7df2e56Smrg    if (!valuator_mask_fetch_double(mask, 1, &y))
793f7df2e56Smrg        return;
794f7df2e56Smrg
795f7df2e56Smrg    if (v->axes[0].resolution != 0 && v->axes[1].resolution != 0)
796f7df2e56Smrg        resolution_ratio = 1.0 * v->axes[0].resolution/v->axes[1].resolution;
797f7df2e56Smrg
798f7df2e56Smrg    ratio = device_ratio/resolution_ratio/screen_ratio;
799f7df2e56Smrg    valuator_mask_set_double(mask, 1, y / ratio);
8004642e01fSmrg}
8014642e01fSmrg
8024642e01fSmrg/**
8034642e01fSmrg * Move the device's pointer by the values given in @valuators.
8044642e01fSmrg *
805f7df2e56Smrg * @param dev The device whose pointer is to be moved.
806f7df2e56Smrg * @param[in,out] mask Valuator data for this event, modified in-place.
8074642e01fSmrg */
8084642e01fSmrgstatic void
809f7df2e56SmrgmoveRelative(DeviceIntPtr dev, int flags, ValuatorMask *mask)
8104642e01fSmrg{
8114642e01fSmrg    int i;
812f7df2e56Smrg    Bool clip_xy = IsMaster(dev) || !IsFloating(dev);
813f7df2e56Smrg    ValuatorClassPtr v = dev->valuator;
814f7df2e56Smrg
815f7df2e56Smrg    /* for abs devices in relative mode, we've just scaled wrong, since we
816f7df2e56Smrg       mapped the device's shape into the screen shape. Undo this. */
817f7df2e56Smrg    if ((flags & POINTER_ABSOLUTE) == 0 && v && v->numAxes > 1 &&
818f7df2e56Smrg        v->axes[0].min_value < v->axes[0].max_value &&
819f7df2e56Smrg        v->axes[1].min_value < v->axes[1].max_value) {
820f7df2e56Smrg        scale_for_device_resolution(dev, mask);
821f7df2e56Smrg    }
8224642e01fSmrg
823f7df2e56Smrg    /* calc other axes, clip, drop back into valuators */
824f7df2e56Smrg    for (i = 0; i < valuator_mask_size(mask); i++) {
825f7df2e56Smrg        double val = dev->last.valuators[i];
8264642e01fSmrg
827f7df2e56Smrg        if (!valuator_mask_isset(mask, i))
828f7df2e56Smrg            continue;
8294642e01fSmrg
830f7df2e56Smrg        add_to_scroll_valuator(dev, mask, i, val);
8314642e01fSmrg
832f7df2e56Smrg        /* x & y need to go over the limits to cross screens if the SD
833f7df2e56Smrg         * isn't currently attached; otherwise, clip to screen bounds. */
834f7df2e56Smrg        if (valuator_get_mode(dev, i) == Absolute &&
835f7df2e56Smrg            ((i != 0 && i != 1) || clip_xy)) {
836f7df2e56Smrg            val = valuator_mask_get_double(mask, i);
837f7df2e56Smrg            clipAxis(dev, i, &val);
838f7df2e56Smrg            valuator_mask_set_double(mask, i, val);
83965b04b38Smrg        }
8404642e01fSmrg    }
8414642e01fSmrg}
8424642e01fSmrg
8434642e01fSmrg/**
8444642e01fSmrg * Accelerate the data in valuators based on the device's acceleration scheme.
8454642e01fSmrg *
8464642e01fSmrg * @param dev The device which's pointer is to be moved.
847f7df2e56Smrg * @param valuators Valuator mask
8484642e01fSmrg * @param ms Current time.
8494642e01fSmrg */
8504642e01fSmrgstatic void
851f7df2e56SmrgaccelPointer(DeviceIntPtr dev, ValuatorMask *valuators, CARD32 ms)
8524642e01fSmrg{
8534642e01fSmrg    if (dev->valuator->accelScheme.AccelSchemeProc)
854f7df2e56Smrg        dev->valuator->accelScheme.AccelSchemeProc(dev, valuators, ms);
855f7df2e56Smrg}
856f7df2e56Smrg
857f7df2e56Smrg/**
858f7df2e56Smrg * Scale from absolute screen coordinates to absolute coordinates in the
859f7df2e56Smrg * device's coordinate range.
860f7df2e56Smrg *
861f7df2e56Smrg * @param dev The device to scale for.
862f7df2e56Smrg * @param[in, out] mask The mask in desktop/screen coordinates, modified in place
863f7df2e56Smrg * to contain device coordinate range.
864f7df2e56Smrg * @param flags If POINTER_SCREEN is set, mask is in per-screen coordinates.
865f7df2e56Smrg *              Otherwise, mask is in desktop coords.
866f7df2e56Smrg */
867f7df2e56Smrgstatic void
868f7df2e56Smrgscale_from_screen(DeviceIntPtr dev, ValuatorMask *mask, int flags)
869f7df2e56Smrg{
870f7df2e56Smrg    double scaled;
871f7df2e56Smrg    ScreenPtr scr = miPointerGetScreen(dev);
872f7df2e56Smrg
873f7df2e56Smrg    if (valuator_mask_isset(mask, 0)) {
874f7df2e56Smrg        scaled = valuator_mask_get_double(mask, 0);
875f7df2e56Smrg        if (flags & POINTER_SCREEN)
876f7df2e56Smrg            scaled += scr->x;
877f7df2e56Smrg        scaled = rescaleValuatorAxis(scaled,
878f7df2e56Smrg                                     NULL, dev->valuator->axes + 0,
879f7df2e56Smrg                                     screenInfo.x, screenInfo.width);
880f7df2e56Smrg        valuator_mask_set_double(mask, 0, scaled);
881f7df2e56Smrg    }
882f7df2e56Smrg    if (valuator_mask_isset(mask, 1)) {
883f7df2e56Smrg        scaled = valuator_mask_get_double(mask, 1);
884f7df2e56Smrg        if (flags & POINTER_SCREEN)
885f7df2e56Smrg            scaled += scr->y;
886f7df2e56Smrg        scaled = rescaleValuatorAxis(scaled,
887f7df2e56Smrg                                     NULL, dev->valuator->axes + 1,
888f7df2e56Smrg                                     screenInfo.y, screenInfo.height);
889f7df2e56Smrg        valuator_mask_set_double(mask, 1, scaled);
890f7df2e56Smrg    }
891f7df2e56Smrg}
892f7df2e56Smrg
893f7df2e56Smrg/**
894f7df2e56Smrg * Scale from (absolute) device to screen coordinates here,
895f7df2e56Smrg *
896f7df2e56Smrg * The coordinates provided are always absolute. see fill_pointer_events for
897f7df2e56Smrg * information on coordinate systems.
898f7df2e56Smrg *
899f7df2e56Smrg * @param dev The device to be moved.
900f7df2e56Smrg * @param mask Mask of axis values for this event
901f7df2e56Smrg * @param[out] devx x desktop-wide coordinate in device coordinate system
902f7df2e56Smrg * @param[out] devy y desktop-wide coordinate in device coordinate system
903f7df2e56Smrg * @param[out] screenx x coordinate in desktop coordinate system
904f7df2e56Smrg * @param[out] screeny y coordinate in desktop coordinate system
905f7df2e56Smrg */
906f7df2e56Smrgstatic ScreenPtr
907f7df2e56Smrgscale_to_desktop(DeviceIntPtr dev, ValuatorMask *mask,
908f7df2e56Smrg                 double *devx, double *devy, double *screenx, double *screeny)
909f7df2e56Smrg{
910f7df2e56Smrg    ScreenPtr scr = miPointerGetScreen(dev);
911f7df2e56Smrg    double x, y;
912f7df2e56Smrg
913f7df2e56Smrg    BUG_WARN(dev->valuator && dev->valuator->numAxes < 2);
914f7df2e56Smrg    if (!dev->valuator || dev->valuator->numAxes < 2) {
915f7df2e56Smrg        /* if we have no axes, last.valuators must be in screen coords
916f7df2e56Smrg         * anyway */
917f7df2e56Smrg        *devx = *screenx = dev->last.valuators[0];
918f7df2e56Smrg        *devy = *screeny = dev->last.valuators[1];
919f7df2e56Smrg        return scr;
920f7df2e56Smrg    }
921f7df2e56Smrg
922f7df2e56Smrg    if (valuator_mask_isset(mask, 0))
923f7df2e56Smrg        x = valuator_mask_get_double(mask, 0);
924f7df2e56Smrg    else
925f7df2e56Smrg        x = dev->last.valuators[0];
926f7df2e56Smrg    if (valuator_mask_isset(mask, 1))
927f7df2e56Smrg        y = valuator_mask_get_double(mask, 1);
928f7df2e56Smrg    else
929f7df2e56Smrg        y = dev->last.valuators[1];
930f7df2e56Smrg
931f7df2e56Smrg    /* scale x&y to desktop coordinates */
932f7df2e56Smrg    *screenx = rescaleValuatorAxis(x, dev->valuator->axes + 0, NULL,
933f7df2e56Smrg                                   screenInfo.x, screenInfo.width);
934f7df2e56Smrg    *screeny = rescaleValuatorAxis(y, dev->valuator->axes + 1, NULL,
935f7df2e56Smrg                                   screenInfo.y, screenInfo.height);
936f7df2e56Smrg
937f7df2e56Smrg    *devx = x;
938f7df2e56Smrg    *devy = y;
939f7df2e56Smrg
940f7df2e56Smrg    return scr;
9414642e01fSmrg}
9424642e01fSmrg
9434642e01fSmrg/**
9444642e01fSmrg * If we have HW cursors, this actually moves the visible sprite. If not, we
9454642e01fSmrg * just do all the screen crossing, etc.
9464642e01fSmrg *
947f7df2e56Smrg * We use the screen coordinates here, call miPointerSetPosition() and then
948f7df2e56Smrg * scale back into device coordinates (if needed). miPSP will change x/y if
949f7df2e56Smrg * the screen was crossed.
950f7df2e56Smrg *
951f7df2e56Smrg * The coordinates provided are always absolute. The parameter mode
952f7df2e56Smrg * specifies whether it was relative or absolute movement that landed us at
953f7df2e56Smrg * those coordinates. see fill_pointer_events for information on coordinate
954f7df2e56Smrg * systems.
9554642e01fSmrg *
9564642e01fSmrg * @param dev The device to be moved.
957f7df2e56Smrg * @param mode Movement mode (Absolute or Relative)
958f7df2e56Smrg * @param[out] mask Mask of axis values for this event, returns the
959f7df2e56Smrg * per-screen device coordinates after confinement
960f7df2e56Smrg * @param[in,out] devx x desktop-wide coordinate in device coordinate system
961f7df2e56Smrg * @param[in,out] devy y desktop-wide coordinate in device coordinate system
962f7df2e56Smrg * @param[in,out] screenx x coordinate in desktop coordinate system
963f7df2e56Smrg * @param[in,out] screeny y coordinate in desktop coordinate system
964f7df2e56Smrg * @param[out] nevents Number of barrier events added to events
965f7df2e56Smrg * @param[in,out] events List of events barrier events are added to
9664642e01fSmrg */
967f7df2e56Smrgstatic ScreenPtr
968f7df2e56SmrgpositionSprite(DeviceIntPtr dev, int mode, ValuatorMask *mask,
969f7df2e56Smrg               double *devx, double *devy, double *screenx, double *screeny,
970f7df2e56Smrg               int *nevents, InternalEvent* events)
9714642e01fSmrg{
972f7df2e56Smrg    ScreenPtr scr = miPointerGetScreen(dev);
973f7df2e56Smrg    double tmpx, tmpy;
9744202a189Smrg
975f7df2e56Smrg    if (!dev->valuator || dev->valuator->numAxes < 2)
976f7df2e56Smrg        return scr;
9774202a189Smrg
978f7df2e56Smrg    tmpx = *screenx;
979f7df2e56Smrg    tmpy = *screeny;
9804202a189Smrg
981f7df2e56Smrg    /* miPointerSetPosition takes care of crossing screens for us, as well as
982f7df2e56Smrg     * clipping to the current screen. Coordinates returned are in desktop
983f7df2e56Smrg     * coord system */
984f7df2e56Smrg    scr = miPointerSetPosition(dev, mode, screenx, screeny, nevents, events);
985f7df2e56Smrg
986f7df2e56Smrg    /* If we were constrained, rescale x/y from the screen coordinates so
987f7df2e56Smrg     * the device valuators reflect the correct position. For screen
988f7df2e56Smrg     * crossing this doesn't matter much, the coords would be 0 or max.
989f7df2e56Smrg     */
990f7df2e56Smrg    if (tmpx != *screenx)
991f7df2e56Smrg        *devx = rescaleValuatorAxis(*screenx, NULL, dev->valuator->axes + 0,
992f7df2e56Smrg                                    screenInfo.x, screenInfo.width);
9934642e01fSmrg
994f7df2e56Smrg    if (tmpy != *screeny)
995f7df2e56Smrg        *devy = rescaleValuatorAxis(*screeny, NULL, dev->valuator->axes + 1,
996f7df2e56Smrg                                    screenInfo.y, screenInfo.height);
9974642e01fSmrg
998f7df2e56Smrg    /* Recalculate the per-screen device coordinates */
999f7df2e56Smrg    if (valuator_mask_isset(mask, 0)) {
1000f7df2e56Smrg        double x;
1001f7df2e56Smrg
1002f7df2e56Smrg        x = rescaleValuatorAxis(*screenx - scr->x, NULL,
1003f7df2e56Smrg                                dev->valuator->axes + 0, 0, scr->width);
1004f7df2e56Smrg        valuator_mask_set_double(mask, 0, x);
10054642e01fSmrg    }
1006f7df2e56Smrg    if (valuator_mask_isset(mask, 1)) {
1007f7df2e56Smrg        double y;
10084642e01fSmrg
1009f7df2e56Smrg        y = rescaleValuatorAxis(*screeny - scr->y, NULL,
1010f7df2e56Smrg                                dev->valuator->axes + 1, 0, scr->height);
1011f7df2e56Smrg        valuator_mask_set_double(mask, 1, y);
10124642e01fSmrg    }
10134642e01fSmrg
1014f7df2e56Smrg    return scr;
10154642e01fSmrg}
10164642e01fSmrg
10174642e01fSmrg/**
10184642e01fSmrg * Update the motion history for the device and (if appropriate) for its
10194642e01fSmrg * master device.
10204642e01fSmrg * @param dev Slave device to update.
102165b04b38Smrg * @param mask Bit mask of valid valuators to append to history.
10224642e01fSmrg * @param num Total number of valuators to append to history.
10234642e01fSmrg * @param ms Current time
10244642e01fSmrg */
10254642e01fSmrgstatic void
102665b04b38SmrgupdateHistory(DeviceIntPtr dev, ValuatorMask *mask, CARD32 ms)
10274642e01fSmrg{
102865b04b38Smrg    if (!dev->valuator)
102965b04b38Smrg        return;
103065b04b38Smrg
103165b04b38Smrg    updateMotionHistory(dev, ms, mask, dev->last.valuators);
1032f7df2e56Smrg    if (!IsMaster(dev) && !IsFloating(dev)) {
10334202a189Smrg        DeviceIntPtr master = GetMaster(dev, MASTER_POINTER);
1034f7df2e56Smrg
103565b04b38Smrg        updateMotionHistory(master, ms, mask, dev->last.valuators);
10364202a189Smrg    }
10374642e01fSmrg}
103805b261ecSmrg
1039f7df2e56Smrgstatic void
1040f7df2e56SmrgqueueEventList(DeviceIntPtr device, InternalEvent *events, int nevents)
1041f7df2e56Smrg{
1042f7df2e56Smrg    int i;
1043f7df2e56Smrg
1044f7df2e56Smrg    for (i = 0; i < nevents; i++)
1045f7df2e56Smrg        mieqEnqueue(device, &events[i]);
1046f7df2e56Smrg}
1047f7df2e56Smrg
1048f7df2e56Smrgstatic void
1049f7df2e56Smrgevent_set_root_coordinates(DeviceEvent *event, double x, double y)
1050f7df2e56Smrg{
1051f7df2e56Smrg    event->root_x = trunc(x);
1052f7df2e56Smrg    event->root_y = trunc(y);
1053f7df2e56Smrg    event->root_x_frac = x - trunc(x);
1054f7df2e56Smrg    event->root_y_frac = y - trunc(y);
1055f7df2e56Smrg}
1056f7df2e56Smrg
105705b261ecSmrg/**
1058f7df2e56Smrg * Generate internal events representing this keyboard event and enqueue
1059f7df2e56Smrg * them on the event queue.
1060f7df2e56Smrg *
1061f7df2e56Smrg * This function is not reentrant. Disable signals before calling.
1062f7df2e56Smrg *
1063f7df2e56Smrg * @param device The device to generate the event for
1064f7df2e56Smrg * @param type Event type, one of KeyPress or KeyRelease
1065f7df2e56Smrg * @param keycode Key code of the pressed/released key
1066f7df2e56Smrg *
106705b261ecSmrg */
1068f7df2e56Smrgvoid
1069f7df2e56SmrgQueueKeyboardEvents(DeviceIntPtr device, int type,
1070f7df2e56Smrg                    int keycode)
1071f7df2e56Smrg{
1072f7df2e56Smrg    int nevents;
107365b04b38Smrg
1074f7df2e56Smrg    nevents = GetKeyboardEvents(InputEventList, device, type, keycode);
1075f7df2e56Smrg    queueEventList(device, InputEventList, nevents);
107605b261ecSmrg}
107705b261ecSmrg
107805b261ecSmrg/**
107965b04b38Smrg * Returns a set of InternalEvents for KeyPress/KeyRelease, optionally
108065b04b38Smrg * also with valuator events.
10814642e01fSmrg *
1082f7df2e56Smrg * The DDX is responsible for allocating the event list in the first
1083f7df2e56Smrg * place via InitEventList(), and for freeing it.
1084f7df2e56Smrg *
1085f7df2e56Smrg * @return the number of events written into events.
108605b261ecSmrg */
10874202a189Smrgint
1088f7df2e56SmrgGetKeyboardEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
1089f7df2e56Smrg                  int key_code)
1090f7df2e56Smrg{
10914202a189Smrg    int num_events = 0;
109205b261ecSmrg    CARD32 ms = 0;
10934202a189Smrg    DeviceEvent *event;
10944202a189Smrg    RawDeviceEvent *raw;
1095f7df2e56Smrg
1096f7df2e56Smrg#if XSERVER_DTRACE
1097f7df2e56Smrg    if (XSERVER_INPUT_EVENT_ENABLED()) {
1098f7df2e56Smrg        XSERVER_INPUT_EVENT(pDev->id, type, key_code, 0, 0,
1099f7df2e56Smrg                            NULL, NULL);
1100f7df2e56Smrg    }
1101f7df2e56Smrg#endif
11024202a189Smrg
11034202a189Smrg    /* refuse events from disabled devices */
11044202a189Smrg    if (!pDev->enabled)
11054202a189Smrg        return 0;
110605b261ecSmrg
1107f7df2e56Smrg    if (!events || !pDev->key || !pDev->focus || !pDev->kbdfeed ||
1108f7df2e56Smrg        (type != KeyPress && type != KeyRelease) ||
1109f7df2e56Smrg        (key_code < 8 || key_code > 255))
111005b261ecSmrg        return 0;
111105b261ecSmrg
11124202a189Smrg    num_events = 1;
111305b261ecSmrg
1114f7df2e56Smrg    events =
1115f7df2e56Smrg        UpdateFromMaster(events, pDev, DEVCHANGE_KEYBOARD_EVENT, &num_events);
111605b261ecSmrg
11174202a189Smrg    /* Handle core repeating, via press/release/press/release. */
11184202a189Smrg    if (type == KeyPress && key_is_down(pDev, key_code, KEY_POSTED)) {
111905b261ecSmrg        /* If autorepeating is disabled either globally or just for that key,
112005b261ecSmrg         * or we have a modifier, don't generate a repeat event. */
112105b261ecSmrg        if (!pDev->kbdfeed->ctrl.autoRepeat ||
112205b261ecSmrg            !key_autorepeats(pDev, key_code) ||
11234202a189Smrg            pDev->key->xkbInfo->desc->map->modmap[key_code])
112405b261ecSmrg            return 0;
112505b261ecSmrg    }
112605b261ecSmrg
112705b261ecSmrg    ms = GetTimeInMillis();
112805b261ecSmrg
1129f7df2e56Smrg    raw = &events->raw_event;
11304202a189Smrg    events++;
11314202a189Smrg    num_events++;
11324202a189Smrg
11334202a189Smrg    init_raw(pDev, raw, ms, type, key_code);
11344202a189Smrg
1135f7df2e56Smrg    event = &events->device_event;
1136f7df2e56Smrg    init_device_event(event, pDev, ms);
11374202a189Smrg    event->detail.key = key_code;
11384202a189Smrg
113905b261ecSmrg    if (type == KeyPress) {
11404202a189Smrg        event->type = ET_KeyPress;
1141f7df2e56Smrg        set_key_down(pDev, key_code, KEY_POSTED);
114205b261ecSmrg    }
114305b261ecSmrg    else if (type == KeyRelease) {
11444202a189Smrg        event->type = ET_KeyRelease;
1145f7df2e56Smrg        set_key_up(pDev, key_code, KEY_POSTED);
114605b261ecSmrg    }
114705b261ecSmrg
11484202a189Smrg    return num_events;
114905b261ecSmrg}
115005b261ecSmrg
11514642e01fSmrg/**
1152f7df2e56Smrg * Initialize an event array large enough for num_events arrays.
11534642e01fSmrg * This event list is to be passed into GetPointerEvents() and
11544642e01fSmrg * GetKeyboardEvents().
11554642e01fSmrg *
11564642e01fSmrg * @param num_events Number of elements in list.
11574642e01fSmrg */
1158f7df2e56SmrgInternalEvent *
11594642e01fSmrgInitEventList(int num_events)
11604642e01fSmrg{
1161f7df2e56Smrg    InternalEvent *events = calloc(num_events, sizeof(InternalEvent));
11624642e01fSmrg
11634642e01fSmrg    return events;
11644642e01fSmrg}
11654642e01fSmrg
11664642e01fSmrg/**
11674642e01fSmrg * Free an event list.
11684642e01fSmrg *
11694642e01fSmrg * @param list The list to be freed.
11704642e01fSmrg * @param num_events Number of elements in list.
11714642e01fSmrg */
11724202a189Smrgvoid
1173f7df2e56SmrgFreeEventList(InternalEvent *list, int num_events)
11744642e01fSmrg{
11754202a189Smrg    free(list);
11764202a189Smrg}
11774202a189Smrg
1178f7df2e56Smrg/**
1179f7df2e56Smrg * Transform vector x/y according to matrix m and drop the rounded coords
1180f7df2e56Smrg * back into x/y.
1181f7df2e56Smrg */
1182f7df2e56Smrgstatic void
1183f7df2e56Smrgtransform(struct pixman_f_transform *m, double *x, double *y)
1184f7df2e56Smrg{
1185f7df2e56Smrg    struct pixman_f_vector p = {.v = {*x, *y, 1} };
1186f7df2e56Smrg    pixman_f_transform_point(m, &p);
1187f7df2e56Smrg
1188f7df2e56Smrg    *x = p.v[0];
1189f7df2e56Smrg    *y = p.v[1];
1190f7df2e56Smrg}
1191f7df2e56Smrg
1192f7df2e56Smrgstatic void
1193f7df2e56SmrgtransformRelative(DeviceIntPtr dev, ValuatorMask *mask)
1194f7df2e56Smrg{
1195f7df2e56Smrg    double x = 0, y = 0;
1196f7df2e56Smrg
1197f7df2e56Smrg    valuator_mask_fetch_double(mask, 0, &x);
1198f7df2e56Smrg    valuator_mask_fetch_double(mask, 1, &y);
1199f7df2e56Smrg
1200f7df2e56Smrg    transform(&dev->relative_transform, &x, &y);
1201f7df2e56Smrg
1202f7df2e56Smrg    if (x)
1203f7df2e56Smrg        valuator_mask_set_double(mask, 0, x);
1204f7df2e56Smrg    else
1205f7df2e56Smrg        valuator_mask_unset(mask, 0);
1206f7df2e56Smrg
1207f7df2e56Smrg    if (y)
1208f7df2e56Smrg        valuator_mask_set_double(mask, 1, y);
1209f7df2e56Smrg    else
1210f7df2e56Smrg        valuator_mask_unset(mask, 1);
1211f7df2e56Smrg}
1212f7df2e56Smrg
1213f7df2e56Smrg/**
1214f7df2e56Smrg * Apply the device's transformation matrix to the valuator mask and replace
1215f7df2e56Smrg * the scaled values in mask. This transformation only applies to valuators
1216f7df2e56Smrg * 0 and 1, others will be untouched.
1217f7df2e56Smrg *
1218f7df2e56Smrg * @param dev The device the valuators came from
1219f7df2e56Smrg * @param[in,out] mask The valuator mask.
1220f7df2e56Smrg */
12214202a189Smrgstatic void
122265b04b38SmrgtransformAbsolute(DeviceIntPtr dev, ValuatorMask *mask)
12234202a189Smrg{
1224f7df2e56Smrg    double x, y, ox, oy;
1225f7df2e56Smrg    int has_x, has_y;
12264202a189Smrg
1227f7df2e56Smrg    has_x = valuator_mask_isset(mask, 0);
1228f7df2e56Smrg    has_y = valuator_mask_isset(mask, 1);
12294202a189Smrg
1230f7df2e56Smrg    if (!has_x && !has_y)
1231f7df2e56Smrg        return;
12324202a189Smrg
1233f7df2e56Smrg    if (!has_x || !has_y) {
1234f7df2e56Smrg        struct pixman_f_transform invert;
1235f7df2e56Smrg
1236f7df2e56Smrg        /* undo transformation from last event */
1237f7df2e56Smrg        ox = dev->last.valuators[0];
1238f7df2e56Smrg        oy = dev->last.valuators[1];
1239f7df2e56Smrg
1240f7df2e56Smrg        pixman_f_transform_invert(&invert, &dev->scale_and_transform);
1241f7df2e56Smrg        transform(&invert, &ox, &oy);
1242f7df2e56Smrg    }
1243f7df2e56Smrg
1244f7df2e56Smrg    if (has_x)
1245f7df2e56Smrg        ox = valuator_mask_get_double(mask, 0);
1246f7df2e56Smrg
1247f7df2e56Smrg    if (has_y)
1248f7df2e56Smrg        oy = valuator_mask_get_double(mask, 1);
1249f7df2e56Smrg
1250f7df2e56Smrg    x = ox;
1251f7df2e56Smrg    y = oy;
1252f7df2e56Smrg
1253f7df2e56Smrg    transform(&dev->scale_and_transform, &x, &y);
1254f7df2e56Smrg
1255f7df2e56Smrg    if (has_x || ox != x)
1256f7df2e56Smrg        valuator_mask_set_double(mask, 0, x);
1257f7df2e56Smrg
1258f7df2e56Smrg    if (has_y || oy != y)
1259f7df2e56Smrg        valuator_mask_set_double(mask, 1, y);
1260f7df2e56Smrg}
1261f7df2e56Smrg
1262f7df2e56Smrgstatic void
1263f7df2e56SmrgstoreLastValuators(DeviceIntPtr dev, ValuatorMask *mask,
1264f7df2e56Smrg                   int xaxis, int yaxis, double devx, double devy)
1265f7df2e56Smrg{
1266f7df2e56Smrg    int i;
1267f7df2e56Smrg
1268f7df2e56Smrg    /* store desktop-wide in last.valuators */
1269f7df2e56Smrg    if (valuator_mask_isset(mask, xaxis))
1270f7df2e56Smrg        dev->last.valuators[0] = devx;
1271f7df2e56Smrg    if (valuator_mask_isset(mask, yaxis))
1272f7df2e56Smrg        dev->last.valuators[1] = devy;
1273f7df2e56Smrg
1274f7df2e56Smrg    for (i = 0; i < valuator_mask_size(mask); i++) {
1275f7df2e56Smrg        if (i == xaxis || i == yaxis)
1276f7df2e56Smrg            continue;
1277f7df2e56Smrg
1278f7df2e56Smrg        if (valuator_mask_isset(mask, i))
1279f7df2e56Smrg            dev->last.valuators[i] = valuator_mask_get_double(mask, i);
1280f7df2e56Smrg    }
128145bb0b75Smrg
12824642e01fSmrg}
128305b261ecSmrg
128405b261ecSmrg/**
1285f7df2e56Smrg * Generate internal events representing this pointer event and enqueue them
1286f7df2e56Smrg * on the event queue.
128705b261ecSmrg *
1288f7df2e56Smrg * This function is not reentrant. Disable signals before calling.
12894642e01fSmrg *
1290f7df2e56Smrg * @param device The device to generate the event for
1291f7df2e56Smrg * @param type Event type, one of ButtonPress, ButtonRelease, MotionNotify
1292f7df2e56Smrg * @param buttons Button number of the buttons modified. Must be 0 for
1293f7df2e56Smrg * MotionNotify
1294f7df2e56Smrg * @param flags Event modification flags
1295f7df2e56Smrg * @param mask Valuator mask for valuators present for this event.
1296f7df2e56Smrg */
1297f7df2e56Smrgvoid
1298f7df2e56SmrgQueuePointerEvents(DeviceIntPtr device, int type,
1299f7df2e56Smrg                   int buttons, int flags, const ValuatorMask *mask)
1300f7df2e56Smrg{
1301f7df2e56Smrg    int nevents;
1302f7df2e56Smrg
1303f7df2e56Smrg    nevents =
1304f7df2e56Smrg        GetPointerEvents(InputEventList, device, type, buttons, flags, mask);
1305f7df2e56Smrg    queueEventList(device, InputEventList, nevents);
1306f7df2e56Smrg}
1307f7df2e56Smrg
1308f7df2e56Smrg/**
1309f7df2e56Smrg * Helper function for GetPointerEvents, which only generates motion and
1310f7df2e56Smrg * raw motion events for the slave device: does not update the master device.
13114642e01fSmrg *
1312f7df2e56Smrg * Should not be called by anyone other than GetPointerEvents.
13134642e01fSmrg *
1314f7df2e56Smrg * We use several different coordinate systems and need to switch between
1315f7df2e56Smrg * the three in fill_pointer_events, positionSprite and
1316f7df2e56Smrg * miPointerSetPosition. "desktop" refers to the width/height of all
1317f7df2e56Smrg * screenInfo.screens[n]->width/height added up. "screen" is ScreenRec, not
1318f7df2e56Smrg * output.
1319f7df2e56Smrg *
1320f7df2e56Smrg * Coordinate systems:
1321f7df2e56Smrg * - relative events have a mask_in in relative coordinates, mapped to
1322f7df2e56Smrg *   pixels. These events are mapped to the current position±delta.
1323f7df2e56Smrg * - absolute events have a mask_in in absolute device coordinates in
1324f7df2e56Smrg *   device-specific range. This range is mapped to the desktop.
1325f7df2e56Smrg * - POINTER_SCREEN absolute events (x86WarpCursor) are in screen-relative
1326f7df2e56Smrg *   screen coordinate range.
1327f7df2e56Smrg * - rootx/rooty in events must be be relative to the current screen's
1328f7df2e56Smrg *   origin (screen coordinate system)
1329f7df2e56Smrg * - XI2 valuators must be relative to the current screen's origin. On
1330f7df2e56Smrg *   the protocol the device min/max range maps to the current screen.
1331f7df2e56Smrg *
1332f7df2e56Smrg * For screen switching we need to get the desktop coordinates for each
1333f7df2e56Smrg * event, then map that to the respective position on each screen and
1334f7df2e56Smrg * position the cursor there.
1335f7df2e56Smrg * The device's last.valuator[] stores the last position in desktop-wide
1336f7df2e56Smrg * coordinates (in device range for slave devices, desktop range for master
1337f7df2e56Smrg * devices).
1338f7df2e56Smrg *
1339f7df2e56Smrg * screen-relative device coordinates requires scaling: A device coordinate
1340f7df2e56Smrg * x/y of range [n..m] that maps to positions Sx/Sy on Screen S must be
1341f7df2e56Smrg * rescaled to match Sx/Sy for [n..m]. In the simplest example, x of (m/2-1)
1342f7df2e56Smrg * is the last coordinate on the first screen and must be rescaled for the
1343f7df2e56Smrg * event to be m. XI2 clients that do their own coordinate mapping would
1344f7df2e56Smrg * otherwise interpret the position of the device elsewere to the cursor.
1345f7df2e56Smrg * However, this scaling leads to losses:
1346f7df2e56Smrg * if we have two ScreenRecs we scale from e.g. [0..44704]  (Wacom I4) to
1347f7df2e56Smrg * [0..2048[. that gives us 2047.954 as desktop coord, or the per-screen
1348f7df2e56Smrg * coordinate 1023.954. Scaling that back into the device coordinate range
1349f7df2e56Smrg * gives us 44703. So off by one device unit. It's a bug, but we'll have to
1350f7df2e56Smrg * live with it because with all this scaling, we just cannot win.
1351f7df2e56Smrg *
1352f7df2e56Smrg * @return the number of events written into events.
135305b261ecSmrg */
1354f7df2e56Smrgstatic int
1355f7df2e56Smrgfill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type,
1356f7df2e56Smrg                    int buttons, CARD32 ms, int flags,
1357f7df2e56Smrg                    const ValuatorMask *mask_in)
1358f7df2e56Smrg{
13594642e01fSmrg    int num_events = 1;
13604202a189Smrg    DeviceEvent *event;
1361f7df2e56Smrg    RawDeviceEvent *raw = NULL;
1362f7df2e56Smrg    double screenx = 0.0, screeny = 0.0;        /* desktop coordinate system */
1363f7df2e56Smrg    double devx = 0.0, devy = 0.0;      /* desktop-wide in device coords */
1364f7df2e56Smrg    int sx = 0, sy = 0;                 /* for POINTER_SCREEN */
136565b04b38Smrg    ValuatorMask mask;
1366f7df2e56Smrg    ScreenPtr scr;
1367f7df2e56Smrg    int num_barrier_events = 0;
1368f7df2e56Smrg
1369f7df2e56Smrg    switch (type) {
1370f7df2e56Smrg    case MotionNotify:
1371f7df2e56Smrg        if (!pDev->valuator) {
1372f7df2e56Smrg            ErrorF("[dix] motion events from device %d without valuators\n",
1373f7df2e56Smrg                   pDev->id);
1374f7df2e56Smrg            return 0;
1375f7df2e56Smrg        }
1376f7df2e56Smrg        if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0)
1377f7df2e56Smrg            return 0;
1378f7df2e56Smrg        break;
1379f7df2e56Smrg    case ButtonPress:
1380f7df2e56Smrg    case ButtonRelease:
1381f7df2e56Smrg        if (!pDev->button || !buttons)
1382f7df2e56Smrg            return 0;
1383f7df2e56Smrg        if (mask_in && valuator_mask_size(mask_in) > 0 && !pDev->valuator) {
1384f7df2e56Smrg            ErrorF
1385f7df2e56Smrg                ("[dix] button event with valuator from device %d without valuators\n",
1386f7df2e56Smrg                 pDev->id);
1387f7df2e56Smrg            return 0;
1388f7df2e56Smrg        }
1389f7df2e56Smrg        break;
1390f7df2e56Smrg    default:
13914202a189Smrg        return 0;
1392f7df2e56Smrg    }
139305b261ecSmrg
1394f7df2e56Smrg    valuator_mask_copy(&mask, mask_in);
139505b261ecSmrg
1396f7df2e56Smrg    if ((flags & POINTER_NORAW) == 0) {
1397f7df2e56Smrg        raw = &events->raw_event;
1398f7df2e56Smrg        events++;
1399f7df2e56Smrg        num_events++;
1400f7df2e56Smrg
1401f7df2e56Smrg        init_raw(pDev, raw, ms, type, buttons);
1402f7df2e56Smrg        set_raw_valuators(raw, &mask, TRUE, raw->valuators.data_raw);
140365b04b38Smrg    }
140465b04b38Smrg
1405f7df2e56Smrg    valuator_mask_drop_unaccelerated(&mask);
140665b04b38Smrg
1407f7df2e56Smrg    /* valuators are in driver-native format (rel or abs) */
14084202a189Smrg
1409f7df2e56Smrg    if (flags & POINTER_ABSOLUTE) {
1410f7df2e56Smrg        if (flags & (POINTER_SCREEN | POINTER_DESKTOP)) {    /* valuators are in screen/desktop coords */
1411f7df2e56Smrg            sx = valuator_mask_get(&mask, 0);
1412f7df2e56Smrg            sy = valuator_mask_get(&mask, 1);
1413f7df2e56Smrg            scale_from_screen(pDev, &mask, flags);
1414f7df2e56Smrg        }
14154202a189Smrg
1416f7df2e56Smrg        transformAbsolute(pDev, &mask);
1417f7df2e56Smrg        clipAbsolute(pDev, &mask);
1418f7df2e56Smrg        if ((flags & POINTER_NORAW) == 0 && raw)
1419f7df2e56Smrg            set_raw_valuators(raw, &mask, FALSE, raw->valuators.data);
1420f7df2e56Smrg    }
1421f7df2e56Smrg    else {
1422f7df2e56Smrg        transformRelative(pDev, &mask);
1423f7df2e56Smrg
1424f7df2e56Smrg        if (flags & POINTER_ACCELERATE)
1425f7df2e56Smrg            accelPointer(pDev, &mask, ms);
1426f7df2e56Smrg        if ((flags & POINTER_NORAW) == 0 && raw)
1427f7df2e56Smrg            set_raw_valuators(raw, &mask, FALSE, raw->valuators.data);
142845bb0b75Smrg
1429f7df2e56Smrg        moveRelative(pDev, flags, &mask);
143045bb0b75Smrg    }
143105b261ecSmrg
1432f7df2e56Smrg    /* valuators are in device coordinate system in absolute coordinates */
1433f7df2e56Smrg    scale_to_desktop(pDev, &mask, &devx, &devy, &screenx, &screeny);
143405b261ecSmrg
1435f7df2e56Smrg    /* #53037 XWarpPointer's scaling back and forth between screen and
1436f7df2e56Smrg       device may leave us with rounding errors. End result is that the
1437f7df2e56Smrg       pointer doesn't end up on the pixel it should.
1438f7df2e56Smrg       Avoid this by forcing screenx/screeny back to what the input
1439f7df2e56Smrg       coordinates were.
1440f7df2e56Smrg     */
1441f7df2e56Smrg    if (flags & POINTER_SCREEN) {
1442f7df2e56Smrg        scr = miPointerGetScreen(pDev);
1443f7df2e56Smrg        screenx = sx + scr->x;
1444f7df2e56Smrg        screeny = sy + scr->y;
144505b261ecSmrg    }
144605b261ecSmrg
1447f7df2e56Smrg    scr = positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative,
1448f7df2e56Smrg                         &mask, &devx, &devy, &screenx, &screeny,
1449f7df2e56Smrg                         &num_barrier_events, events);
1450f7df2e56Smrg    num_events += num_barrier_events;
1451f7df2e56Smrg    events += num_barrier_events;
145205b261ecSmrg
1453f7df2e56Smrg    /* screenx, screeny are in desktop coordinates,
1454f7df2e56Smrg       mask is in device coordinates per-screen (the event data)
1455f7df2e56Smrg       devx/devy is in device coordinate desktop-wide */
145665b04b38Smrg    updateHistory(pDev, &mask, ms);
145705b261ecSmrg
145865b04b38Smrg    clipValuators(pDev, &mask);
14594202a189Smrg
1460f7df2e56Smrg    storeLastValuators(pDev, &mask, 0, 1, devx, devy);
1461f7df2e56Smrg
1462f7df2e56Smrg    /* Update the MD's co-ordinates, which are always in desktop space. */
1463f7df2e56Smrg    if (!IsMaster(pDev) && !IsFloating(pDev)) {
1464f7df2e56Smrg        DeviceIntPtr master = GetMaster(pDev, MASTER_POINTER);
1465f7df2e56Smrg
1466f7df2e56Smrg        master->last.valuators[0] = screenx;
1467f7df2e56Smrg        master->last.valuators[1] = screeny;
1468f7df2e56Smrg    }
1469f7df2e56Smrg
1470f7df2e56Smrg    event = &events->device_event;
1471f7df2e56Smrg    init_device_event(event, pDev, ms);
147205b261ecSmrg
14734642e01fSmrg    if (type == MotionNotify) {
14744202a189Smrg        event->type = ET_Motion;
14754202a189Smrg        event->detail.button = 0;
14764642e01fSmrg    }
14774642e01fSmrg    else {
14784202a189Smrg        if (type == ButtonPress) {
14794202a189Smrg            event->type = ET_ButtonPress;
14804202a189Smrg            set_button_down(pDev, buttons, BUTTON_POSTED);
14814202a189Smrg        }
14824202a189Smrg        else if (type == ButtonRelease) {
14834202a189Smrg            event->type = ET_ButtonRelease;
14844202a189Smrg            set_button_up(pDev, buttons, BUTTON_POSTED);
14854202a189Smrg        }
14864202a189Smrg        event->detail.button = buttons;
14874642e01fSmrg    }
148805b261ecSmrg
1489f7df2e56Smrg    /* root_x and root_y must be in per-screen co-ordinates */
1490f7df2e56Smrg    event_set_root_coordinates(event, screenx - scr->x, screeny - scr->y);
1491f7df2e56Smrg
1492f7df2e56Smrg    if (flags & POINTER_EMULATED) {
1493f7df2e56Smrg        if (raw)
1494f7df2e56Smrg            raw->flags = XIPointerEmulated;
1495f7df2e56Smrg        event->flags = XIPointerEmulated;
1496f7df2e56Smrg    }
149705b261ecSmrg
149865b04b38Smrg    set_valuators(pDev, event, &mask);
149905b261ecSmrg
150005b261ecSmrg    return num_events;
150105b261ecSmrg}
150205b261ecSmrg
1503f7df2e56Smrg/**
1504f7df2e56Smrg * Generate events for each scroll axis that changed between before/after
1505f7df2e56Smrg * for the device.
1506f7df2e56Smrg *
1507f7df2e56Smrg * @param events The pointer to the event list to fill the events
1508f7df2e56Smrg * @param dev The device to generate the events for
1509f7df2e56Smrg * @param type The real type of the event
1510f7df2e56Smrg * @param axis The axis number to generate events for
1511f7df2e56Smrg * @param mask State before this event in absolute coords
1512f7df2e56Smrg * @param[in,out] last Last scroll state posted in absolute coords (modified
1513f7df2e56Smrg * in-place)
1514f7df2e56Smrg * @param ms Current time in ms
1515f7df2e56Smrg * @param max_events Max number of events to be generated
1516f7df2e56Smrg * @return The number of events generated
1517f7df2e56Smrg */
1518f7df2e56Smrgstatic int
1519f7df2e56Smrgemulate_scroll_button_events(InternalEvent *events,
1520f7df2e56Smrg                             DeviceIntPtr dev,
1521f7df2e56Smrg                             int type,
1522f7df2e56Smrg                             int axis,
1523f7df2e56Smrg                             const ValuatorMask *mask,
1524f7df2e56Smrg                             ValuatorMask *last, CARD32 ms, int max_events)
1525f7df2e56Smrg{
1526f7df2e56Smrg    AxisInfoPtr ax;
1527f7df2e56Smrg    double delta;
1528f7df2e56Smrg    double incr;
1529f7df2e56Smrg    int num_events = 0;
1530f7df2e56Smrg    double total;
1531f7df2e56Smrg    int b;
1532f7df2e56Smrg    int flags = 0;
1533f7df2e56Smrg
1534f7df2e56Smrg    if (dev->valuator->axes[axis].scroll.type == SCROLL_TYPE_NONE)
1535f7df2e56Smrg        return 0;
1536f7df2e56Smrg
1537f7df2e56Smrg    if (!valuator_mask_isset(mask, axis))
1538f7df2e56Smrg        return 0;
1539f7df2e56Smrg
1540f7df2e56Smrg    ax = &dev->valuator->axes[axis];
1541f7df2e56Smrg    incr = ax->scroll.increment;
1542f7df2e56Smrg
1543f7df2e56Smrg    BUG_WARN_MSG(incr == 0, "for device %s\n", dev->name);
1544f7df2e56Smrg    if (incr == 0)
1545f7df2e56Smrg        return 0;
1546f7df2e56Smrg
1547f7df2e56Smrg    if (type != ButtonPress && type != ButtonRelease)
1548f7df2e56Smrg        flags |= POINTER_EMULATED;
1549f7df2e56Smrg
1550f7df2e56Smrg    if (!valuator_mask_isset(last, axis))
1551f7df2e56Smrg        valuator_mask_set_double(last, axis, 0);
1552f7df2e56Smrg
1553f7df2e56Smrg    delta =
1554f7df2e56Smrg        valuator_mask_get_double(mask, axis) - valuator_mask_get_double(last,
1555f7df2e56Smrg                                                                        axis);
1556f7df2e56Smrg    total = delta;
1557f7df2e56Smrg    b = (ax->scroll.type == SCROLL_TYPE_VERTICAL) ? 5 : 7;
1558f7df2e56Smrg
1559f7df2e56Smrg    if ((incr > 0 && delta < 0) || (incr < 0 && delta > 0))
1560f7df2e56Smrg        b--;                    /* we're scrolling up or left → button 4 or 6 */
1561f7df2e56Smrg
1562f7df2e56Smrg    while (fabs(delta) >= fabs(incr)) {
1563f7df2e56Smrg        int nev_tmp;
1564f7df2e56Smrg
1565f7df2e56Smrg        if (delta > 0)
1566f7df2e56Smrg            delta -= fabs(incr);
1567f7df2e56Smrg        else if (delta < 0)
1568f7df2e56Smrg            delta += fabs(incr);
1569f7df2e56Smrg
1570f7df2e56Smrg        /* fill_pointer_events() generates four events: one normal and one raw
1571f7df2e56Smrg         * event for button press and button release.
1572f7df2e56Smrg         * We may get a bigger scroll delta than we can generate events
1573f7df2e56Smrg         * for. In that case, we keep decreasing delta, but skip events.
1574f7df2e56Smrg         */
1575f7df2e56Smrg        if (num_events + 4 < max_events) {
1576f7df2e56Smrg            if (type != ButtonRelease) {
1577f7df2e56Smrg                nev_tmp = fill_pointer_events(events, dev, ButtonPress, b, ms,
1578f7df2e56Smrg                                              flags, NULL);
1579f7df2e56Smrg                events += nev_tmp;
1580f7df2e56Smrg                num_events += nev_tmp;
1581f7df2e56Smrg            }
1582f7df2e56Smrg            if (type != ButtonPress) {
1583f7df2e56Smrg                nev_tmp = fill_pointer_events(events, dev, ButtonRelease, b, ms,
1584f7df2e56Smrg                                              flags, NULL);
1585f7df2e56Smrg                events += nev_tmp;
1586f7df2e56Smrg                num_events += nev_tmp;
1587f7df2e56Smrg            }
1588f7df2e56Smrg        }
1589f7df2e56Smrg    }
1590f7df2e56Smrg
1591f7df2e56Smrg    /* We emulated, update last.scroll */
1592f7df2e56Smrg    if (total != delta) {
1593f7df2e56Smrg        total -= delta;
1594f7df2e56Smrg        valuator_mask_set_double(last, axis,
1595f7df2e56Smrg                                 valuator_mask_get_double(last, axis) + total);
1596f7df2e56Smrg    }
1597f7df2e56Smrg
1598f7df2e56Smrg    return num_events;
1599f7df2e56Smrg}
1600f7df2e56Smrg
160105b261ecSmrg
160205b261ecSmrg/**
1603f7df2e56Smrg * Generate a complete series of InternalEvents (filled into the EventList)
1604f7df2e56Smrg * representing pointer motion, or button presses.  If the device is a slave
1605f7df2e56Smrg * device, also potentially generate a DeviceClassesChangedEvent to update
1606f7df2e56Smrg * the master device.
160705b261ecSmrg *
160805b261ecSmrg * events is not NULL-terminated; the return value is the number of events.
160905b261ecSmrg * The DDX is responsible for allocating the event structure in the first
1610f7df2e56Smrg * place via InitEventList() and GetMaximumEventsNum(), and for freeing it.
1611f7df2e56Smrg *
1612f7df2e56Smrg * In the generated events rootX/Y will be in absolute screen coords and
1613f7df2e56Smrg * the valuator information in the absolute or relative device coords.
1614f7df2e56Smrg *
1615f7df2e56Smrg * last.valuators[x] of the device is always in absolute device coords.
1616f7df2e56Smrg * last.valuators[x] of the master device is in absolute screen coords.
1617f7df2e56Smrg *
1618f7df2e56Smrg * master->last.valuators[x] for x > 2 is undefined.
1619f7df2e56Smrg */
1620f7df2e56Smrgint
1621f7df2e56SmrgGetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
1622f7df2e56Smrg                 int buttons, int flags, const ValuatorMask *mask_in)
1623f7df2e56Smrg{
1624f7df2e56Smrg    CARD32 ms = GetTimeInMillis();
1625f7df2e56Smrg    int num_events = 0, nev_tmp;
1626f7df2e56Smrg    ValuatorMask mask;
1627f7df2e56Smrg    ValuatorMask scroll;
1628f7df2e56Smrg    int i;
1629f7df2e56Smrg    int realtype = type;
1630f7df2e56Smrg
1631f7df2e56Smrg#if XSERVER_DTRACE
1632f7df2e56Smrg    if (XSERVER_INPUT_EVENT_ENABLED()) {
1633f7df2e56Smrg        XSERVER_INPUT_EVENT(pDev->id, type, buttons, flags,
1634f7df2e56Smrg                            mask_in ? mask_in->last_bit + 1 : 0,
1635f7df2e56Smrg                            mask_in ? mask_in->mask : NULL,
1636f7df2e56Smrg                            mask_in ? mask_in->valuators : NULL);
1637f7df2e56Smrg    }
1638f7df2e56Smrg#endif
1639f7df2e56Smrg
1640f7df2e56Smrg    BUG_RETURN_VAL(buttons >= MAX_BUTTONS, 0);
1641f7df2e56Smrg
1642f7df2e56Smrg    /* refuse events from disabled devices */
1643f7df2e56Smrg    if (!pDev->enabled)
1644f7df2e56Smrg        return 0;
1645f7df2e56Smrg
1646f7df2e56Smrg    if (!miPointerGetScreen(pDev))
1647f7df2e56Smrg        return 0;
1648f7df2e56Smrg
1649f7df2e56Smrg    events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT,
1650f7df2e56Smrg                              &num_events);
1651f7df2e56Smrg
1652f7df2e56Smrg    valuator_mask_copy(&mask, mask_in);
1653f7df2e56Smrg
1654f7df2e56Smrg    /* Turn a scroll button press into a smooth-scrolling event if
1655f7df2e56Smrg     * necessary. This only needs to cater for the XIScrollFlagPreferred
1656f7df2e56Smrg     * axis (if more than one scrolling axis is present) */
1657f7df2e56Smrg    if (type == ButtonPress) {
1658f7df2e56Smrg        double adj;
1659f7df2e56Smrg        int axis;
1660f7df2e56Smrg        int h_scroll_axis = -1;
1661f7df2e56Smrg        int v_scroll_axis = -1;
1662f7df2e56Smrg
1663f7df2e56Smrg        if (pDev->valuator) {
1664f7df2e56Smrg            h_scroll_axis = pDev->valuator->h_scroll_axis;
1665f7df2e56Smrg            v_scroll_axis = pDev->valuator->v_scroll_axis;
1666f7df2e56Smrg        }
1667f7df2e56Smrg
1668f7df2e56Smrg        /* Up is negative on valuators, down positive */
1669f7df2e56Smrg        switch (buttons) {
1670f7df2e56Smrg        case 4:
1671f7df2e56Smrg            adj = -1.0;
1672f7df2e56Smrg            axis = v_scroll_axis;
1673f7df2e56Smrg            break;
1674f7df2e56Smrg        case 5:
1675f7df2e56Smrg            adj = 1.0;
1676f7df2e56Smrg            axis = v_scroll_axis;
1677f7df2e56Smrg            break;
1678f7df2e56Smrg        case 6:
1679f7df2e56Smrg            adj = -1.0;
1680f7df2e56Smrg            axis = h_scroll_axis;
1681f7df2e56Smrg            break;
1682f7df2e56Smrg        case 7:
1683f7df2e56Smrg            adj = 1.0;
1684f7df2e56Smrg            axis = h_scroll_axis;
1685f7df2e56Smrg            break;
1686f7df2e56Smrg        default:
1687f7df2e56Smrg            adj = 0.0;
1688f7df2e56Smrg            axis = -1;
1689f7df2e56Smrg            break;
1690f7df2e56Smrg        }
1691f7df2e56Smrg
1692f7df2e56Smrg        if (adj != 0.0 && axis != -1) {
1693f7df2e56Smrg            adj *= pDev->valuator->axes[axis].scroll.increment;
1694f7df2e56Smrg            if (!valuator_mask_isset(&mask, axis))
1695f7df2e56Smrg                valuator_mask_set(&mask, axis, 0);
1696f7df2e56Smrg            add_to_scroll_valuator(pDev, &mask, axis, adj);
1697f7df2e56Smrg            type = MotionNotify;
1698f7df2e56Smrg            buttons = 0;
1699f7df2e56Smrg            flags |= POINTER_EMULATED;
1700f7df2e56Smrg        }
1701f7df2e56Smrg    }
1702f7df2e56Smrg
1703f7df2e56Smrg    /* First fill out the original event set, with smooth-scrolling axes. */
1704f7df2e56Smrg    nev_tmp = fill_pointer_events(events, pDev, type, buttons, ms, flags,
1705f7df2e56Smrg                                  &mask);
1706f7df2e56Smrg    events += nev_tmp;
1707f7df2e56Smrg    num_events += nev_tmp;
1708f7df2e56Smrg
1709f7df2e56Smrg    valuator_mask_zero(&scroll);
1710f7df2e56Smrg
1711f7df2e56Smrg    /* Now turn the smooth-scrolling axes back into emulated button presses
1712f7df2e56Smrg     * for legacy clients, based on the integer delta between before and now */
1713f7df2e56Smrg    for (i = 0; i < valuator_mask_size(&mask); i++) {
1714f7df2e56Smrg        if ( !pDev->valuator || (i >= pDev->valuator->numAxes))
1715f7df2e56Smrg            break;
1716f7df2e56Smrg
1717f7df2e56Smrg        if (!valuator_mask_isset(&mask, i))
1718f7df2e56Smrg            continue;
1719f7df2e56Smrg
1720f7df2e56Smrg        valuator_mask_set_double(&scroll, i, pDev->last.valuators[i]);
1721f7df2e56Smrg
1722f7df2e56Smrg        nev_tmp =
1723f7df2e56Smrg            emulate_scroll_button_events(events, pDev, realtype, i, &scroll,
1724f7df2e56Smrg                                         pDev->last.scroll, ms,
1725f7df2e56Smrg                                         GetMaximumEventsNum() - num_events);
1726f7df2e56Smrg        events += nev_tmp;
1727f7df2e56Smrg        num_events += nev_tmp;
1728f7df2e56Smrg    }
1729f7df2e56Smrg
1730f7df2e56Smrg    return num_events;
1731f7df2e56Smrg}
1732f7df2e56Smrg
1733f7df2e56Smrg/**
1734f7df2e56Smrg * Generate internal events representing this proximity event and enqueue
1735f7df2e56Smrg * them on the event queue.
1736f7df2e56Smrg *
1737f7df2e56Smrg * This function is not reentrant. Disable signals before calling.
1738f7df2e56Smrg *
1739f7df2e56Smrg * @param device The device to generate the event for
1740f7df2e56Smrg * @param type Event type, one of ProximityIn or ProximityOut
1741f7df2e56Smrg * @param keycode Key code of the pressed/released key
1742f7df2e56Smrg * @param mask Valuator mask for valuators present for this event.
1743f7df2e56Smrg *
1744f7df2e56Smrg */
1745f7df2e56Smrgvoid
1746f7df2e56SmrgQueueProximityEvents(DeviceIntPtr device, int type, const ValuatorMask *mask)
1747f7df2e56Smrg{
1748f7df2e56Smrg    int nevents;
1749f7df2e56Smrg
1750f7df2e56Smrg    nevents = GetProximityEvents(InputEventList, device, type, mask);
1751f7df2e56Smrg    queueEventList(device, InputEventList, nevents);
1752f7df2e56Smrg}
1753f7df2e56Smrg
1754f7df2e56Smrg/**
1755f7df2e56Smrg * Generate ProximityIn/ProximityOut InternalEvents, accompanied by
1756f7df2e56Smrg * valuators.
1757f7df2e56Smrg *
1758f7df2e56Smrg * The DDX is responsible for allocating the events in the first place via
1759f7df2e56Smrg * InitEventList(), and for freeing it.
1760f7df2e56Smrg *
1761f7df2e56Smrg * @return the number of events written into events.
176205b261ecSmrg */
17634202a189Smrgint
1764f7df2e56SmrgGetProximityEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
1765f7df2e56Smrg                   const ValuatorMask *mask_in)
176605b261ecSmrg{
176765b04b38Smrg    int num_events = 1, i;
17684202a189Smrg    DeviceEvent *event;
176965b04b38Smrg    ValuatorMask mask;
17704202a189Smrg
1771f7df2e56Smrg#if XSERVER_DTRACE
1772f7df2e56Smrg    if (XSERVER_INPUT_EVENT_ENABLED()) {
1773f7df2e56Smrg        XSERVER_INPUT_EVENT(pDev->id, type, 0, 0,
1774f7df2e56Smrg                            mask_in ? mask_in->last_bit + 1 : 0,
1775f7df2e56Smrg                            mask_in ? mask_in->mask : NULL,
1776f7df2e56Smrg                            mask_in ? mask_in->valuators : NULL);
1777f7df2e56Smrg    }
1778f7df2e56Smrg#endif
1779f7df2e56Smrg
17804202a189Smrg    /* refuse events from disabled devices */
17814202a189Smrg    if (!pDev->enabled)
17824202a189Smrg        return 0;
178305b261ecSmrg
178405b261ecSmrg    /* Sanity checks. */
178565b04b38Smrg    if ((type != ProximityIn && type != ProximityOut) || !mask_in)
178605b261ecSmrg        return 0;
1787f7df2e56Smrg    if (!pDev->valuator || !pDev->proximity)
178805b261ecSmrg        return 0;
178905b261ecSmrg
179065b04b38Smrg    valuator_mask_copy(&mask, mask_in);
179165b04b38Smrg
179265b04b38Smrg    /* ignore relative axes for proximity. */
1793f7df2e56Smrg    for (i = 0; i < valuator_mask_size(&mask); i++) {
179465b04b38Smrg        if (valuator_mask_isset(&mask, i) &&
179565b04b38Smrg            valuator_get_mode(pDev, i) == Relative)
179665b04b38Smrg            valuator_mask_unset(&mask, i);
179765b04b38Smrg    }
179865b04b38Smrg
179965b04b38Smrg    /* FIXME: posting proximity events with relative valuators only results
180065b04b38Smrg     * in an empty event, EventToXI() will fail to convert → no event sent
180165b04b38Smrg     * to client. */
180205b261ecSmrg
1803f7df2e56Smrg    events =
1804f7df2e56Smrg        UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events);
18054642e01fSmrg
1806f7df2e56Smrg    event = &events->device_event;
1807f7df2e56Smrg    init_device_event(event, pDev, GetTimeInMillis());
18084202a189Smrg    event->type = (type == ProximityIn) ? ET_ProximityIn : ET_ProximityOut;
180905b261ecSmrg
181065b04b38Smrg    clipValuators(pDev, &mask);
181105b261ecSmrg
181265b04b38Smrg    set_valuators(pDev, event, &mask);
18134202a189Smrg
181405b261ecSmrg    return num_events;
181505b261ecSmrg}
181605b261ecSmrg
1817f7df2e56Smrgint
1818f7df2e56SmrgGetTouchOwnershipEvents(InternalEvent *events, DeviceIntPtr pDev,
1819f7df2e56Smrg                        TouchPointInfoPtr ti, uint8_t reason, XID resource,
1820f7df2e56Smrg                        uint32_t flags)
1821f7df2e56Smrg{
1822f7df2e56Smrg    TouchClassPtr t = pDev->touch;
1823f7df2e56Smrg    TouchOwnershipEvent *event;
1824f7df2e56Smrg    CARD32 ms = GetTimeInMillis();
1825f7df2e56Smrg
1826f7df2e56Smrg    if (!pDev->enabled || !t || !ti)
1827f7df2e56Smrg        return 0;
1828f7df2e56Smrg
1829f7df2e56Smrg    event = &events->touch_ownership_event;
1830f7df2e56Smrg    init_touch_ownership(pDev, event, ms);
1831f7df2e56Smrg
1832f7df2e56Smrg    event->touchid = ti->client_id;
1833f7df2e56Smrg    event->sourceid = ti->sourceid;
1834f7df2e56Smrg    event->resource = resource;
1835f7df2e56Smrg    event->flags = flags;
1836f7df2e56Smrg    event->reason = reason;
1837f7df2e56Smrg
1838f7df2e56Smrg    return 1;
1839f7df2e56Smrg}
1840f7df2e56Smrg
1841f7df2e56Smrg/**
1842f7df2e56Smrg * Generate internal events representing this touch event and enqueue them
1843f7df2e56Smrg * on the event queue.
1844f7df2e56Smrg *
1845f7df2e56Smrg * This function is not reentrant. Disable signals before calling.
1846f7df2e56Smrg *
1847f7df2e56Smrg * @param device The device to generate the event for
1848f7df2e56Smrg * @param type Event type, one of XI_TouchBegin, XI_TouchUpdate, XI_TouchEnd
1849f7df2e56Smrg * @param touchid Touch point ID
1850f7df2e56Smrg * @param flags Event modification flags
1851f7df2e56Smrg * @param mask Valuator mask for valuators present for this event.
1852f7df2e56Smrg */
1853f7df2e56Smrgvoid
1854f7df2e56SmrgQueueTouchEvents(DeviceIntPtr device, int type,
1855f7df2e56Smrg                 uint32_t ddx_touchid, int flags, const ValuatorMask *mask)
1856f7df2e56Smrg{
1857f7df2e56Smrg    int nevents;
1858f7df2e56Smrg
1859f7df2e56Smrg    nevents =
1860f7df2e56Smrg        GetTouchEvents(InputEventList, device, ddx_touchid, type, flags, mask);
1861f7df2e56Smrg    queueEventList(device, InputEventList, nevents);
1862f7df2e56Smrg}
1863f7df2e56Smrg
1864f7df2e56Smrg/**
1865f7df2e56Smrg * Get events for a touch. Generates a TouchBegin event if end is not set and
1866f7df2e56Smrg * the touch id is not active. Generates a TouchUpdate event if end is not set
1867f7df2e56Smrg * and the touch id is active. Generates a TouchEnd event if end is set and the
1868f7df2e56Smrg * touch id is active.
1869f7df2e56Smrg *
1870f7df2e56Smrg * events is not NULL-terminated; the return value is the number of events.
1871f7df2e56Smrg * The DDX is responsible for allocating the event structure in the first
1872f7df2e56Smrg * place via GetMaximumEventsNum(), and for freeing it.
1873f7df2e56Smrg *
1874f7df2e56Smrg * @param[out] events The list of events generated
1875f7df2e56Smrg * @param dev The device to generate the events for
1876f7df2e56Smrg * @param ddx_touchid The touch ID as assigned by the DDX
1877f7df2e56Smrg * @param type XI_TouchBegin, XI_TouchUpdate or XI_TouchEnd
1878f7df2e56Smrg * @param flags Event flags
1879f7df2e56Smrg * @param mask_in Valuator information for this event
1880f7df2e56Smrg */
1881f7df2e56Smrgint
1882f7df2e56SmrgGetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
1883f7df2e56Smrg               uint16_t type, uint32_t flags, const ValuatorMask *mask_in)
1884f7df2e56Smrg{
1885f7df2e56Smrg    ScreenPtr scr = dev->spriteInfo->sprite->hotPhys.pScreen;
1886f7df2e56Smrg    TouchClassPtr t = dev->touch;
1887f7df2e56Smrg    ValuatorClassPtr v = dev->valuator;
1888f7df2e56Smrg    DeviceEvent *event;
1889f7df2e56Smrg    CARD32 ms = GetTimeInMillis();
1890f7df2e56Smrg    ValuatorMask mask;
1891f7df2e56Smrg    double screenx = 0.0, screeny = 0.0;        /* desktop coordinate system */
1892f7df2e56Smrg    double devx = 0.0, devy = 0.0;      /* desktop-wide in device coords */
1893f7df2e56Smrg    int i;
1894f7df2e56Smrg    int num_events = 0;
1895f7df2e56Smrg    RawDeviceEvent *raw;
1896f7df2e56Smrg    DDXTouchPointInfoPtr ti;
1897f7df2e56Smrg    int need_rawevent = TRUE;
1898f7df2e56Smrg    Bool emulate_pointer = FALSE;
1899f7df2e56Smrg    int client_id = 0;
1900f7df2e56Smrg
1901f7df2e56Smrg#if XSERVER_DTRACE
1902f7df2e56Smrg    if (XSERVER_INPUT_EVENT_ENABLED()) {
1903f7df2e56Smrg        XSERVER_INPUT_EVENT(dev->id, type, ddx_touchid, flags,
1904f7df2e56Smrg                            mask_in ? mask_in->last_bit + 1 : 0,
1905f7df2e56Smrg                            mask_in ? mask_in->mask : NULL,
1906f7df2e56Smrg                            mask_in ? mask_in->valuators : NULL);
1907f7df2e56Smrg    }
1908f7df2e56Smrg#endif
1909f7df2e56Smrg
1910f7df2e56Smrg    if (!dev->enabled || !t || !v)
1911f7df2e56Smrg        return 0;
1912f7df2e56Smrg
1913f7df2e56Smrg    /* Find and/or create the DDX touch info */
1914f7df2e56Smrg
1915f7df2e56Smrg    ti = TouchFindByDDXID(dev, ddx_touchid, (type == XI_TouchBegin));
1916f7df2e56Smrg    if (!ti) {
1917f7df2e56Smrg        ErrorFSigSafe("[dix] %s: unable to %s touch point %u\n", dev->name,
1918f7df2e56Smrg                      type == XI_TouchBegin ? "begin" : "find", ddx_touchid);
1919f7df2e56Smrg        return 0;
1920f7df2e56Smrg    }
1921f7df2e56Smrg    client_id = ti->client_id;
1922f7df2e56Smrg
1923f7df2e56Smrg    emulate_pointer = ti->emulate_pointer;
1924f7df2e56Smrg
1925f7df2e56Smrg    if (!IsMaster(dev))
1926f7df2e56Smrg        events =
1927f7df2e56Smrg            UpdateFromMaster(events, dev, DEVCHANGE_POINTER_EVENT, &num_events);
1928f7df2e56Smrg
1929f7df2e56Smrg    valuator_mask_copy(&mask, mask_in);
1930f7df2e56Smrg
1931f7df2e56Smrg    if (need_rawevent) {
1932f7df2e56Smrg        raw = &events->raw_event;
1933f7df2e56Smrg        events++;
1934f7df2e56Smrg        num_events++;
1935f7df2e56Smrg        init_raw(dev, raw, ms, type, client_id);
1936f7df2e56Smrg        set_raw_valuators(raw, &mask, TRUE, raw->valuators.data_raw);
1937f7df2e56Smrg    }
1938f7df2e56Smrg
1939f7df2e56Smrg    event = &events->device_event;
1940f7df2e56Smrg    num_events++;
1941f7df2e56Smrg
1942f7df2e56Smrg    init_device_event(event, dev, ms);
1943f7df2e56Smrg
1944f7df2e56Smrg    switch (type) {
1945f7df2e56Smrg    case XI_TouchBegin:
1946f7df2e56Smrg        event->type = ET_TouchBegin;
1947f7df2e56Smrg        /* If we're starting a touch, we must have x & y co-ordinates. */
1948f7df2e56Smrg        if (!mask_in ||
1949f7df2e56Smrg            !valuator_mask_isset(mask_in, 0) ||
1950f7df2e56Smrg            !valuator_mask_isset(mask_in, 1)) {
1951f7df2e56Smrg            ErrorFSigSafe("%s: Attempted to start touch without x/y "
1952f7df2e56Smrg                          "(driver bug)\n", dev->name);
1953f7df2e56Smrg            return 0;
1954f7df2e56Smrg        }
1955f7df2e56Smrg        break;
1956f7df2e56Smrg    case XI_TouchUpdate:
1957f7df2e56Smrg        event->type = ET_TouchUpdate;
1958f7df2e56Smrg        if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0) {
1959f7df2e56Smrg            ErrorFSigSafe("%s: TouchUpdate with no valuators? Driver bug\n",
1960f7df2e56Smrg                          dev->name);
1961f7df2e56Smrg        }
1962f7df2e56Smrg        break;
1963f7df2e56Smrg    case XI_TouchEnd:
1964f7df2e56Smrg        event->type = ET_TouchEnd;
1965f7df2e56Smrg        /* We can end the DDX touch here, since we don't use the active
1966f7df2e56Smrg         * field below */
1967f7df2e56Smrg        TouchEndDDXTouch(dev, ti);
1968f7df2e56Smrg        break;
1969f7df2e56Smrg    default:
1970f7df2e56Smrg        return 0;
1971f7df2e56Smrg    }
1972f7df2e56Smrg
1973f7df2e56Smrg    /* Get our screen event co-ordinates (root_x/root_y/event_x/event_y):
1974f7df2e56Smrg     * these come from the touchpoint in Absolute mode, or the sprite in
1975f7df2e56Smrg     * Relative. */
1976f7df2e56Smrg    if (t->mode == XIDirectTouch) {
1977f7df2e56Smrg        for (i = 0; i < max(valuator_mask_size(&mask), 2); i++) {
1978f7df2e56Smrg            double val;
1979f7df2e56Smrg
1980f7df2e56Smrg            if (valuator_mask_fetch_double(&mask, i, &val))
1981f7df2e56Smrg                valuator_mask_set_double(ti->valuators, i, val);
1982f7df2e56Smrg            /* If the device doesn't post new X and Y axis values,
1983f7df2e56Smrg             * use the last values posted.
1984f7df2e56Smrg             */
1985f7df2e56Smrg            else if (i < 2 &&
1986f7df2e56Smrg                valuator_mask_fetch_double(ti->valuators, i, &val))
1987f7df2e56Smrg                valuator_mask_set_double(&mask, i, val);
1988f7df2e56Smrg        }
1989f7df2e56Smrg
1990f7df2e56Smrg        transformAbsolute(dev, &mask);
1991f7df2e56Smrg        clipAbsolute(dev, &mask);
1992f7df2e56Smrg    }
1993f7df2e56Smrg    else {
1994f7df2e56Smrg        screenx = dev->spriteInfo->sprite->hotPhys.x;
1995f7df2e56Smrg        screeny = dev->spriteInfo->sprite->hotPhys.y;
1996f7df2e56Smrg    }
1997f7df2e56Smrg    if (need_rawevent)
1998f7df2e56Smrg        set_raw_valuators(raw, &mask, FALSE, raw->valuators.data);
1999f7df2e56Smrg
2000f7df2e56Smrg    /* Indirect device touch coordinates are not used for cursor positioning.
2001f7df2e56Smrg     * They are merely informational, and are provided in device coordinates.
2002f7df2e56Smrg     * The device sprite is used for positioning instead, and it is already
2003f7df2e56Smrg     * scaled. */
2004f7df2e56Smrg    if (t->mode == XIDirectTouch)
2005f7df2e56Smrg        scr = scale_to_desktop(dev, &mask, &devx, &devy, &screenx, &screeny);
2006f7df2e56Smrg    if (emulate_pointer)
2007f7df2e56Smrg        scr = positionSprite(dev, Absolute, &mask,
2008f7df2e56Smrg                             &devx, &devy, &screenx, &screeny, NULL, NULL);
2009f7df2e56Smrg
2010f7df2e56Smrg    /* see fill_pointer_events for coordinate systems */
2011f7df2e56Smrg    if (emulate_pointer)
2012f7df2e56Smrg        updateHistory(dev, &mask, ms);
2013f7df2e56Smrg
2014f7df2e56Smrg    clipValuators(dev, &mask);
2015f7df2e56Smrg
2016f7df2e56Smrg    if (emulate_pointer)
2017f7df2e56Smrg        storeLastValuators(dev, &mask, 0, 1, devx, devy);
2018f7df2e56Smrg
2019f7df2e56Smrg    /* Update the MD's co-ordinates, which are always in desktop space. */
2020f7df2e56Smrg    if (emulate_pointer && !IsMaster(dev) && !IsFloating(dev)) {
2021f7df2e56Smrg	    DeviceIntPtr master = GetMaster(dev, MASTER_POINTER);
2022f7df2e56Smrg
2023f7df2e56Smrg	    master->last.valuators[0] = screenx;
2024f7df2e56Smrg	    master->last.valuators[1] = screeny;
2025f7df2e56Smrg    }
2026f7df2e56Smrg
2027f7df2e56Smrg    event->root = scr->root->drawable.id;
2028f7df2e56Smrg
2029f7df2e56Smrg    event_set_root_coordinates(event, screenx - scr->x, screeny - scr->y);
2030f7df2e56Smrg    event->touchid = client_id;
2031f7df2e56Smrg    event->flags = flags;
2032f7df2e56Smrg
2033f7df2e56Smrg    if (emulate_pointer) {
2034f7df2e56Smrg        event->flags |= TOUCH_POINTER_EMULATED;
2035f7df2e56Smrg        event->detail.button = 1;
2036f7df2e56Smrg    }
2037f7df2e56Smrg
2038f7df2e56Smrg    set_valuators(dev, event, &mask);
2039f7df2e56Smrg    for (i = 0; i < v->numAxes; i++) {
2040f7df2e56Smrg        if (valuator_mask_isset(&mask, i))
2041f7df2e56Smrg            v->axisVal[i] = valuator_mask_get(&mask, i);
2042f7df2e56Smrg    }
2043f7df2e56Smrg
2044f7df2e56Smrg    return num_events;
2045f7df2e56Smrg}
2046f7df2e56Smrg
2047f7df2e56Smrgvoid
2048f7df2e56SmrgGetDixTouchEnd(InternalEvent *ievent, DeviceIntPtr dev, TouchPointInfoPtr ti,
2049f7df2e56Smrg               uint32_t flags)
2050f7df2e56Smrg{
2051f7df2e56Smrg    ScreenPtr scr = dev->spriteInfo->sprite->hotPhys.pScreen;
2052f7df2e56Smrg    DeviceEvent *event = &ievent->device_event;
2053f7df2e56Smrg    CARD32 ms = GetTimeInMillis();
2054f7df2e56Smrg
2055f7df2e56Smrg    BUG_WARN(!dev->enabled);
2056f7df2e56Smrg
2057f7df2e56Smrg    init_device_event(event, dev, ms);
2058f7df2e56Smrg
2059f7df2e56Smrg    event->sourceid = ti->sourceid;
2060f7df2e56Smrg    event->type = ET_TouchEnd;
2061f7df2e56Smrg
2062f7df2e56Smrg    event->root = scr->root->drawable.id;
2063f7df2e56Smrg
2064f7df2e56Smrg    /* Get screen event coordinates from the sprite.  Is this really the best
2065f7df2e56Smrg     * we can do? */
2066f7df2e56Smrg    event_set_root_coordinates(event,
2067f7df2e56Smrg                               dev->last.valuators[0] - scr->x,
2068f7df2e56Smrg                               dev->last.valuators[1] - scr->y);
2069f7df2e56Smrg    event->touchid = ti->client_id;
2070f7df2e56Smrg    event->flags = flags;
2071f7df2e56Smrg
2072f7df2e56Smrg    if (flags & TOUCH_POINTER_EMULATED) {
2073f7df2e56Smrg        event->flags |= TOUCH_POINTER_EMULATED;
2074f7df2e56Smrg        event->detail.button = 1;
2075f7df2e56Smrg    }
2076f7df2e56Smrg}
2077f7df2e56Smrg
207805b261ecSmrg/**
207905b261ecSmrg * Synthesize a single motion event for the core pointer.
208005b261ecSmrg *
208105b261ecSmrg * Used in cursor functions, e.g. when cursor confinement changes, and we need
208205b261ecSmrg * to shift the pointer to get it inside the new bounds.
208305b261ecSmrg */
208405b261ecSmrgvoid
20854642e01fSmrgPostSyntheticMotion(DeviceIntPtr pDev,
2086f7df2e56Smrg                    int x, int y, int screen, unsigned long time)
208705b261ecSmrg{
20884202a189Smrg    DeviceEvent ev;
208905b261ecSmrg
209005b261ecSmrg#ifdef PANORAMIX
209105b261ecSmrg    /* Translate back to the sprite screen since processInputProc
209205b261ecSmrg       will translate from sprite screen to screen 0 upon reentry
209305b261ecSmrg       to the DIX layer. */
209405b261ecSmrg    if (!noPanoramiXExtension) {
20954202a189Smrg        x += screenInfo.screens[0]->x - screenInfo.screens[screen]->x;
20964202a189Smrg        y += screenInfo.screens[0]->y - screenInfo.screens[screen]->y;
209705b261ecSmrg    }
209805b261ecSmrg#endif
209905b261ecSmrg
21004202a189Smrg    memset(&ev, 0, sizeof(DeviceEvent));
2101f7df2e56Smrg    init_device_event(&ev, pDev, time);
21024202a189Smrg    ev.root_x = x;
21034202a189Smrg    ev.root_y = y;
21044202a189Smrg    ev.type = ET_Motion;
21054202a189Smrg    ev.time = time;
210605b261ecSmrg
21074202a189Smrg    /* FIXME: MD/SD considerations? */
2108f7df2e56Smrg    (*pDev->public.processInputProc) ((InternalEvent *) &ev, pDev);
210905b261ecSmrg}
2110