1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright © 2006 Nokia Corporation
3*4882a593Smuzhiyun * Copyright © 2006-2007 Daniel Stone
4*4882a593Smuzhiyun * Copyright © 2008 Red Hat, Inc.
5*4882a593Smuzhiyun * Copyright © 2011 The Chromium Authors
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Permission is hereby granted, free of charge, to any person obtaining a
8*4882a593Smuzhiyun * copy of this software and associated documentation files (the "Software"),
9*4882a593Smuzhiyun * to deal in the Software without restriction, including without limitation
10*4882a593Smuzhiyun * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11*4882a593Smuzhiyun * and/or sell copies of the Software, and to permit persons to whom the
12*4882a593Smuzhiyun * Software is furnished to do so, subject to the following conditions:
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * The above copyright notice and this permission notice (including the next
15*4882a593Smuzhiyun * paragraph) shall be included in all copies or substantial portions of the
16*4882a593Smuzhiyun * Software.
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19*4882a593Smuzhiyun * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20*4882a593Smuzhiyun * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21*4882a593Smuzhiyun * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22*4882a593Smuzhiyun * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23*4882a593Smuzhiyun * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24*4882a593Smuzhiyun * DEALINGS IN THE SOFTWARE.
25*4882a593Smuzhiyun *
26*4882a593Smuzhiyun * Authors: Daniel Stone <daniel@fooishbar.org>
27*4882a593Smuzhiyun * Peter Hutterer <peter.hutterer@who-t.net>
28*4882a593Smuzhiyun */
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
31*4882a593Smuzhiyun #include <dix-config.h>
32*4882a593Smuzhiyun #endif
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #include <X11/X.h>
35*4882a593Smuzhiyun #include <X11/keysym.h>
36*4882a593Smuzhiyun #include <X11/Xproto.h>
37*4882a593Smuzhiyun #include <math.h>
38*4882a593Smuzhiyun #include <limits.h>
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun #include "misc.h"
41*4882a593Smuzhiyun #include "resource.h"
42*4882a593Smuzhiyun #include "inputstr.h"
43*4882a593Smuzhiyun #include "scrnintstr.h"
44*4882a593Smuzhiyun #include "cursorstr.h"
45*4882a593Smuzhiyun #include "dixstruct.h"
46*4882a593Smuzhiyun #include "globals.h"
47*4882a593Smuzhiyun #include "dixevents.h"
48*4882a593Smuzhiyun #include "mipointer.h"
49*4882a593Smuzhiyun #include "eventstr.h"
50*4882a593Smuzhiyun #include "eventconvert.h"
51*4882a593Smuzhiyun #include "inpututils.h"
52*4882a593Smuzhiyun #include "mi.h"
53*4882a593Smuzhiyun #include "windowstr.h"
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun #include <X11/extensions/XKBproto.h>
56*4882a593Smuzhiyun #include "xkbsrv.h"
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun #ifdef PANORAMIX
59*4882a593Smuzhiyun #include "panoramiX.h"
60*4882a593Smuzhiyun #include "panoramiXsrv.h"
61*4882a593Smuzhiyun #endif
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun #include <X11/extensions/XI.h>
64*4882a593Smuzhiyun #include <X11/extensions/XI2.h>
65*4882a593Smuzhiyun #include <X11/extensions/XIproto.h>
66*4882a593Smuzhiyun #include <pixman.h>
67*4882a593Smuzhiyun #include "exglobals.h"
68*4882a593Smuzhiyun #include "exevents.h"
69*4882a593Smuzhiyun #include "extnsionst.h"
70*4882a593Smuzhiyun #include "listdev.h" /* for sizing up DeviceClassesChangedEvent */
71*4882a593Smuzhiyun #include "probes.h"
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /* Number of motion history events to store. */
74*4882a593Smuzhiyun #define MOTION_HISTORY_SIZE 256
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun /**
77*4882a593Smuzhiyun * InputEventList is the storage for input events generated by
78*4882a593Smuzhiyun * QueuePointerEvents, QueueKeyboardEvents, and QueueProximityEvents.
79*4882a593Smuzhiyun * This list is allocated on startup by the DIX.
80*4882a593Smuzhiyun */
81*4882a593Smuzhiyun InternalEvent *InputEventList = NULL;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /**
84*4882a593Smuzhiyun * Pick some arbitrary size for Xi motion history.
85*4882a593Smuzhiyun */
86*4882a593Smuzhiyun int
GetMotionHistorySize(void)87*4882a593Smuzhiyun GetMotionHistorySize(void)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun return MOTION_HISTORY_SIZE;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun void
set_button_down(DeviceIntPtr pDev,int button,int type)93*4882a593Smuzhiyun set_button_down(DeviceIntPtr pDev, int button, int type)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun if (type == BUTTON_PROCESSED)
96*4882a593Smuzhiyun SetBit(pDev->button->down, button);
97*4882a593Smuzhiyun else
98*4882a593Smuzhiyun SetBit(pDev->button->postdown, button);
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun void
set_button_up(DeviceIntPtr pDev,int button,int type)102*4882a593Smuzhiyun set_button_up(DeviceIntPtr pDev, int button, int type)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun if (type == BUTTON_PROCESSED)
105*4882a593Smuzhiyun ClearBit(pDev->button->down, button);
106*4882a593Smuzhiyun else
107*4882a593Smuzhiyun ClearBit(pDev->button->postdown, button);
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun Bool
button_is_down(DeviceIntPtr pDev,int button,int type)111*4882a593Smuzhiyun button_is_down(DeviceIntPtr pDev, int button, int type)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun Bool ret = FALSE;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun if (type & BUTTON_PROCESSED)
116*4882a593Smuzhiyun ret = ret || BitIsOn(pDev->button->down, button);
117*4882a593Smuzhiyun if (type & BUTTON_POSTED)
118*4882a593Smuzhiyun ret = ret || BitIsOn(pDev->button->postdown, button);
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun return ret;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun void
set_key_down(DeviceIntPtr pDev,int key_code,int type)124*4882a593Smuzhiyun set_key_down(DeviceIntPtr pDev, int key_code, int type)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun if (type == KEY_PROCESSED)
127*4882a593Smuzhiyun SetBit(pDev->key->down, key_code);
128*4882a593Smuzhiyun else
129*4882a593Smuzhiyun SetBit(pDev->key->postdown, key_code);
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun void
set_key_up(DeviceIntPtr pDev,int key_code,int type)133*4882a593Smuzhiyun set_key_up(DeviceIntPtr pDev, int key_code, int type)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun if (type == KEY_PROCESSED)
136*4882a593Smuzhiyun ClearBit(pDev->key->down, key_code);
137*4882a593Smuzhiyun else
138*4882a593Smuzhiyun ClearBit(pDev->key->postdown, key_code);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun Bool
key_is_down(DeviceIntPtr pDev,int key_code,int type)142*4882a593Smuzhiyun key_is_down(DeviceIntPtr pDev, int key_code, int type)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun Bool ret = FALSE;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun if (type & KEY_PROCESSED)
147*4882a593Smuzhiyun ret = ret || BitIsOn(pDev->key->down, key_code);
148*4882a593Smuzhiyun if (type & KEY_POSTED)
149*4882a593Smuzhiyun ret = ret || BitIsOn(pDev->key->postdown, key_code);
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun return ret;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun static Bool
key_autorepeats(DeviceIntPtr pDev,int key_code)155*4882a593Smuzhiyun key_autorepeats(DeviceIntPtr pDev, int key_code)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun return ! !(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3] &
158*4882a593Smuzhiyun (1 << (key_code & 7)));
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun static void
init_touch_ownership(DeviceIntPtr dev,TouchOwnershipEvent * event,Time ms)162*4882a593Smuzhiyun init_touch_ownership(DeviceIntPtr dev, TouchOwnershipEvent *event, Time ms)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun memset(event, 0, sizeof(TouchOwnershipEvent));
165*4882a593Smuzhiyun event->header = ET_Internal;
166*4882a593Smuzhiyun event->type = ET_TouchOwnership;
167*4882a593Smuzhiyun event->length = sizeof(TouchOwnershipEvent);
168*4882a593Smuzhiyun event->time = ms;
169*4882a593Smuzhiyun event->deviceid = dev->id;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun static void
init_raw(DeviceIntPtr dev,RawDeviceEvent * event,Time ms,int type,int detail)173*4882a593Smuzhiyun init_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun memset(event, 0, sizeof(RawDeviceEvent));
176*4882a593Smuzhiyun event->header = ET_Internal;
177*4882a593Smuzhiyun event->length = sizeof(RawDeviceEvent);
178*4882a593Smuzhiyun switch (type) {
179*4882a593Smuzhiyun case MotionNotify:
180*4882a593Smuzhiyun event->type = ET_RawMotion;
181*4882a593Smuzhiyun break;
182*4882a593Smuzhiyun case ButtonPress:
183*4882a593Smuzhiyun event->type = ET_RawButtonPress;
184*4882a593Smuzhiyun break;
185*4882a593Smuzhiyun case ButtonRelease:
186*4882a593Smuzhiyun event->type = ET_RawButtonRelease;
187*4882a593Smuzhiyun break;
188*4882a593Smuzhiyun case KeyPress:
189*4882a593Smuzhiyun event->type = ET_RawKeyPress;
190*4882a593Smuzhiyun break;
191*4882a593Smuzhiyun case KeyRelease:
192*4882a593Smuzhiyun event->type = ET_RawKeyRelease;
193*4882a593Smuzhiyun break;
194*4882a593Smuzhiyun case XI_TouchBegin:
195*4882a593Smuzhiyun event->type = ET_RawTouchBegin;
196*4882a593Smuzhiyun break;
197*4882a593Smuzhiyun case XI_TouchUpdate:
198*4882a593Smuzhiyun event->type = ET_RawTouchUpdate;
199*4882a593Smuzhiyun break;
200*4882a593Smuzhiyun case XI_TouchEnd:
201*4882a593Smuzhiyun event->type = ET_RawTouchEnd;
202*4882a593Smuzhiyun break;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun event->time = ms;
205*4882a593Smuzhiyun event->deviceid = dev->id;
206*4882a593Smuzhiyun event->sourceid = dev->id;
207*4882a593Smuzhiyun event->detail.button = detail;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun static void
set_raw_valuators(RawDeviceEvent * event,ValuatorMask * mask,BOOL use_unaccel,double * data)211*4882a593Smuzhiyun set_raw_valuators(RawDeviceEvent *event, ValuatorMask *mask,
212*4882a593Smuzhiyun BOOL use_unaccel, double *data)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun int i;
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun use_unaccel = use_unaccel && valuator_mask_has_unaccelerated(mask);
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun for (i = 0; i < valuator_mask_size(mask); i++) {
219*4882a593Smuzhiyun if (valuator_mask_isset(mask, i)) {
220*4882a593Smuzhiyun double v;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun SetBit(event->valuators.mask, i);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun if (use_unaccel)
225*4882a593Smuzhiyun v = valuator_mask_get_unaccelerated(mask, i);
226*4882a593Smuzhiyun else
227*4882a593Smuzhiyun v = valuator_mask_get_double(mask, i);
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun data[i] = v;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun static void
set_valuators(DeviceIntPtr dev,DeviceEvent * event,ValuatorMask * mask)235*4882a593Smuzhiyun set_valuators(DeviceIntPtr dev, DeviceEvent *event, ValuatorMask *mask)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun int i;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun /* Set the data to the previous value for unset absolute axes. The values
240*4882a593Smuzhiyun * may be used when sent as part of an XI 1.x valuator event. */
241*4882a593Smuzhiyun for (i = 0; i < valuator_mask_size(mask); i++) {
242*4882a593Smuzhiyun if (valuator_mask_isset(mask, i)) {
243*4882a593Smuzhiyun SetBit(event->valuators.mask, i);
244*4882a593Smuzhiyun if (valuator_get_mode(dev, i) == Absolute)
245*4882a593Smuzhiyun SetBit(event->valuators.mode, i);
246*4882a593Smuzhiyun event->valuators.data[i] = valuator_mask_get_double(mask, i);
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun else
249*4882a593Smuzhiyun event->valuators.data[i] = dev->valuator->axisVal[i];
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun void
CreateClassesChangedEvent(InternalEvent * event,DeviceIntPtr master,DeviceIntPtr slave,int flags)254*4882a593Smuzhiyun CreateClassesChangedEvent(InternalEvent *event,
255*4882a593Smuzhiyun DeviceIntPtr master, DeviceIntPtr slave, int flags)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun int i;
258*4882a593Smuzhiyun DeviceChangedEvent *dce;
259*4882a593Smuzhiyun CARD32 ms = GetTimeInMillis();
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun dce = &event->changed_event;
262*4882a593Smuzhiyun memset(dce, 0, sizeof(DeviceChangedEvent));
263*4882a593Smuzhiyun dce->deviceid = slave->id;
264*4882a593Smuzhiyun dce->masterid = master ? master->id : 0;
265*4882a593Smuzhiyun dce->header = ET_Internal;
266*4882a593Smuzhiyun dce->length = sizeof(DeviceChangedEvent);
267*4882a593Smuzhiyun dce->type = ET_DeviceChanged;
268*4882a593Smuzhiyun dce->time = ms;
269*4882a593Smuzhiyun dce->flags = flags;
270*4882a593Smuzhiyun dce->sourceid = slave->id;
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun if (slave->button) {
273*4882a593Smuzhiyun dce->buttons.num_buttons = slave->button->numButtons;
274*4882a593Smuzhiyun for (i = 0; i < dce->buttons.num_buttons; i++)
275*4882a593Smuzhiyun dce->buttons.names[i] = slave->button->labels[i];
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun if (slave->valuator) {
278*4882a593Smuzhiyun dce->num_valuators = slave->valuator->numAxes;
279*4882a593Smuzhiyun for (i = 0; i < dce->num_valuators; i++) {
280*4882a593Smuzhiyun dce->valuators[i].min = slave->valuator->axes[i].min_value;
281*4882a593Smuzhiyun dce->valuators[i].max = slave->valuator->axes[i].max_value;
282*4882a593Smuzhiyun dce->valuators[i].resolution = slave->valuator->axes[i].resolution;
283*4882a593Smuzhiyun dce->valuators[i].mode = slave->valuator->axes[i].mode;
284*4882a593Smuzhiyun dce->valuators[i].name = slave->valuator->axes[i].label;
285*4882a593Smuzhiyun dce->valuators[i].scroll = slave->valuator->axes[i].scroll;
286*4882a593Smuzhiyun dce->valuators[i].value = slave->valuator->axisVal[i];
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun if (slave->key) {
290*4882a593Smuzhiyun dce->keys.min_keycode = slave->key->xkbInfo->desc->min_key_code;
291*4882a593Smuzhiyun dce->keys.max_keycode = slave->key->xkbInfo->desc->max_key_code;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun /**
296*4882a593Smuzhiyun * Rescale the coord between the two axis ranges.
297*4882a593Smuzhiyun */
298*4882a593Smuzhiyun static double
rescaleValuatorAxis(double coord,AxisInfoPtr from,AxisInfoPtr to,double defmin,double defmax)299*4882a593Smuzhiyun rescaleValuatorAxis(double coord, AxisInfoPtr from, AxisInfoPtr to,
300*4882a593Smuzhiyun double defmin, double defmax)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun double fmin = defmin, fmax = defmax;
303*4882a593Smuzhiyun double tmin = defmin, tmax = defmax;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun if (from && from->min_value < from->max_value) {
306*4882a593Smuzhiyun fmin = from->min_value;
307*4882a593Smuzhiyun fmax = from->max_value + 1;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun if (to && to->min_value < to->max_value) {
310*4882a593Smuzhiyun tmin = to->min_value;
311*4882a593Smuzhiyun tmax = to->max_value + 1;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun if (fmin == tmin && fmax == tmax)
315*4882a593Smuzhiyun return coord;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun if (fmax == fmin) /* avoid division by 0 */
318*4882a593Smuzhiyun return 0.0;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun return (coord - fmin) * (tmax - tmin) / (fmax - fmin) + tmin;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun /**
324*4882a593Smuzhiyun * Update all coordinates when changing to a different SD
325*4882a593Smuzhiyun * to ensure that relative reporting will work as expected
326*4882a593Smuzhiyun * without loss of precision.
327*4882a593Smuzhiyun *
328*4882a593Smuzhiyun * pDev->last.valuators will be in absolute device coordinates after this
329*4882a593Smuzhiyun * function.
330*4882a593Smuzhiyun */
331*4882a593Smuzhiyun static void
updateSlaveDeviceCoords(DeviceIntPtr master,DeviceIntPtr pDev)332*4882a593Smuzhiyun updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun /* master->last.valuators[0]/[1] is in desktop-wide coords and the actual
335*4882a593Smuzhiyun * position of the pointer */
336*4882a593Smuzhiyun pDev->last.valuators[0] = master->last.valuators[0];
337*4882a593Smuzhiyun pDev->last.valuators[1] = master->last.valuators[1];
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun if (!pDev->valuator)
340*4882a593Smuzhiyun return;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun /* scale back to device coordinates */
343*4882a593Smuzhiyun if (pDev->valuator->numAxes > 0) {
344*4882a593Smuzhiyun pDev->last.valuators[0] = rescaleValuatorAxis(pDev->last.valuators[0],
345*4882a593Smuzhiyun NULL,
346*4882a593Smuzhiyun pDev->valuator->axes + 0,
347*4882a593Smuzhiyun screenInfo.x,
348*4882a593Smuzhiyun screenInfo.width);
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun if (pDev->valuator->numAxes > 1) {
351*4882a593Smuzhiyun pDev->last.valuators[1] = rescaleValuatorAxis(pDev->last.valuators[1],
352*4882a593Smuzhiyun NULL,
353*4882a593Smuzhiyun pDev->valuator->axes + 1,
354*4882a593Smuzhiyun screenInfo.y,
355*4882a593Smuzhiyun screenInfo.height);
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun /* other axes are left as-is */
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun /**
362*4882a593Smuzhiyun * Allocate the motion history buffer.
363*4882a593Smuzhiyun */
364*4882a593Smuzhiyun void
AllocateMotionHistory(DeviceIntPtr pDev)365*4882a593Smuzhiyun AllocateMotionHistory(DeviceIntPtr pDev)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun int size;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun free(pDev->valuator->motion);
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if (pDev->valuator->numMotionEvents < 1)
372*4882a593Smuzhiyun return;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun /* An MD must have a motion history size large enough to keep all
375*4882a593Smuzhiyun * potential valuators, plus the respective range of the valuators.
376*4882a593Smuzhiyun * 3 * INT32 for (min_val, max_val, curr_val))
377*4882a593Smuzhiyun */
378*4882a593Smuzhiyun if (IsMaster(pDev))
379*4882a593Smuzhiyun size = sizeof(INT32) * 3 * MAX_VALUATORS;
380*4882a593Smuzhiyun else {
381*4882a593Smuzhiyun ValuatorClassPtr v = pDev->valuator;
382*4882a593Smuzhiyun int numAxes;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun /* XI1 doesn't understand mixed mode devices */
385*4882a593Smuzhiyun for (numAxes = 0; numAxes < v->numAxes; numAxes++)
386*4882a593Smuzhiyun if (valuator_get_mode(pDev, numAxes) != valuator_get_mode(pDev, 0))
387*4882a593Smuzhiyun break;
388*4882a593Smuzhiyun size = sizeof(INT32) * numAxes;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun size += sizeof(Time);
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun pDev->valuator->motion = calloc(pDev->valuator->numMotionEvents, size);
394*4882a593Smuzhiyun pDev->valuator->first_motion = 0;
395*4882a593Smuzhiyun pDev->valuator->last_motion = 0;
396*4882a593Smuzhiyun if (!pDev->valuator->motion)
397*4882a593Smuzhiyun ErrorF("[dix] %s: Failed to alloc motion history (%d bytes).\n",
398*4882a593Smuzhiyun pDev->name, size * pDev->valuator->numMotionEvents);
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun /**
402*4882a593Smuzhiyun * Dump the motion history between start and stop into the supplied buffer.
403*4882a593Smuzhiyun * Only records the event for a given screen in theory, but in practice, we
404*4882a593Smuzhiyun * sort of ignore this.
405*4882a593Smuzhiyun *
406*4882a593Smuzhiyun * If core is set, we only generate x/y, in INT16, scaled to screen coords.
407*4882a593Smuzhiyun */
408*4882a593Smuzhiyun int
GetMotionHistory(DeviceIntPtr pDev,xTimecoord ** buff,unsigned long start,unsigned long stop,ScreenPtr pScreen,BOOL core)409*4882a593Smuzhiyun GetMotionHistory(DeviceIntPtr pDev, xTimecoord ** buff, unsigned long start,
410*4882a593Smuzhiyun unsigned long stop, ScreenPtr pScreen, BOOL core)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun char *ibuff = NULL, *obuff;
413*4882a593Smuzhiyun int i = 0, ret = 0;
414*4882a593Smuzhiyun int j, coord;
415*4882a593Smuzhiyun Time current;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun /* The size of a single motion event. */
418*4882a593Smuzhiyun int size;
419*4882a593Smuzhiyun AxisInfo from, *to; /* for scaling */
420*4882a593Smuzhiyun INT32 *ocbuf, *icbuf; /* pointer to coordinates for copying */
421*4882a593Smuzhiyun INT16 *corebuf;
422*4882a593Smuzhiyun AxisInfo core_axis = { 0 };
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun if (!pDev->valuator || !pDev->valuator->numMotionEvents)
425*4882a593Smuzhiyun return 0;
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun if (core && !pScreen)
428*4882a593Smuzhiyun return 0;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun if (IsMaster(pDev))
431*4882a593Smuzhiyun size = (sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(Time);
432*4882a593Smuzhiyun else
433*4882a593Smuzhiyun size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun *buff = malloc(size * pDev->valuator->numMotionEvents);
436*4882a593Smuzhiyun if (!(*buff))
437*4882a593Smuzhiyun return 0;
438*4882a593Smuzhiyun obuff = (char *) *buff;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun for (i = pDev->valuator->first_motion;
441*4882a593Smuzhiyun i != pDev->valuator->last_motion;
442*4882a593Smuzhiyun i = (i + 1) % pDev->valuator->numMotionEvents) {
443*4882a593Smuzhiyun /* We index the input buffer by which element we're accessing, which
444*4882a593Smuzhiyun * is not monotonic, and the output buffer by how many events we've
445*4882a593Smuzhiyun * written so far. */
446*4882a593Smuzhiyun ibuff = (char *) pDev->valuator->motion + (i * size);
447*4882a593Smuzhiyun memcpy(¤t, ibuff, sizeof(Time));
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun if (current > stop) {
450*4882a593Smuzhiyun return ret;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun else if (current >= start) {
453*4882a593Smuzhiyun if (core) {
454*4882a593Smuzhiyun memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun icbuf = (INT32 *) (ibuff + sizeof(Time));
457*4882a593Smuzhiyun corebuf = (INT16 *) (obuff + sizeof(Time));
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun /* fetch x coordinate + range */
460*4882a593Smuzhiyun memcpy(&from.min_value, icbuf++, sizeof(INT32));
461*4882a593Smuzhiyun memcpy(&from.max_value, icbuf++, sizeof(INT32));
462*4882a593Smuzhiyun memcpy(&coord, icbuf++, sizeof(INT32));
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun /* scale to screen coords */
465*4882a593Smuzhiyun to = &core_axis;
466*4882a593Smuzhiyun to->max_value = pScreen->width;
467*4882a593Smuzhiyun coord =
468*4882a593Smuzhiyun rescaleValuatorAxis(coord, &from, to, 0, pScreen->width);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun memcpy(corebuf, &coord, sizeof(INT16));
471*4882a593Smuzhiyun corebuf++;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun /* fetch y coordinate + range */
474*4882a593Smuzhiyun memcpy(&from.min_value, icbuf++, sizeof(INT32));
475*4882a593Smuzhiyun memcpy(&from.max_value, icbuf++, sizeof(INT32));
476*4882a593Smuzhiyun memcpy(&coord, icbuf++, sizeof(INT32));
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun to->max_value = pScreen->height;
479*4882a593Smuzhiyun coord =
480*4882a593Smuzhiyun rescaleValuatorAxis(coord, &from, to, 0, pScreen->height);
481*4882a593Smuzhiyun memcpy(corebuf, &coord, sizeof(INT16));
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun else if (IsMaster(pDev)) {
485*4882a593Smuzhiyun memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun ocbuf = (INT32 *) (obuff + sizeof(Time));
488*4882a593Smuzhiyun icbuf = (INT32 *) (ibuff + sizeof(Time));
489*4882a593Smuzhiyun for (j = 0; j < MAX_VALUATORS; j++) {
490*4882a593Smuzhiyun if (j >= pDev->valuator->numAxes)
491*4882a593Smuzhiyun break;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun /* fetch min/max/coordinate */
494*4882a593Smuzhiyun memcpy(&from.min_value, icbuf++, sizeof(INT32));
495*4882a593Smuzhiyun memcpy(&from.max_value, icbuf++, sizeof(INT32));
496*4882a593Smuzhiyun memcpy(&coord, icbuf++, sizeof(INT32));
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun to = (j <
499*4882a593Smuzhiyun pDev->valuator->numAxes) ? &pDev->valuator->
500*4882a593Smuzhiyun axes[j] : NULL;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /* x/y scaled to screen if no range is present */
503*4882a593Smuzhiyun if (j == 0 && (from.max_value < from.min_value))
504*4882a593Smuzhiyun from.max_value = pScreen->width;
505*4882a593Smuzhiyun else if (j == 1 && (from.max_value < from.min_value))
506*4882a593Smuzhiyun from.max_value = pScreen->height;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun /* scale from stored range into current range */
509*4882a593Smuzhiyun coord = rescaleValuatorAxis(coord, &from, to, 0, 0);
510*4882a593Smuzhiyun memcpy(ocbuf, &coord, sizeof(INT32));
511*4882a593Smuzhiyun ocbuf++;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun else
515*4882a593Smuzhiyun memcpy(obuff, ibuff, size);
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun /* don't advance by size here. size may be different to the
518*4882a593Smuzhiyun * actually written size if the MD has less valuators than MAX */
519*4882a593Smuzhiyun if (core)
520*4882a593Smuzhiyun obuff += sizeof(INT32) + sizeof(Time);
521*4882a593Smuzhiyun else
522*4882a593Smuzhiyun obuff +=
523*4882a593Smuzhiyun (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
524*4882a593Smuzhiyun ret++;
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun return ret;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun /**
532*4882a593Smuzhiyun * Update the motion history for a specific device, with the list of
533*4882a593Smuzhiyun * valuators.
534*4882a593Smuzhiyun *
535*4882a593Smuzhiyun * Layout of the history buffer:
536*4882a593Smuzhiyun * for SDs: [time] [val0] [val1] ... [valn]
537*4882a593Smuzhiyun * for MDs: [time] [min_val0] [max_val0] [val0] [min_val1] ... [valn]
538*4882a593Smuzhiyun *
539*4882a593Smuzhiyun * For events that have some valuators unset:
540*4882a593Smuzhiyun * min_val == max_val == val == 0.
541*4882a593Smuzhiyun */
542*4882a593Smuzhiyun static void
updateMotionHistory(DeviceIntPtr pDev,CARD32 ms,ValuatorMask * mask,double * valuators)543*4882a593Smuzhiyun updateMotionHistory(DeviceIntPtr pDev, CARD32 ms, ValuatorMask *mask,
544*4882a593Smuzhiyun double *valuators)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun char *buff = (char *) pDev->valuator->motion;
547*4882a593Smuzhiyun ValuatorClassPtr v;
548*4882a593Smuzhiyun int i;
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun if (!pDev->valuator->numMotionEvents)
551*4882a593Smuzhiyun return;
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun v = pDev->valuator;
554*4882a593Smuzhiyun if (IsMaster(pDev)) {
555*4882a593Smuzhiyun buff += ((sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(CARD32)) *
556*4882a593Smuzhiyun v->last_motion;
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun memcpy(buff, &ms, sizeof(Time));
559*4882a593Smuzhiyun buff += sizeof(Time);
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun memset(buff, 0, sizeof(INT32) * 3 * MAX_VALUATORS);
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun for (i = 0; i < v->numAxes; i++) {
564*4882a593Smuzhiyun int val;
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun /* XI1 doesn't support mixed mode devices */
567*4882a593Smuzhiyun if (valuator_get_mode(pDev, i) != valuator_get_mode(pDev, 0))
568*4882a593Smuzhiyun break;
569*4882a593Smuzhiyun if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i)) {
570*4882a593Smuzhiyun buff += 3 * sizeof(INT32);
571*4882a593Smuzhiyun continue;
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun memcpy(buff, &v->axes[i].min_value, sizeof(INT32));
574*4882a593Smuzhiyun buff += sizeof(INT32);
575*4882a593Smuzhiyun memcpy(buff, &v->axes[i].max_value, sizeof(INT32));
576*4882a593Smuzhiyun buff += sizeof(INT32);
577*4882a593Smuzhiyun val = valuators[i];
578*4882a593Smuzhiyun memcpy(buff, &val, sizeof(INT32));
579*4882a593Smuzhiyun buff += sizeof(INT32);
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun else {
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) *
585*4882a593Smuzhiyun pDev->valuator->last_motion;
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun memcpy(buff, &ms, sizeof(Time));
588*4882a593Smuzhiyun buff += sizeof(Time);
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun memset(buff, 0, sizeof(INT32) * pDev->valuator->numAxes);
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun for (i = 0; i < MAX_VALUATORS; i++) {
593*4882a593Smuzhiyun int val;
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i)) {
596*4882a593Smuzhiyun buff += sizeof(INT32);
597*4882a593Smuzhiyun continue;
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun val = valuators[i];
600*4882a593Smuzhiyun memcpy(buff, &val, sizeof(INT32));
601*4882a593Smuzhiyun buff += sizeof(INT32);
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun pDev->valuator->last_motion = (pDev->valuator->last_motion + 1) %
606*4882a593Smuzhiyun pDev->valuator->numMotionEvents;
607*4882a593Smuzhiyun /* If we're wrapping around, just keep the circular buffer going. */
608*4882a593Smuzhiyun if (pDev->valuator->first_motion == pDev->valuator->last_motion)
609*4882a593Smuzhiyun pDev->valuator->first_motion = (pDev->valuator->first_motion + 1) %
610*4882a593Smuzhiyun pDev->valuator->numMotionEvents;
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun return;
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun /**
616*4882a593Smuzhiyun * Returns the maximum number of events GetKeyboardEvents
617*4882a593Smuzhiyun * and GetPointerEvents will ever return.
618*4882a593Smuzhiyun *
619*4882a593Smuzhiyun * This MUST be absolutely constant, from init until exit.
620*4882a593Smuzhiyun */
621*4882a593Smuzhiyun int
GetMaximumEventsNum(void)622*4882a593Smuzhiyun GetMaximumEventsNum(void)
623*4882a593Smuzhiyun {
624*4882a593Smuzhiyun /* One raw event
625*4882a593Smuzhiyun * One device event
626*4882a593Smuzhiyun * One possible device changed event
627*4882a593Smuzhiyun * Lots of possible separate button scroll events (horiz + vert)
628*4882a593Smuzhiyun * Lots of possible separate raw button scroll events (horiz + vert)
629*4882a593Smuzhiyun */
630*4882a593Smuzhiyun return 100;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun /**
634*4882a593Smuzhiyun * Clip an axis to its bounds, which are declared in the call to
635*4882a593Smuzhiyun * InitValuatorAxisClassStruct.
636*4882a593Smuzhiyun */
637*4882a593Smuzhiyun static void
clipAxis(DeviceIntPtr pDev,int axisNum,double * val)638*4882a593Smuzhiyun clipAxis(DeviceIntPtr pDev, int axisNum, double *val)
639*4882a593Smuzhiyun {
640*4882a593Smuzhiyun AxisInfoPtr axis;
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun if (axisNum >= pDev->valuator->numAxes)
643*4882a593Smuzhiyun return;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun axis = pDev->valuator->axes + axisNum;
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun /* If a value range is defined, clip. If not, do nothing */
648*4882a593Smuzhiyun if (axis->max_value <= axis->min_value)
649*4882a593Smuzhiyun return;
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun if (*val < axis->min_value)
652*4882a593Smuzhiyun *val = axis->min_value;
653*4882a593Smuzhiyun if (*val > axis->max_value)
654*4882a593Smuzhiyun *val = axis->max_value;
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun /**
658*4882a593Smuzhiyun * Clip every axis in the list of valuators to its bounds.
659*4882a593Smuzhiyun */
660*4882a593Smuzhiyun static void
clipValuators(DeviceIntPtr pDev,ValuatorMask * mask)661*4882a593Smuzhiyun clipValuators(DeviceIntPtr pDev, ValuatorMask *mask)
662*4882a593Smuzhiyun {
663*4882a593Smuzhiyun int i;
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun for (i = 0; i < valuator_mask_size(mask); i++)
666*4882a593Smuzhiyun if (valuator_mask_isset(mask, i)) {
667*4882a593Smuzhiyun double val = valuator_mask_get_double(mask, i);
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun clipAxis(pDev, i, &val);
670*4882a593Smuzhiyun valuator_mask_set_double(mask, i, val);
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun /**
675*4882a593Smuzhiyun * Create the DCCE event (does not update the master's device state yet, this
676*4882a593Smuzhiyun * is done in the event processing).
677*4882a593Smuzhiyun * Pull in the coordinates from the MD if necessary.
678*4882a593Smuzhiyun *
679*4882a593Smuzhiyun * @param events Pointer to a pre-allocated event array.
680*4882a593Smuzhiyun * @param dev The slave device that generated an event.
681*4882a593Smuzhiyun * @param type Either DEVCHANGE_POINTER_EVENT and/or DEVCHANGE_KEYBOARD_EVENT
682*4882a593Smuzhiyun * @param num_events The current number of events, returns the number of
683*4882a593Smuzhiyun * events if a DCCE was generated.
684*4882a593Smuzhiyun * @return The updated @events pointer.
685*4882a593Smuzhiyun */
686*4882a593Smuzhiyun InternalEvent *
UpdateFromMaster(InternalEvent * events,DeviceIntPtr dev,int type,int * num_events)687*4882a593Smuzhiyun UpdateFromMaster(InternalEvent *events, DeviceIntPtr dev, int type,
688*4882a593Smuzhiyun int *num_events)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun DeviceIntPtr master;
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun master =
693*4882a593Smuzhiyun GetMaster(dev,
694*4882a593Smuzhiyun (type & DEVCHANGE_POINTER_EVENT) ? MASTER_POINTER :
695*4882a593Smuzhiyun MASTER_KEYBOARD);
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun if (master && master->last.slave != dev) {
698*4882a593Smuzhiyun CreateClassesChangedEvent(events, master, dev,
699*4882a593Smuzhiyun type | DEVCHANGE_SLAVE_SWITCH);
700*4882a593Smuzhiyun if (IsPointerDevice(master)) {
701*4882a593Smuzhiyun updateSlaveDeviceCoords(master, dev);
702*4882a593Smuzhiyun master->last.numValuators = dev->last.numValuators;
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun master->last.slave = dev;
705*4882a593Smuzhiyun (*num_events)++;
706*4882a593Smuzhiyun events++;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun return events;
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun /**
712*4882a593Smuzhiyun * Move the device's pointer to the position given in the valuators.
713*4882a593Smuzhiyun *
714*4882a593Smuzhiyun * @param dev The device whose pointer is to be moved.
715*4882a593Smuzhiyun * @param mask Valuator data for this event.
716*4882a593Smuzhiyun */
717*4882a593Smuzhiyun static void
clipAbsolute(DeviceIntPtr dev,ValuatorMask * mask)718*4882a593Smuzhiyun clipAbsolute(DeviceIntPtr dev, ValuatorMask *mask)
719*4882a593Smuzhiyun {
720*4882a593Smuzhiyun int i;
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun for (i = 0; i < valuator_mask_size(mask); i++) {
723*4882a593Smuzhiyun double val;
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun if (!valuator_mask_isset(mask, i))
726*4882a593Smuzhiyun continue;
727*4882a593Smuzhiyun val = valuator_mask_get_double(mask, i);
728*4882a593Smuzhiyun clipAxis(dev, i, &val);
729*4882a593Smuzhiyun valuator_mask_set_double(mask, i, val);
730*4882a593Smuzhiyun }
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun static void
add_to_scroll_valuator(DeviceIntPtr dev,ValuatorMask * mask,int valuator,double value)734*4882a593Smuzhiyun add_to_scroll_valuator(DeviceIntPtr dev, ValuatorMask *mask, int valuator, double value)
735*4882a593Smuzhiyun {
736*4882a593Smuzhiyun double v;
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun if (!valuator_mask_fetch_double(mask, valuator, &v))
739*4882a593Smuzhiyun return;
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun /* protect against scrolling overflow. INT_MAX for double, because
742*4882a593Smuzhiyun * we'll eventually write this as 32.32 fixed point */
743*4882a593Smuzhiyun if ((value > 0 && v > INT_MAX - value) || (value < 0 && v < INT_MIN - value)) {
744*4882a593Smuzhiyun v = 0;
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun /* reset last.scroll to avoid a button storm */
747*4882a593Smuzhiyun valuator_mask_set_double(dev->last.scroll, valuator, 0);
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun else
750*4882a593Smuzhiyun v += value;
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun valuator_mask_set_double(mask, valuator, v);
753*4882a593Smuzhiyun }
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun static void
scale_for_device_resolution(DeviceIntPtr dev,ValuatorMask * mask)757*4882a593Smuzhiyun scale_for_device_resolution(DeviceIntPtr dev, ValuatorMask *mask)
758*4882a593Smuzhiyun {
759*4882a593Smuzhiyun double y;
760*4882a593Smuzhiyun ValuatorClassPtr v = dev->valuator;
761*4882a593Smuzhiyun int xrange = v->axes[0].max_value - v->axes[0].min_value + 1;
762*4882a593Smuzhiyun int yrange = v->axes[1].max_value - v->axes[1].min_value + 1;
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun double screen_ratio = 1.0 * screenInfo.width/screenInfo.height;
765*4882a593Smuzhiyun double device_ratio = 1.0 * xrange/yrange;
766*4882a593Smuzhiyun double resolution_ratio = 1.0;
767*4882a593Smuzhiyun double ratio;
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun if (!valuator_mask_fetch_double(mask, 1, &y))
770*4882a593Smuzhiyun return;
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun if (v->axes[0].resolution != 0 && v->axes[1].resolution != 0)
773*4882a593Smuzhiyun resolution_ratio = 1.0 * v->axes[0].resolution/v->axes[1].resolution;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun ratio = device_ratio/resolution_ratio/screen_ratio;
776*4882a593Smuzhiyun valuator_mask_set_double(mask, 1, y / ratio);
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun /**
780*4882a593Smuzhiyun * Move the device's pointer by the values given in @valuators.
781*4882a593Smuzhiyun *
782*4882a593Smuzhiyun * @param dev The device whose pointer is to be moved.
783*4882a593Smuzhiyun * @param[in,out] mask Valuator data for this event, modified in-place.
784*4882a593Smuzhiyun */
785*4882a593Smuzhiyun static void
moveRelative(DeviceIntPtr dev,int flags,ValuatorMask * mask)786*4882a593Smuzhiyun moveRelative(DeviceIntPtr dev, int flags, ValuatorMask *mask)
787*4882a593Smuzhiyun {
788*4882a593Smuzhiyun int i;
789*4882a593Smuzhiyun Bool clip_xy = IsMaster(dev) || !IsFloating(dev);
790*4882a593Smuzhiyun ValuatorClassPtr v = dev->valuator;
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun /* for abs devices in relative mode, we've just scaled wrong, since we
793*4882a593Smuzhiyun mapped the device's shape into the screen shape. Undo this. */
794*4882a593Smuzhiyun if ((flags & POINTER_ABSOLUTE) == 0 && v && v->numAxes > 1 &&
795*4882a593Smuzhiyun v->axes[0].min_value < v->axes[0].max_value &&
796*4882a593Smuzhiyun v->axes[1].min_value < v->axes[1].max_value) {
797*4882a593Smuzhiyun scale_for_device_resolution(dev, mask);
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun /* calc other axes, clip, drop back into valuators */
801*4882a593Smuzhiyun for (i = 0; i < valuator_mask_size(mask); i++) {
802*4882a593Smuzhiyun double val = dev->last.valuators[i];
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun if (!valuator_mask_isset(mask, i))
805*4882a593Smuzhiyun continue;
806*4882a593Smuzhiyun
807*4882a593Smuzhiyun add_to_scroll_valuator(dev, mask, i, val);
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun /* x & y need to go over the limits to cross screens if the SD
810*4882a593Smuzhiyun * isn't currently attached; otherwise, clip to screen bounds. */
811*4882a593Smuzhiyun if (valuator_get_mode(dev, i) == Absolute &&
812*4882a593Smuzhiyun ((i != 0 && i != 1) || clip_xy)) {
813*4882a593Smuzhiyun val = valuator_mask_get_double(mask, i);
814*4882a593Smuzhiyun clipAxis(dev, i, &val);
815*4882a593Smuzhiyun valuator_mask_set_double(mask, i, val);
816*4882a593Smuzhiyun }
817*4882a593Smuzhiyun }
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun /**
821*4882a593Smuzhiyun * Accelerate the data in valuators based on the device's acceleration scheme.
822*4882a593Smuzhiyun *
823*4882a593Smuzhiyun * @param dev The device which's pointer is to be moved.
824*4882a593Smuzhiyun * @param valuators Valuator mask
825*4882a593Smuzhiyun * @param ms Current time.
826*4882a593Smuzhiyun */
827*4882a593Smuzhiyun static void
accelPointer(DeviceIntPtr dev,ValuatorMask * valuators,CARD32 ms)828*4882a593Smuzhiyun accelPointer(DeviceIntPtr dev, ValuatorMask *valuators, CARD32 ms)
829*4882a593Smuzhiyun {
830*4882a593Smuzhiyun if (dev->valuator->accelScheme.AccelSchemeProc)
831*4882a593Smuzhiyun dev->valuator->accelScheme.AccelSchemeProc(dev, valuators, ms);
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun /**
835*4882a593Smuzhiyun * Scale from absolute screen coordinates to absolute coordinates in the
836*4882a593Smuzhiyun * device's coordinate range.
837*4882a593Smuzhiyun *
838*4882a593Smuzhiyun * @param dev The device to scale for.
839*4882a593Smuzhiyun * @param[in, out] mask The mask in desktop/screen coordinates, modified in place
840*4882a593Smuzhiyun * to contain device coordinate range.
841*4882a593Smuzhiyun * @param flags If POINTER_SCREEN is set, mask is in per-screen coordinates.
842*4882a593Smuzhiyun * Otherwise, mask is in desktop coords.
843*4882a593Smuzhiyun */
844*4882a593Smuzhiyun static void
scale_from_screen(DeviceIntPtr dev,ValuatorMask * mask,int flags)845*4882a593Smuzhiyun scale_from_screen(DeviceIntPtr dev, ValuatorMask *mask, int flags)
846*4882a593Smuzhiyun {
847*4882a593Smuzhiyun double scaled;
848*4882a593Smuzhiyun ScreenPtr scr = miPointerGetScreen(dev);
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun if (valuator_mask_isset(mask, 0)) {
851*4882a593Smuzhiyun scaled = valuator_mask_get_double(mask, 0);
852*4882a593Smuzhiyun if (flags & POINTER_SCREEN)
853*4882a593Smuzhiyun scaled += scr->x;
854*4882a593Smuzhiyun scaled = rescaleValuatorAxis(scaled,
855*4882a593Smuzhiyun NULL, dev->valuator->axes + 0,
856*4882a593Smuzhiyun screenInfo.x, screenInfo.width);
857*4882a593Smuzhiyun valuator_mask_set_double(mask, 0, scaled);
858*4882a593Smuzhiyun }
859*4882a593Smuzhiyun if (valuator_mask_isset(mask, 1)) {
860*4882a593Smuzhiyun scaled = valuator_mask_get_double(mask, 1);
861*4882a593Smuzhiyun if (flags & POINTER_SCREEN)
862*4882a593Smuzhiyun scaled += scr->y;
863*4882a593Smuzhiyun scaled = rescaleValuatorAxis(scaled,
864*4882a593Smuzhiyun NULL, dev->valuator->axes + 1,
865*4882a593Smuzhiyun screenInfo.y, screenInfo.height);
866*4882a593Smuzhiyun valuator_mask_set_double(mask, 1, scaled);
867*4882a593Smuzhiyun }
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun
870*4882a593Smuzhiyun /**
871*4882a593Smuzhiyun * Scale from (absolute) device to screen coordinates here,
872*4882a593Smuzhiyun *
873*4882a593Smuzhiyun * The coordinates provided are always absolute. see fill_pointer_events for
874*4882a593Smuzhiyun * information on coordinate systems.
875*4882a593Smuzhiyun *
876*4882a593Smuzhiyun * @param dev The device to be moved.
877*4882a593Smuzhiyun * @param mask Mask of axis values for this event
878*4882a593Smuzhiyun * @param[out] devx x desktop-wide coordinate in device coordinate system
879*4882a593Smuzhiyun * @param[out] devy y desktop-wide coordinate in device coordinate system
880*4882a593Smuzhiyun * @param[out] screenx x coordinate in desktop coordinate system
881*4882a593Smuzhiyun * @param[out] screeny y coordinate in desktop coordinate system
882*4882a593Smuzhiyun */
883*4882a593Smuzhiyun static ScreenPtr
scale_to_desktop(DeviceIntPtr dev,ValuatorMask * mask,double * devx,double * devy,double * screenx,double * screeny)884*4882a593Smuzhiyun scale_to_desktop(DeviceIntPtr dev, ValuatorMask *mask,
885*4882a593Smuzhiyun double *devx, double *devy, double *screenx, double *screeny)
886*4882a593Smuzhiyun {
887*4882a593Smuzhiyun ScreenPtr scr = miPointerGetScreen(dev);
888*4882a593Smuzhiyun double x, y;
889*4882a593Smuzhiyun
890*4882a593Smuzhiyun BUG_WARN(dev->valuator && dev->valuator->numAxes < 2);
891*4882a593Smuzhiyun if (!dev->valuator || dev->valuator->numAxes < 2) {
892*4882a593Smuzhiyun /* if we have no axes, last.valuators must be in screen coords
893*4882a593Smuzhiyun * anyway */
894*4882a593Smuzhiyun *devx = *screenx = dev->last.valuators[0];
895*4882a593Smuzhiyun *devy = *screeny = dev->last.valuators[1];
896*4882a593Smuzhiyun return scr;
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun if (valuator_mask_isset(mask, 0))
900*4882a593Smuzhiyun x = valuator_mask_get_double(mask, 0);
901*4882a593Smuzhiyun else
902*4882a593Smuzhiyun x = dev->last.valuators[0];
903*4882a593Smuzhiyun if (valuator_mask_isset(mask, 1))
904*4882a593Smuzhiyun y = valuator_mask_get_double(mask, 1);
905*4882a593Smuzhiyun else
906*4882a593Smuzhiyun y = dev->last.valuators[1];
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun /* scale x&y to desktop coordinates */
909*4882a593Smuzhiyun *screenx = rescaleValuatorAxis(x, dev->valuator->axes + 0, NULL,
910*4882a593Smuzhiyun screenInfo.x, screenInfo.width);
911*4882a593Smuzhiyun *screeny = rescaleValuatorAxis(y, dev->valuator->axes + 1, NULL,
912*4882a593Smuzhiyun screenInfo.y, screenInfo.height);
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun *devx = x;
915*4882a593Smuzhiyun *devy = y;
916*4882a593Smuzhiyun
917*4882a593Smuzhiyun return scr;
918*4882a593Smuzhiyun }
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun /**
921*4882a593Smuzhiyun * If we have HW cursors, this actually moves the visible sprite. If not, we
922*4882a593Smuzhiyun * just do all the screen crossing, etc.
923*4882a593Smuzhiyun *
924*4882a593Smuzhiyun * We use the screen coordinates here, call miPointerSetPosition() and then
925*4882a593Smuzhiyun * scale back into device coordinates (if needed). miPSP will change x/y if
926*4882a593Smuzhiyun * the screen was crossed.
927*4882a593Smuzhiyun *
928*4882a593Smuzhiyun * The coordinates provided are always absolute. The parameter mode
929*4882a593Smuzhiyun * specifies whether it was relative or absolute movement that landed us at
930*4882a593Smuzhiyun * those coordinates. see fill_pointer_events for information on coordinate
931*4882a593Smuzhiyun * systems.
932*4882a593Smuzhiyun *
933*4882a593Smuzhiyun * @param dev The device to be moved.
934*4882a593Smuzhiyun * @param mode Movement mode (Absolute or Relative)
935*4882a593Smuzhiyun * @param[out] mask Mask of axis values for this event, returns the
936*4882a593Smuzhiyun * per-screen device coordinates after confinement
937*4882a593Smuzhiyun * @param[in,out] devx x desktop-wide coordinate in device coordinate system
938*4882a593Smuzhiyun * @param[in,out] devy y desktop-wide coordinate in device coordinate system
939*4882a593Smuzhiyun * @param[in,out] screenx x coordinate in desktop coordinate system
940*4882a593Smuzhiyun * @param[in,out] screeny y coordinate in desktop coordinate system
941*4882a593Smuzhiyun * @param[out] nevents Number of barrier events added to events
942*4882a593Smuzhiyun * @param[in,out] events List of events barrier events are added to
943*4882a593Smuzhiyun */
944*4882a593Smuzhiyun static ScreenPtr
positionSprite(DeviceIntPtr dev,int mode,ValuatorMask * mask,double * devx,double * devy,double * screenx,double * screeny,int * nevents,InternalEvent * events)945*4882a593Smuzhiyun positionSprite(DeviceIntPtr dev, int mode, ValuatorMask *mask,
946*4882a593Smuzhiyun double *devx, double *devy, double *screenx, double *screeny,
947*4882a593Smuzhiyun int *nevents, InternalEvent* events)
948*4882a593Smuzhiyun {
949*4882a593Smuzhiyun ScreenPtr scr = miPointerGetScreen(dev);
950*4882a593Smuzhiyun double tmpx, tmpy;
951*4882a593Smuzhiyun
952*4882a593Smuzhiyun if (!dev->valuator || dev->valuator->numAxes < 2)
953*4882a593Smuzhiyun return scr;
954*4882a593Smuzhiyun
955*4882a593Smuzhiyun tmpx = *screenx;
956*4882a593Smuzhiyun tmpy = *screeny;
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun /* miPointerSetPosition takes care of crossing screens for us, as well as
959*4882a593Smuzhiyun * clipping to the current screen. Coordinates returned are in desktop
960*4882a593Smuzhiyun * coord system */
961*4882a593Smuzhiyun scr = miPointerSetPosition(dev, mode, screenx, screeny, nevents, events);
962*4882a593Smuzhiyun
963*4882a593Smuzhiyun /* If we were constrained, rescale x/y from the screen coordinates so
964*4882a593Smuzhiyun * the device valuators reflect the correct position. For screen
965*4882a593Smuzhiyun * crossing this doesn't matter much, the coords would be 0 or max.
966*4882a593Smuzhiyun */
967*4882a593Smuzhiyun if (tmpx != *screenx)
968*4882a593Smuzhiyun *devx = rescaleValuatorAxis(*screenx, NULL, dev->valuator->axes + 0,
969*4882a593Smuzhiyun screenInfo.x, screenInfo.width);
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun if (tmpy != *screeny)
972*4882a593Smuzhiyun *devy = rescaleValuatorAxis(*screeny, NULL, dev->valuator->axes + 1,
973*4882a593Smuzhiyun screenInfo.y, screenInfo.height);
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun /* Recalculate the per-screen device coordinates */
976*4882a593Smuzhiyun if (valuator_mask_isset(mask, 0)) {
977*4882a593Smuzhiyun double x;
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun x = rescaleValuatorAxis(*screenx - scr->x, NULL,
980*4882a593Smuzhiyun dev->valuator->axes + 0, 0, scr->width);
981*4882a593Smuzhiyun valuator_mask_set_double(mask, 0, x);
982*4882a593Smuzhiyun }
983*4882a593Smuzhiyun if (valuator_mask_isset(mask, 1)) {
984*4882a593Smuzhiyun double y;
985*4882a593Smuzhiyun
986*4882a593Smuzhiyun y = rescaleValuatorAxis(*screeny - scr->y, NULL,
987*4882a593Smuzhiyun dev->valuator->axes + 1, 0, scr->height);
988*4882a593Smuzhiyun valuator_mask_set_double(mask, 1, y);
989*4882a593Smuzhiyun }
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun return scr;
992*4882a593Smuzhiyun }
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun /**
995*4882a593Smuzhiyun * Update the motion history for the device and (if appropriate) for its
996*4882a593Smuzhiyun * master device.
997*4882a593Smuzhiyun * @param dev Slave device to update.
998*4882a593Smuzhiyun * @param mask Bit mask of valid valuators to append to history.
999*4882a593Smuzhiyun * @param num Total number of valuators to append to history.
1000*4882a593Smuzhiyun * @param ms Current time
1001*4882a593Smuzhiyun */
1002*4882a593Smuzhiyun static void
updateHistory(DeviceIntPtr dev,ValuatorMask * mask,CARD32 ms)1003*4882a593Smuzhiyun updateHistory(DeviceIntPtr dev, ValuatorMask *mask, CARD32 ms)
1004*4882a593Smuzhiyun {
1005*4882a593Smuzhiyun if (!dev->valuator)
1006*4882a593Smuzhiyun return;
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun updateMotionHistory(dev, ms, mask, dev->last.valuators);
1009*4882a593Smuzhiyun if (!IsMaster(dev) && !IsFloating(dev)) {
1010*4882a593Smuzhiyun DeviceIntPtr master = GetMaster(dev, MASTER_POINTER);
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun updateMotionHistory(master, ms, mask, dev->last.valuators);
1013*4882a593Smuzhiyun }
1014*4882a593Smuzhiyun }
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun static void
queueEventList(DeviceIntPtr device,InternalEvent * events,int nevents)1017*4882a593Smuzhiyun queueEventList(DeviceIntPtr device, InternalEvent *events, int nevents)
1018*4882a593Smuzhiyun {
1019*4882a593Smuzhiyun int i;
1020*4882a593Smuzhiyun
1021*4882a593Smuzhiyun for (i = 0; i < nevents; i++)
1022*4882a593Smuzhiyun mieqEnqueue(device, &events[i]);
1023*4882a593Smuzhiyun }
1024*4882a593Smuzhiyun
1025*4882a593Smuzhiyun static void
event_set_root_coordinates(DeviceEvent * event,double x,double y)1026*4882a593Smuzhiyun event_set_root_coordinates(DeviceEvent *event, double x, double y)
1027*4882a593Smuzhiyun {
1028*4882a593Smuzhiyun event->root_x = trunc(x);
1029*4882a593Smuzhiyun event->root_y = trunc(y);
1030*4882a593Smuzhiyun event->root_x_frac = x - trunc(x);
1031*4882a593Smuzhiyun event->root_y_frac = y - trunc(y);
1032*4882a593Smuzhiyun }
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun /**
1035*4882a593Smuzhiyun * Generate internal events representing this keyboard event and enqueue
1036*4882a593Smuzhiyun * them on the event queue.
1037*4882a593Smuzhiyun *
1038*4882a593Smuzhiyun * This function is not reentrant. Disable signals before calling.
1039*4882a593Smuzhiyun *
1040*4882a593Smuzhiyun * @param device The device to generate the event for
1041*4882a593Smuzhiyun * @param type Event type, one of KeyPress or KeyRelease
1042*4882a593Smuzhiyun * @param keycode Key code of the pressed/released key
1043*4882a593Smuzhiyun *
1044*4882a593Smuzhiyun */
1045*4882a593Smuzhiyun void
QueueKeyboardEvents(DeviceIntPtr device,int type,int keycode)1046*4882a593Smuzhiyun QueueKeyboardEvents(DeviceIntPtr device, int type,
1047*4882a593Smuzhiyun int keycode)
1048*4882a593Smuzhiyun {
1049*4882a593Smuzhiyun int nevents;
1050*4882a593Smuzhiyun
1051*4882a593Smuzhiyun nevents = GetKeyboardEvents(InputEventList, device, type, keycode);
1052*4882a593Smuzhiyun queueEventList(device, InputEventList, nevents);
1053*4882a593Smuzhiyun }
1054*4882a593Smuzhiyun
1055*4882a593Smuzhiyun /**
1056*4882a593Smuzhiyun * Returns a set of InternalEvents for KeyPress/KeyRelease, optionally
1057*4882a593Smuzhiyun * also with valuator events.
1058*4882a593Smuzhiyun *
1059*4882a593Smuzhiyun * The DDX is responsible for allocating the event list in the first
1060*4882a593Smuzhiyun * place via InitEventList(), and for freeing it.
1061*4882a593Smuzhiyun *
1062*4882a593Smuzhiyun * @return the number of events written into events.
1063*4882a593Smuzhiyun */
1064*4882a593Smuzhiyun int
GetKeyboardEvents(InternalEvent * events,DeviceIntPtr pDev,int type,int key_code)1065*4882a593Smuzhiyun GetKeyboardEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
1066*4882a593Smuzhiyun int key_code)
1067*4882a593Smuzhiyun {
1068*4882a593Smuzhiyun int num_events = 0;
1069*4882a593Smuzhiyun CARD32 ms = 0;
1070*4882a593Smuzhiyun DeviceEvent *event;
1071*4882a593Smuzhiyun RawDeviceEvent *raw;
1072*4882a593Smuzhiyun enum DeviceEventSource source_type = EVENT_SOURCE_NORMAL;
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun #if XSERVER_DTRACE
1075*4882a593Smuzhiyun if (XSERVER_INPUT_EVENT_ENABLED()) {
1076*4882a593Smuzhiyun XSERVER_INPUT_EVENT(pDev->id, type, key_code, 0, 0,
1077*4882a593Smuzhiyun NULL, NULL);
1078*4882a593Smuzhiyun }
1079*4882a593Smuzhiyun #endif
1080*4882a593Smuzhiyun
1081*4882a593Smuzhiyun if (type == EnterNotify) {
1082*4882a593Smuzhiyun source_type = EVENT_SOURCE_FOCUS;
1083*4882a593Smuzhiyun type = KeyPress;
1084*4882a593Smuzhiyun } else if (type == LeaveNotify) {
1085*4882a593Smuzhiyun source_type = EVENT_SOURCE_FOCUS;
1086*4882a593Smuzhiyun type = KeyRelease;
1087*4882a593Smuzhiyun }
1088*4882a593Smuzhiyun
1089*4882a593Smuzhiyun /* refuse events from disabled devices */
1090*4882a593Smuzhiyun if (!pDev->enabled)
1091*4882a593Smuzhiyun return 0;
1092*4882a593Smuzhiyun
1093*4882a593Smuzhiyun if (!events || !pDev->key || !pDev->focus || !pDev->kbdfeed ||
1094*4882a593Smuzhiyun (type != KeyPress && type != KeyRelease) ||
1095*4882a593Smuzhiyun (key_code < 8 || key_code > 255))
1096*4882a593Smuzhiyun return 0;
1097*4882a593Smuzhiyun
1098*4882a593Smuzhiyun num_events = 1;
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun events =
1101*4882a593Smuzhiyun UpdateFromMaster(events, pDev, DEVCHANGE_KEYBOARD_EVENT, &num_events);
1102*4882a593Smuzhiyun
1103*4882a593Smuzhiyun /* Handle core repeating, via press/release/press/release. */
1104*4882a593Smuzhiyun if (type == KeyPress && key_is_down(pDev, key_code, KEY_POSTED)) {
1105*4882a593Smuzhiyun /* If autorepeating is disabled either globally or just for that key,
1106*4882a593Smuzhiyun * or we have a modifier, don't generate a repeat event. */
1107*4882a593Smuzhiyun if (!pDev->kbdfeed->ctrl.autoRepeat ||
1108*4882a593Smuzhiyun !key_autorepeats(pDev, key_code) ||
1109*4882a593Smuzhiyun pDev->key->xkbInfo->desc->map->modmap[key_code])
1110*4882a593Smuzhiyun return 0;
1111*4882a593Smuzhiyun }
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun ms = GetTimeInMillis();
1114*4882a593Smuzhiyun
1115*4882a593Smuzhiyun if (source_type == EVENT_SOURCE_NORMAL) {
1116*4882a593Smuzhiyun raw = &events->raw_event;
1117*4882a593Smuzhiyun init_raw(pDev, raw, ms, type, key_code);
1118*4882a593Smuzhiyun events++;
1119*4882a593Smuzhiyun num_events++;
1120*4882a593Smuzhiyun }
1121*4882a593Smuzhiyun
1122*4882a593Smuzhiyun event = &events->device_event;
1123*4882a593Smuzhiyun init_device_event(event, pDev, ms, source_type);
1124*4882a593Smuzhiyun event->detail.key = key_code;
1125*4882a593Smuzhiyun
1126*4882a593Smuzhiyun if (type == KeyPress) {
1127*4882a593Smuzhiyun event->type = ET_KeyPress;
1128*4882a593Smuzhiyun set_key_down(pDev, key_code, KEY_POSTED);
1129*4882a593Smuzhiyun }
1130*4882a593Smuzhiyun else if (type == KeyRelease) {
1131*4882a593Smuzhiyun event->type = ET_KeyRelease;
1132*4882a593Smuzhiyun set_key_up(pDev, key_code, KEY_POSTED);
1133*4882a593Smuzhiyun }
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun return num_events;
1136*4882a593Smuzhiyun }
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun /**
1139*4882a593Smuzhiyun * Initialize an event array large enough for num_events arrays.
1140*4882a593Smuzhiyun * This event list is to be passed into GetPointerEvents() and
1141*4882a593Smuzhiyun * GetKeyboardEvents().
1142*4882a593Smuzhiyun *
1143*4882a593Smuzhiyun * @param num_events Number of elements in list.
1144*4882a593Smuzhiyun */
1145*4882a593Smuzhiyun InternalEvent *
InitEventList(int num_events)1146*4882a593Smuzhiyun InitEventList(int num_events)
1147*4882a593Smuzhiyun {
1148*4882a593Smuzhiyun InternalEvent *events = calloc(num_events, sizeof(InternalEvent));
1149*4882a593Smuzhiyun
1150*4882a593Smuzhiyun return events;
1151*4882a593Smuzhiyun }
1152*4882a593Smuzhiyun
1153*4882a593Smuzhiyun /**
1154*4882a593Smuzhiyun * Free an event list.
1155*4882a593Smuzhiyun *
1156*4882a593Smuzhiyun * @param list The list to be freed.
1157*4882a593Smuzhiyun * @param num_events Number of elements in list.
1158*4882a593Smuzhiyun */
1159*4882a593Smuzhiyun void
FreeEventList(InternalEvent * list,int num_events)1160*4882a593Smuzhiyun FreeEventList(InternalEvent *list, int num_events)
1161*4882a593Smuzhiyun {
1162*4882a593Smuzhiyun free(list);
1163*4882a593Smuzhiyun }
1164*4882a593Smuzhiyun
1165*4882a593Smuzhiyun /**
1166*4882a593Smuzhiyun * Transform vector x/y according to matrix m and drop the rounded coords
1167*4882a593Smuzhiyun * back into x/y.
1168*4882a593Smuzhiyun */
1169*4882a593Smuzhiyun static void
transform(struct pixman_f_transform * m,double * x,double * y)1170*4882a593Smuzhiyun transform(struct pixman_f_transform *m, double *x, double *y)
1171*4882a593Smuzhiyun {
1172*4882a593Smuzhiyun struct pixman_f_vector p = {.v = {*x, *y, 1} };
1173*4882a593Smuzhiyun pixman_f_transform_point(m, &p);
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun *x = p.v[0];
1176*4882a593Smuzhiyun *y = p.v[1];
1177*4882a593Smuzhiyun }
1178*4882a593Smuzhiyun
1179*4882a593Smuzhiyun static void
transformRelative(DeviceIntPtr dev,ValuatorMask * mask)1180*4882a593Smuzhiyun transformRelative(DeviceIntPtr dev, ValuatorMask *mask)
1181*4882a593Smuzhiyun {
1182*4882a593Smuzhiyun double x = 0, y = 0;
1183*4882a593Smuzhiyun
1184*4882a593Smuzhiyun valuator_mask_fetch_double(mask, 0, &x);
1185*4882a593Smuzhiyun valuator_mask_fetch_double(mask, 1, &y);
1186*4882a593Smuzhiyun
1187*4882a593Smuzhiyun transform(&dev->relative_transform, &x, &y);
1188*4882a593Smuzhiyun
1189*4882a593Smuzhiyun if (x)
1190*4882a593Smuzhiyun valuator_mask_set_double(mask, 0, x);
1191*4882a593Smuzhiyun else
1192*4882a593Smuzhiyun valuator_mask_unset(mask, 0);
1193*4882a593Smuzhiyun
1194*4882a593Smuzhiyun if (y)
1195*4882a593Smuzhiyun valuator_mask_set_double(mask, 1, y);
1196*4882a593Smuzhiyun else
1197*4882a593Smuzhiyun valuator_mask_unset(mask, 1);
1198*4882a593Smuzhiyun }
1199*4882a593Smuzhiyun
1200*4882a593Smuzhiyun /**
1201*4882a593Smuzhiyun * Apply the device's transformation matrix to the valuator mask and replace
1202*4882a593Smuzhiyun * the scaled values in mask. This transformation only applies to valuators
1203*4882a593Smuzhiyun * 0 and 1, others will be untouched.
1204*4882a593Smuzhiyun *
1205*4882a593Smuzhiyun * @param dev The device the valuators came from
1206*4882a593Smuzhiyun * @param[in,out] mask The valuator mask.
1207*4882a593Smuzhiyun */
1208*4882a593Smuzhiyun static void
transformAbsolute(DeviceIntPtr dev,ValuatorMask * mask)1209*4882a593Smuzhiyun transformAbsolute(DeviceIntPtr dev, ValuatorMask *mask)
1210*4882a593Smuzhiyun {
1211*4882a593Smuzhiyun double x, y, ox = 0.0, oy = 0.0;
1212*4882a593Smuzhiyun int has_x, has_y;
1213*4882a593Smuzhiyun
1214*4882a593Smuzhiyun has_x = valuator_mask_isset(mask, 0);
1215*4882a593Smuzhiyun has_y = valuator_mask_isset(mask, 1);
1216*4882a593Smuzhiyun
1217*4882a593Smuzhiyun if (!has_x && !has_y)
1218*4882a593Smuzhiyun return;
1219*4882a593Smuzhiyun
1220*4882a593Smuzhiyun if (!has_x || !has_y) {
1221*4882a593Smuzhiyun struct pixman_f_transform invert;
1222*4882a593Smuzhiyun
1223*4882a593Smuzhiyun /* undo transformation from last event */
1224*4882a593Smuzhiyun ox = dev->last.valuators[0];
1225*4882a593Smuzhiyun oy = dev->last.valuators[1];
1226*4882a593Smuzhiyun
1227*4882a593Smuzhiyun pixman_f_transform_invert(&invert, &dev->scale_and_transform);
1228*4882a593Smuzhiyun transform(&invert, &ox, &oy);
1229*4882a593Smuzhiyun }
1230*4882a593Smuzhiyun
1231*4882a593Smuzhiyun if (has_x)
1232*4882a593Smuzhiyun ox = valuator_mask_get_double(mask, 0);
1233*4882a593Smuzhiyun
1234*4882a593Smuzhiyun if (has_y)
1235*4882a593Smuzhiyun oy = valuator_mask_get_double(mask, 1);
1236*4882a593Smuzhiyun
1237*4882a593Smuzhiyun x = ox;
1238*4882a593Smuzhiyun y = oy;
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun transform(&dev->scale_and_transform, &x, &y);
1241*4882a593Smuzhiyun
1242*4882a593Smuzhiyun if (has_x || ox != x)
1243*4882a593Smuzhiyun valuator_mask_set_double(mask, 0, x);
1244*4882a593Smuzhiyun
1245*4882a593Smuzhiyun if (has_y || oy != y)
1246*4882a593Smuzhiyun valuator_mask_set_double(mask, 1, y);
1247*4882a593Smuzhiyun }
1248*4882a593Smuzhiyun
1249*4882a593Smuzhiyun static void
storeLastValuators(DeviceIntPtr dev,ValuatorMask * mask,int xaxis,int yaxis,double devx,double devy)1250*4882a593Smuzhiyun storeLastValuators(DeviceIntPtr dev, ValuatorMask *mask,
1251*4882a593Smuzhiyun int xaxis, int yaxis, double devx, double devy)
1252*4882a593Smuzhiyun {
1253*4882a593Smuzhiyun int i;
1254*4882a593Smuzhiyun
1255*4882a593Smuzhiyun /* store desktop-wide in last.valuators */
1256*4882a593Smuzhiyun if (valuator_mask_isset(mask, xaxis))
1257*4882a593Smuzhiyun dev->last.valuators[0] = devx;
1258*4882a593Smuzhiyun if (valuator_mask_isset(mask, yaxis))
1259*4882a593Smuzhiyun dev->last.valuators[1] = devy;
1260*4882a593Smuzhiyun
1261*4882a593Smuzhiyun for (i = 0; i < valuator_mask_size(mask); i++) {
1262*4882a593Smuzhiyun if (i == xaxis || i == yaxis)
1263*4882a593Smuzhiyun continue;
1264*4882a593Smuzhiyun
1265*4882a593Smuzhiyun if (valuator_mask_isset(mask, i))
1266*4882a593Smuzhiyun dev->last.valuators[i] = valuator_mask_get_double(mask, i);
1267*4882a593Smuzhiyun }
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun }
1270*4882a593Smuzhiyun
1271*4882a593Smuzhiyun /**
1272*4882a593Smuzhiyun * Generate internal events representing this pointer event and enqueue them
1273*4882a593Smuzhiyun * on the event queue.
1274*4882a593Smuzhiyun *
1275*4882a593Smuzhiyun * This function is not reentrant. Disable signals before calling.
1276*4882a593Smuzhiyun *
1277*4882a593Smuzhiyun * @param device The device to generate the event for
1278*4882a593Smuzhiyun * @param type Event type, one of ButtonPress, ButtonRelease, MotionNotify
1279*4882a593Smuzhiyun * @param buttons Button number of the buttons modified. Must be 0 for
1280*4882a593Smuzhiyun * MotionNotify
1281*4882a593Smuzhiyun * @param flags Event modification flags
1282*4882a593Smuzhiyun * @param mask Valuator mask for valuators present for this event.
1283*4882a593Smuzhiyun */
1284*4882a593Smuzhiyun void
QueuePointerEvents(DeviceIntPtr device,int type,int buttons,int flags,const ValuatorMask * mask)1285*4882a593Smuzhiyun QueuePointerEvents(DeviceIntPtr device, int type,
1286*4882a593Smuzhiyun int buttons, int flags, const ValuatorMask *mask)
1287*4882a593Smuzhiyun {
1288*4882a593Smuzhiyun int nevents;
1289*4882a593Smuzhiyun
1290*4882a593Smuzhiyun nevents =
1291*4882a593Smuzhiyun GetPointerEvents(InputEventList, device, type, buttons, flags, mask);
1292*4882a593Smuzhiyun queueEventList(device, InputEventList, nevents);
1293*4882a593Smuzhiyun }
1294*4882a593Smuzhiyun
1295*4882a593Smuzhiyun /**
1296*4882a593Smuzhiyun * Helper function for GetPointerEvents, which only generates motion and
1297*4882a593Smuzhiyun * raw motion events for the slave device: does not update the master device.
1298*4882a593Smuzhiyun *
1299*4882a593Smuzhiyun * Should not be called by anyone other than GetPointerEvents.
1300*4882a593Smuzhiyun *
1301*4882a593Smuzhiyun * We use several different coordinate systems and need to switch between
1302*4882a593Smuzhiyun * the three in fill_pointer_events, positionSprite and
1303*4882a593Smuzhiyun * miPointerSetPosition. "desktop" refers to the width/height of all
1304*4882a593Smuzhiyun * screenInfo.screens[n]->width/height added up. "screen" is ScreenRec, not
1305*4882a593Smuzhiyun * output.
1306*4882a593Smuzhiyun *
1307*4882a593Smuzhiyun * Coordinate systems:
1308*4882a593Smuzhiyun * - relative events have a mask_in in relative coordinates, mapped to
1309*4882a593Smuzhiyun * pixels. These events are mapped to the current position±delta.
1310*4882a593Smuzhiyun * - absolute events have a mask_in in absolute device coordinates in
1311*4882a593Smuzhiyun * device-specific range. This range is mapped to the desktop.
1312*4882a593Smuzhiyun * - POINTER_SCREEN absolute events (x86WarpCursor) are in screen-relative
1313*4882a593Smuzhiyun * screen coordinate range.
1314*4882a593Smuzhiyun * - rootx/rooty in events must be be relative to the current screen's
1315*4882a593Smuzhiyun * origin (screen coordinate system)
1316*4882a593Smuzhiyun * - XI2 valuators must be relative to the current screen's origin. On
1317*4882a593Smuzhiyun * the protocol the device min/max range maps to the current screen.
1318*4882a593Smuzhiyun *
1319*4882a593Smuzhiyun * For screen switching we need to get the desktop coordinates for each
1320*4882a593Smuzhiyun * event, then map that to the respective position on each screen and
1321*4882a593Smuzhiyun * position the cursor there.
1322*4882a593Smuzhiyun * The device's last.valuator[] stores the last position in desktop-wide
1323*4882a593Smuzhiyun * coordinates (in device range for slave devices, desktop range for master
1324*4882a593Smuzhiyun * devices).
1325*4882a593Smuzhiyun *
1326*4882a593Smuzhiyun * screen-relative device coordinates requires scaling: A device coordinate
1327*4882a593Smuzhiyun * x/y of range [n..m] that maps to positions Sx/Sy on Screen S must be
1328*4882a593Smuzhiyun * rescaled to match Sx/Sy for [n..m]. In the simplest example, x of (m/2-1)
1329*4882a593Smuzhiyun * is the last coordinate on the first screen and must be rescaled for the
1330*4882a593Smuzhiyun * event to be m. XI2 clients that do their own coordinate mapping would
1331*4882a593Smuzhiyun * otherwise interpret the position of the device elsewere to the cursor.
1332*4882a593Smuzhiyun * However, this scaling leads to losses:
1333*4882a593Smuzhiyun * if we have two ScreenRecs we scale from e.g. [0..44704] (Wacom I4) to
1334*4882a593Smuzhiyun * [0..2048[. that gives us 2047.954 as desktop coord, or the per-screen
1335*4882a593Smuzhiyun * coordinate 1023.954. Scaling that back into the device coordinate range
1336*4882a593Smuzhiyun * gives us 44703. So off by one device unit. It's a bug, but we'll have to
1337*4882a593Smuzhiyun * live with it because with all this scaling, we just cannot win.
1338*4882a593Smuzhiyun *
1339*4882a593Smuzhiyun * @return the number of events written into events.
1340*4882a593Smuzhiyun */
1341*4882a593Smuzhiyun static int
fill_pointer_events(InternalEvent * events,DeviceIntPtr pDev,int type,int buttons,CARD32 ms,int flags,const ValuatorMask * mask_in)1342*4882a593Smuzhiyun fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type,
1343*4882a593Smuzhiyun int buttons, CARD32 ms, int flags,
1344*4882a593Smuzhiyun const ValuatorMask *mask_in)
1345*4882a593Smuzhiyun {
1346*4882a593Smuzhiyun int num_events = 1;
1347*4882a593Smuzhiyun DeviceEvent *event;
1348*4882a593Smuzhiyun RawDeviceEvent *raw = NULL;
1349*4882a593Smuzhiyun double screenx = 0.0, screeny = 0.0; /* desktop coordinate system */
1350*4882a593Smuzhiyun double devx = 0.0, devy = 0.0; /* desktop-wide in device coords */
1351*4882a593Smuzhiyun int sx = 0, sy = 0; /* for POINTER_SCREEN */
1352*4882a593Smuzhiyun ValuatorMask mask;
1353*4882a593Smuzhiyun ScreenPtr scr;
1354*4882a593Smuzhiyun int num_barrier_events = 0;
1355*4882a593Smuzhiyun
1356*4882a593Smuzhiyun switch (type) {
1357*4882a593Smuzhiyun case MotionNotify:
1358*4882a593Smuzhiyun if (!pDev->valuator) {
1359*4882a593Smuzhiyun ErrorF("[dix] motion events from device %d without valuators\n",
1360*4882a593Smuzhiyun pDev->id);
1361*4882a593Smuzhiyun return 0;
1362*4882a593Smuzhiyun }
1363*4882a593Smuzhiyun if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0)
1364*4882a593Smuzhiyun return 0;
1365*4882a593Smuzhiyun break;
1366*4882a593Smuzhiyun case ButtonPress:
1367*4882a593Smuzhiyun case ButtonRelease:
1368*4882a593Smuzhiyun if (!pDev->button || !buttons)
1369*4882a593Smuzhiyun return 0;
1370*4882a593Smuzhiyun if (mask_in && valuator_mask_size(mask_in) > 0 && !pDev->valuator) {
1371*4882a593Smuzhiyun ErrorF
1372*4882a593Smuzhiyun ("[dix] button event with valuator from device %d without valuators\n",
1373*4882a593Smuzhiyun pDev->id);
1374*4882a593Smuzhiyun return 0;
1375*4882a593Smuzhiyun }
1376*4882a593Smuzhiyun break;
1377*4882a593Smuzhiyun default:
1378*4882a593Smuzhiyun return 0;
1379*4882a593Smuzhiyun }
1380*4882a593Smuzhiyun
1381*4882a593Smuzhiyun valuator_mask_copy(&mask, mask_in);
1382*4882a593Smuzhiyun
1383*4882a593Smuzhiyun if ((flags & POINTER_NORAW) == 0) {
1384*4882a593Smuzhiyun raw = &events->raw_event;
1385*4882a593Smuzhiyun events++;
1386*4882a593Smuzhiyun num_events++;
1387*4882a593Smuzhiyun
1388*4882a593Smuzhiyun init_raw(pDev, raw, ms, type, buttons);
1389*4882a593Smuzhiyun set_raw_valuators(raw, &mask, TRUE, raw->valuators.data_raw);
1390*4882a593Smuzhiyun }
1391*4882a593Smuzhiyun
1392*4882a593Smuzhiyun valuator_mask_drop_unaccelerated(&mask);
1393*4882a593Smuzhiyun
1394*4882a593Smuzhiyun /* valuators are in driver-native format (rel or abs) */
1395*4882a593Smuzhiyun
1396*4882a593Smuzhiyun if (flags & POINTER_ABSOLUTE) {
1397*4882a593Smuzhiyun if (flags & (POINTER_SCREEN | POINTER_DESKTOP)) { /* valuators are in screen/desktop coords */
1398*4882a593Smuzhiyun sx = valuator_mask_get(&mask, 0);
1399*4882a593Smuzhiyun sy = valuator_mask_get(&mask, 1);
1400*4882a593Smuzhiyun scale_from_screen(pDev, &mask, flags);
1401*4882a593Smuzhiyun }
1402*4882a593Smuzhiyun
1403*4882a593Smuzhiyun transformAbsolute(pDev, &mask);
1404*4882a593Smuzhiyun clipAbsolute(pDev, &mask);
1405*4882a593Smuzhiyun if ((flags & POINTER_NORAW) == 0 && raw)
1406*4882a593Smuzhiyun set_raw_valuators(raw, &mask, FALSE, raw->valuators.data);
1407*4882a593Smuzhiyun }
1408*4882a593Smuzhiyun else {
1409*4882a593Smuzhiyun transformRelative(pDev, &mask);
1410*4882a593Smuzhiyun
1411*4882a593Smuzhiyun if (flags & POINTER_ACCELERATE)
1412*4882a593Smuzhiyun accelPointer(pDev, &mask, ms);
1413*4882a593Smuzhiyun if ((flags & POINTER_NORAW) == 0 && raw)
1414*4882a593Smuzhiyun set_raw_valuators(raw, &mask, FALSE, raw->valuators.data);
1415*4882a593Smuzhiyun
1416*4882a593Smuzhiyun moveRelative(pDev, flags, &mask);
1417*4882a593Smuzhiyun }
1418*4882a593Smuzhiyun
1419*4882a593Smuzhiyun /* valuators are in device coordinate system in absolute coordinates */
1420*4882a593Smuzhiyun scale_to_desktop(pDev, &mask, &devx, &devy, &screenx, &screeny);
1421*4882a593Smuzhiyun
1422*4882a593Smuzhiyun /* #53037 XWarpPointer's scaling back and forth between screen and
1423*4882a593Smuzhiyun device may leave us with rounding errors. End result is that the
1424*4882a593Smuzhiyun pointer doesn't end up on the pixel it should.
1425*4882a593Smuzhiyun Avoid this by forcing screenx/screeny back to what the input
1426*4882a593Smuzhiyun coordinates were.
1427*4882a593Smuzhiyun */
1428*4882a593Smuzhiyun if (flags & POINTER_SCREEN) {
1429*4882a593Smuzhiyun scr = miPointerGetScreen(pDev);
1430*4882a593Smuzhiyun screenx = sx + scr->x;
1431*4882a593Smuzhiyun screeny = sy + scr->y;
1432*4882a593Smuzhiyun }
1433*4882a593Smuzhiyun
1434*4882a593Smuzhiyun scr = positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative,
1435*4882a593Smuzhiyun &mask, &devx, &devy, &screenx, &screeny,
1436*4882a593Smuzhiyun &num_barrier_events, events);
1437*4882a593Smuzhiyun num_events += num_barrier_events;
1438*4882a593Smuzhiyun events += num_barrier_events;
1439*4882a593Smuzhiyun
1440*4882a593Smuzhiyun /* screenx, screeny are in desktop coordinates,
1441*4882a593Smuzhiyun mask is in device coordinates per-screen (the event data)
1442*4882a593Smuzhiyun devx/devy is in device coordinate desktop-wide */
1443*4882a593Smuzhiyun updateHistory(pDev, &mask, ms);
1444*4882a593Smuzhiyun
1445*4882a593Smuzhiyun clipValuators(pDev, &mask);
1446*4882a593Smuzhiyun
1447*4882a593Smuzhiyun storeLastValuators(pDev, &mask, 0, 1, devx, devy);
1448*4882a593Smuzhiyun
1449*4882a593Smuzhiyun /* Update the MD's co-ordinates, which are always in desktop space. */
1450*4882a593Smuzhiyun if (!IsMaster(pDev) && !IsFloating(pDev)) {
1451*4882a593Smuzhiyun DeviceIntPtr master = GetMaster(pDev, MASTER_POINTER);
1452*4882a593Smuzhiyun
1453*4882a593Smuzhiyun master->last.valuators[0] = screenx;
1454*4882a593Smuzhiyun master->last.valuators[1] = screeny;
1455*4882a593Smuzhiyun }
1456*4882a593Smuzhiyun
1457*4882a593Smuzhiyun event = &events->device_event;
1458*4882a593Smuzhiyun init_device_event(event, pDev, ms, EVENT_SOURCE_NORMAL);
1459*4882a593Smuzhiyun
1460*4882a593Smuzhiyun if (type == MotionNotify) {
1461*4882a593Smuzhiyun event->type = ET_Motion;
1462*4882a593Smuzhiyun event->detail.button = 0;
1463*4882a593Smuzhiyun }
1464*4882a593Smuzhiyun else {
1465*4882a593Smuzhiyun if (type == ButtonPress) {
1466*4882a593Smuzhiyun event->type = ET_ButtonPress;
1467*4882a593Smuzhiyun set_button_down(pDev, buttons, BUTTON_POSTED);
1468*4882a593Smuzhiyun }
1469*4882a593Smuzhiyun else if (type == ButtonRelease) {
1470*4882a593Smuzhiyun event->type = ET_ButtonRelease;
1471*4882a593Smuzhiyun set_button_up(pDev, buttons, BUTTON_POSTED);
1472*4882a593Smuzhiyun }
1473*4882a593Smuzhiyun event->detail.button = buttons;
1474*4882a593Smuzhiyun }
1475*4882a593Smuzhiyun
1476*4882a593Smuzhiyun /* root_x and root_y must be in per-screen co-ordinates */
1477*4882a593Smuzhiyun event_set_root_coordinates(event, screenx - scr->x, screeny - scr->y);
1478*4882a593Smuzhiyun
1479*4882a593Smuzhiyun if (flags & POINTER_EMULATED) {
1480*4882a593Smuzhiyun if (raw)
1481*4882a593Smuzhiyun raw->flags = XIPointerEmulated;
1482*4882a593Smuzhiyun event->flags = XIPointerEmulated;
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun
1485*4882a593Smuzhiyun set_valuators(pDev, event, &mask);
1486*4882a593Smuzhiyun
1487*4882a593Smuzhiyun return num_events;
1488*4882a593Smuzhiyun }
1489*4882a593Smuzhiyun
1490*4882a593Smuzhiyun /**
1491*4882a593Smuzhiyun * Generate events for each scroll axis that changed between before/after
1492*4882a593Smuzhiyun * for the device.
1493*4882a593Smuzhiyun *
1494*4882a593Smuzhiyun * @param events The pointer to the event list to fill the events
1495*4882a593Smuzhiyun * @param dev The device to generate the events for
1496*4882a593Smuzhiyun * @param type The real type of the event
1497*4882a593Smuzhiyun * @param axis The axis number to generate events for
1498*4882a593Smuzhiyun * @param mask State before this event in absolute coords
1499*4882a593Smuzhiyun * @param[in,out] last Last scroll state posted in absolute coords (modified
1500*4882a593Smuzhiyun * in-place)
1501*4882a593Smuzhiyun * @param ms Current time in ms
1502*4882a593Smuzhiyun * @param max_events Max number of events to be generated
1503*4882a593Smuzhiyun * @return The number of events generated
1504*4882a593Smuzhiyun */
1505*4882a593Smuzhiyun static int
emulate_scroll_button_events(InternalEvent * events,DeviceIntPtr dev,int type,int axis,const ValuatorMask * mask,ValuatorMask * last,CARD32 ms,int max_events)1506*4882a593Smuzhiyun emulate_scroll_button_events(InternalEvent *events,
1507*4882a593Smuzhiyun DeviceIntPtr dev,
1508*4882a593Smuzhiyun int type,
1509*4882a593Smuzhiyun int axis,
1510*4882a593Smuzhiyun const ValuatorMask *mask,
1511*4882a593Smuzhiyun ValuatorMask *last, CARD32 ms, int max_events)
1512*4882a593Smuzhiyun {
1513*4882a593Smuzhiyun AxisInfoPtr ax;
1514*4882a593Smuzhiyun double delta;
1515*4882a593Smuzhiyun double incr;
1516*4882a593Smuzhiyun int num_events = 0;
1517*4882a593Smuzhiyun double total;
1518*4882a593Smuzhiyun int b;
1519*4882a593Smuzhiyun int flags = 0;
1520*4882a593Smuzhiyun
1521*4882a593Smuzhiyun if (dev->valuator->axes[axis].scroll.type == SCROLL_TYPE_NONE)
1522*4882a593Smuzhiyun return 0;
1523*4882a593Smuzhiyun
1524*4882a593Smuzhiyun if (!valuator_mask_isset(mask, axis))
1525*4882a593Smuzhiyun return 0;
1526*4882a593Smuzhiyun
1527*4882a593Smuzhiyun ax = &dev->valuator->axes[axis];
1528*4882a593Smuzhiyun incr = ax->scroll.increment;
1529*4882a593Smuzhiyun
1530*4882a593Smuzhiyun BUG_WARN_MSG(incr == 0, "for device %s\n", dev->name);
1531*4882a593Smuzhiyun if (incr == 0)
1532*4882a593Smuzhiyun return 0;
1533*4882a593Smuzhiyun
1534*4882a593Smuzhiyun if (type != ButtonPress && type != ButtonRelease)
1535*4882a593Smuzhiyun flags |= POINTER_EMULATED;
1536*4882a593Smuzhiyun
1537*4882a593Smuzhiyun if (!valuator_mask_isset(last, axis))
1538*4882a593Smuzhiyun valuator_mask_set_double(last, axis, 0);
1539*4882a593Smuzhiyun
1540*4882a593Smuzhiyun delta =
1541*4882a593Smuzhiyun valuator_mask_get_double(mask, axis) - valuator_mask_get_double(last,
1542*4882a593Smuzhiyun axis);
1543*4882a593Smuzhiyun total = delta;
1544*4882a593Smuzhiyun b = (ax->scroll.type == SCROLL_TYPE_VERTICAL) ? 5 : 7;
1545*4882a593Smuzhiyun
1546*4882a593Smuzhiyun if ((incr > 0 && delta < 0) || (incr < 0 && delta > 0))
1547*4882a593Smuzhiyun b--; /* we're scrolling up or left → button 4 or 6 */
1548*4882a593Smuzhiyun
1549*4882a593Smuzhiyun while (fabs(delta) >= fabs(incr)) {
1550*4882a593Smuzhiyun int nev_tmp;
1551*4882a593Smuzhiyun
1552*4882a593Smuzhiyun if (delta > 0)
1553*4882a593Smuzhiyun delta -= fabs(incr);
1554*4882a593Smuzhiyun else if (delta < 0)
1555*4882a593Smuzhiyun delta += fabs(incr);
1556*4882a593Smuzhiyun
1557*4882a593Smuzhiyun /* fill_pointer_events() generates four events: one normal and one raw
1558*4882a593Smuzhiyun * event for button press and button release.
1559*4882a593Smuzhiyun * We may get a bigger scroll delta than we can generate events
1560*4882a593Smuzhiyun * for. In that case, we keep decreasing delta, but skip events.
1561*4882a593Smuzhiyun */
1562*4882a593Smuzhiyun if (num_events + 4 < max_events) {
1563*4882a593Smuzhiyun if (type != ButtonRelease) {
1564*4882a593Smuzhiyun nev_tmp = fill_pointer_events(events, dev, ButtonPress, b, ms,
1565*4882a593Smuzhiyun flags, NULL);
1566*4882a593Smuzhiyun events += nev_tmp;
1567*4882a593Smuzhiyun num_events += nev_tmp;
1568*4882a593Smuzhiyun }
1569*4882a593Smuzhiyun if (type != ButtonPress) {
1570*4882a593Smuzhiyun nev_tmp = fill_pointer_events(events, dev, ButtonRelease, b, ms,
1571*4882a593Smuzhiyun flags, NULL);
1572*4882a593Smuzhiyun events += nev_tmp;
1573*4882a593Smuzhiyun num_events += nev_tmp;
1574*4882a593Smuzhiyun }
1575*4882a593Smuzhiyun }
1576*4882a593Smuzhiyun }
1577*4882a593Smuzhiyun
1578*4882a593Smuzhiyun /* We emulated, update last.scroll */
1579*4882a593Smuzhiyun if (total != delta) {
1580*4882a593Smuzhiyun total -= delta;
1581*4882a593Smuzhiyun valuator_mask_set_double(last, axis,
1582*4882a593Smuzhiyun valuator_mask_get_double(last, axis) + total);
1583*4882a593Smuzhiyun }
1584*4882a593Smuzhiyun
1585*4882a593Smuzhiyun return num_events;
1586*4882a593Smuzhiyun }
1587*4882a593Smuzhiyun
1588*4882a593Smuzhiyun
1589*4882a593Smuzhiyun /**
1590*4882a593Smuzhiyun * Generate a complete series of InternalEvents (filled into the EventList)
1591*4882a593Smuzhiyun * representing pointer motion, or button presses. If the device is a slave
1592*4882a593Smuzhiyun * device, also potentially generate a DeviceClassesChangedEvent to update
1593*4882a593Smuzhiyun * the master device.
1594*4882a593Smuzhiyun *
1595*4882a593Smuzhiyun * events is not NULL-terminated; the return value is the number of events.
1596*4882a593Smuzhiyun * The DDX is responsible for allocating the event structure in the first
1597*4882a593Smuzhiyun * place via InitEventList() and GetMaximumEventsNum(), and for freeing it.
1598*4882a593Smuzhiyun *
1599*4882a593Smuzhiyun * In the generated events rootX/Y will be in absolute screen coords and
1600*4882a593Smuzhiyun * the valuator information in the absolute or relative device coords.
1601*4882a593Smuzhiyun *
1602*4882a593Smuzhiyun * last.valuators[x] of the device is always in absolute device coords.
1603*4882a593Smuzhiyun * last.valuators[x] of the master device is in absolute screen coords.
1604*4882a593Smuzhiyun *
1605*4882a593Smuzhiyun * master->last.valuators[x] for x > 2 is undefined.
1606*4882a593Smuzhiyun */
1607*4882a593Smuzhiyun int
GetPointerEvents(InternalEvent * events,DeviceIntPtr pDev,int type,int buttons,int flags,const ValuatorMask * mask_in)1608*4882a593Smuzhiyun GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
1609*4882a593Smuzhiyun int buttons, int flags, const ValuatorMask *mask_in)
1610*4882a593Smuzhiyun {
1611*4882a593Smuzhiyun CARD32 ms = GetTimeInMillis();
1612*4882a593Smuzhiyun int num_events = 0, nev_tmp;
1613*4882a593Smuzhiyun ValuatorMask mask;
1614*4882a593Smuzhiyun ValuatorMask scroll;
1615*4882a593Smuzhiyun int i;
1616*4882a593Smuzhiyun int realtype = type;
1617*4882a593Smuzhiyun
1618*4882a593Smuzhiyun #if XSERVER_DTRACE
1619*4882a593Smuzhiyun if (XSERVER_INPUT_EVENT_ENABLED()) {
1620*4882a593Smuzhiyun XSERVER_INPUT_EVENT(pDev->id, type, buttons, flags,
1621*4882a593Smuzhiyun mask_in ? mask_in->last_bit + 1 : 0,
1622*4882a593Smuzhiyun mask_in ? mask_in->mask : NULL,
1623*4882a593Smuzhiyun mask_in ? mask_in->valuators : NULL);
1624*4882a593Smuzhiyun }
1625*4882a593Smuzhiyun #endif
1626*4882a593Smuzhiyun
1627*4882a593Smuzhiyun BUG_RETURN_VAL(buttons >= MAX_BUTTONS, 0);
1628*4882a593Smuzhiyun
1629*4882a593Smuzhiyun /* refuse events from disabled devices */
1630*4882a593Smuzhiyun if (!pDev->enabled)
1631*4882a593Smuzhiyun return 0;
1632*4882a593Smuzhiyun
1633*4882a593Smuzhiyun if (!miPointerGetScreen(pDev))
1634*4882a593Smuzhiyun return 0;
1635*4882a593Smuzhiyun
1636*4882a593Smuzhiyun events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT,
1637*4882a593Smuzhiyun &num_events);
1638*4882a593Smuzhiyun
1639*4882a593Smuzhiyun valuator_mask_copy(&mask, mask_in);
1640*4882a593Smuzhiyun
1641*4882a593Smuzhiyun /* Turn a scroll button press into a smooth-scrolling event if
1642*4882a593Smuzhiyun * necessary. This only needs to cater for the XIScrollFlagPreferred
1643*4882a593Smuzhiyun * axis (if more than one scrolling axis is present) */
1644*4882a593Smuzhiyun if (type == ButtonPress) {
1645*4882a593Smuzhiyun double adj;
1646*4882a593Smuzhiyun int axis;
1647*4882a593Smuzhiyun int h_scroll_axis = -1;
1648*4882a593Smuzhiyun int v_scroll_axis = -1;
1649*4882a593Smuzhiyun
1650*4882a593Smuzhiyun if (pDev->valuator) {
1651*4882a593Smuzhiyun h_scroll_axis = pDev->valuator->h_scroll_axis;
1652*4882a593Smuzhiyun v_scroll_axis = pDev->valuator->v_scroll_axis;
1653*4882a593Smuzhiyun }
1654*4882a593Smuzhiyun
1655*4882a593Smuzhiyun /* Up is negative on valuators, down positive */
1656*4882a593Smuzhiyun switch (buttons) {
1657*4882a593Smuzhiyun case 4:
1658*4882a593Smuzhiyun adj = -1.0;
1659*4882a593Smuzhiyun axis = v_scroll_axis;
1660*4882a593Smuzhiyun break;
1661*4882a593Smuzhiyun case 5:
1662*4882a593Smuzhiyun adj = 1.0;
1663*4882a593Smuzhiyun axis = v_scroll_axis;
1664*4882a593Smuzhiyun break;
1665*4882a593Smuzhiyun case 6:
1666*4882a593Smuzhiyun adj = -1.0;
1667*4882a593Smuzhiyun axis = h_scroll_axis;
1668*4882a593Smuzhiyun break;
1669*4882a593Smuzhiyun case 7:
1670*4882a593Smuzhiyun adj = 1.0;
1671*4882a593Smuzhiyun axis = h_scroll_axis;
1672*4882a593Smuzhiyun break;
1673*4882a593Smuzhiyun default:
1674*4882a593Smuzhiyun adj = 0.0;
1675*4882a593Smuzhiyun axis = -1;
1676*4882a593Smuzhiyun break;
1677*4882a593Smuzhiyun }
1678*4882a593Smuzhiyun
1679*4882a593Smuzhiyun if (adj != 0.0 && axis != -1) {
1680*4882a593Smuzhiyun adj *= pDev->valuator->axes[axis].scroll.increment;
1681*4882a593Smuzhiyun if (!valuator_mask_isset(&mask, axis))
1682*4882a593Smuzhiyun valuator_mask_set(&mask, axis, 0);
1683*4882a593Smuzhiyun add_to_scroll_valuator(pDev, &mask, axis, adj);
1684*4882a593Smuzhiyun type = MotionNotify;
1685*4882a593Smuzhiyun buttons = 0;
1686*4882a593Smuzhiyun flags |= POINTER_EMULATED;
1687*4882a593Smuzhiyun }
1688*4882a593Smuzhiyun }
1689*4882a593Smuzhiyun
1690*4882a593Smuzhiyun /* First fill out the original event set, with smooth-scrolling axes. */
1691*4882a593Smuzhiyun nev_tmp = fill_pointer_events(events, pDev, type, buttons, ms, flags,
1692*4882a593Smuzhiyun &mask);
1693*4882a593Smuzhiyun events += nev_tmp;
1694*4882a593Smuzhiyun num_events += nev_tmp;
1695*4882a593Smuzhiyun
1696*4882a593Smuzhiyun valuator_mask_zero(&scroll);
1697*4882a593Smuzhiyun
1698*4882a593Smuzhiyun /* Now turn the smooth-scrolling axes back into emulated button presses
1699*4882a593Smuzhiyun * for legacy clients, based on the integer delta between before and now */
1700*4882a593Smuzhiyun for (i = 0; i < valuator_mask_size(&mask); i++) {
1701*4882a593Smuzhiyun if ( !pDev->valuator || (i >= pDev->valuator->numAxes))
1702*4882a593Smuzhiyun break;
1703*4882a593Smuzhiyun
1704*4882a593Smuzhiyun if (!valuator_mask_isset(&mask, i))
1705*4882a593Smuzhiyun continue;
1706*4882a593Smuzhiyun
1707*4882a593Smuzhiyun valuator_mask_set_double(&scroll, i, pDev->last.valuators[i]);
1708*4882a593Smuzhiyun
1709*4882a593Smuzhiyun nev_tmp =
1710*4882a593Smuzhiyun emulate_scroll_button_events(events, pDev, realtype, i, &scroll,
1711*4882a593Smuzhiyun pDev->last.scroll, ms,
1712*4882a593Smuzhiyun GetMaximumEventsNum() - num_events);
1713*4882a593Smuzhiyun events += nev_tmp;
1714*4882a593Smuzhiyun num_events += nev_tmp;
1715*4882a593Smuzhiyun }
1716*4882a593Smuzhiyun
1717*4882a593Smuzhiyun return num_events;
1718*4882a593Smuzhiyun }
1719*4882a593Smuzhiyun
1720*4882a593Smuzhiyun /**
1721*4882a593Smuzhiyun * Generate internal events representing this proximity event and enqueue
1722*4882a593Smuzhiyun * them on the event queue.
1723*4882a593Smuzhiyun *
1724*4882a593Smuzhiyun * This function is not reentrant. Disable signals before calling.
1725*4882a593Smuzhiyun *
1726*4882a593Smuzhiyun * @param device The device to generate the event for
1727*4882a593Smuzhiyun * @param type Event type, one of ProximityIn or ProximityOut
1728*4882a593Smuzhiyun * @param keycode Key code of the pressed/released key
1729*4882a593Smuzhiyun * @param mask Valuator mask for valuators present for this event.
1730*4882a593Smuzhiyun *
1731*4882a593Smuzhiyun */
1732*4882a593Smuzhiyun void
QueueProximityEvents(DeviceIntPtr device,int type,const ValuatorMask * mask)1733*4882a593Smuzhiyun QueueProximityEvents(DeviceIntPtr device, int type, const ValuatorMask *mask)
1734*4882a593Smuzhiyun {
1735*4882a593Smuzhiyun int nevents;
1736*4882a593Smuzhiyun
1737*4882a593Smuzhiyun nevents = GetProximityEvents(InputEventList, device, type, mask);
1738*4882a593Smuzhiyun queueEventList(device, InputEventList, nevents);
1739*4882a593Smuzhiyun }
1740*4882a593Smuzhiyun
1741*4882a593Smuzhiyun /**
1742*4882a593Smuzhiyun * Generate ProximityIn/ProximityOut InternalEvents, accompanied by
1743*4882a593Smuzhiyun * valuators.
1744*4882a593Smuzhiyun *
1745*4882a593Smuzhiyun * The DDX is responsible for allocating the events in the first place via
1746*4882a593Smuzhiyun * InitEventList(), and for freeing it.
1747*4882a593Smuzhiyun *
1748*4882a593Smuzhiyun * @return the number of events written into events.
1749*4882a593Smuzhiyun */
1750*4882a593Smuzhiyun int
GetProximityEvents(InternalEvent * events,DeviceIntPtr pDev,int type,const ValuatorMask * mask_in)1751*4882a593Smuzhiyun GetProximityEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
1752*4882a593Smuzhiyun const ValuatorMask *mask_in)
1753*4882a593Smuzhiyun {
1754*4882a593Smuzhiyun int num_events = 1, i;
1755*4882a593Smuzhiyun DeviceEvent *event;
1756*4882a593Smuzhiyun ValuatorMask mask;
1757*4882a593Smuzhiyun
1758*4882a593Smuzhiyun #if XSERVER_DTRACE
1759*4882a593Smuzhiyun if (XSERVER_INPUT_EVENT_ENABLED()) {
1760*4882a593Smuzhiyun XSERVER_INPUT_EVENT(pDev->id, type, 0, 0,
1761*4882a593Smuzhiyun mask_in ? mask_in->last_bit + 1 : 0,
1762*4882a593Smuzhiyun mask_in ? mask_in->mask : NULL,
1763*4882a593Smuzhiyun mask_in ? mask_in->valuators : NULL);
1764*4882a593Smuzhiyun }
1765*4882a593Smuzhiyun #endif
1766*4882a593Smuzhiyun
1767*4882a593Smuzhiyun /* refuse events from disabled devices */
1768*4882a593Smuzhiyun if (!pDev->enabled)
1769*4882a593Smuzhiyun return 0;
1770*4882a593Smuzhiyun
1771*4882a593Smuzhiyun /* Sanity checks. */
1772*4882a593Smuzhiyun if ((type != ProximityIn && type != ProximityOut) || !mask_in)
1773*4882a593Smuzhiyun return 0;
1774*4882a593Smuzhiyun if (!pDev->valuator || !pDev->proximity)
1775*4882a593Smuzhiyun return 0;
1776*4882a593Smuzhiyun
1777*4882a593Smuzhiyun valuator_mask_copy(&mask, mask_in);
1778*4882a593Smuzhiyun
1779*4882a593Smuzhiyun /* ignore relative axes for proximity. */
1780*4882a593Smuzhiyun for (i = 0; i < valuator_mask_size(&mask); i++) {
1781*4882a593Smuzhiyun if (valuator_mask_isset(&mask, i) &&
1782*4882a593Smuzhiyun valuator_get_mode(pDev, i) == Relative)
1783*4882a593Smuzhiyun valuator_mask_unset(&mask, i);
1784*4882a593Smuzhiyun }
1785*4882a593Smuzhiyun
1786*4882a593Smuzhiyun /* FIXME: posting proximity events with relative valuators only results
1787*4882a593Smuzhiyun * in an empty event, EventToXI() will fail to convert → no event sent
1788*4882a593Smuzhiyun * to client. */
1789*4882a593Smuzhiyun
1790*4882a593Smuzhiyun events =
1791*4882a593Smuzhiyun UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events);
1792*4882a593Smuzhiyun
1793*4882a593Smuzhiyun event = &events->device_event;
1794*4882a593Smuzhiyun init_device_event(event, pDev, GetTimeInMillis(), EVENT_SOURCE_NORMAL);
1795*4882a593Smuzhiyun event->type = (type == ProximityIn) ? ET_ProximityIn : ET_ProximityOut;
1796*4882a593Smuzhiyun
1797*4882a593Smuzhiyun clipValuators(pDev, &mask);
1798*4882a593Smuzhiyun
1799*4882a593Smuzhiyun set_valuators(pDev, event, &mask);
1800*4882a593Smuzhiyun
1801*4882a593Smuzhiyun return num_events;
1802*4882a593Smuzhiyun }
1803*4882a593Smuzhiyun
1804*4882a593Smuzhiyun int
GetTouchOwnershipEvents(InternalEvent * events,DeviceIntPtr pDev,TouchPointInfoPtr ti,uint8_t reason,XID resource,uint32_t flags)1805*4882a593Smuzhiyun GetTouchOwnershipEvents(InternalEvent *events, DeviceIntPtr pDev,
1806*4882a593Smuzhiyun TouchPointInfoPtr ti, uint8_t reason, XID resource,
1807*4882a593Smuzhiyun uint32_t flags)
1808*4882a593Smuzhiyun {
1809*4882a593Smuzhiyun TouchClassPtr t = pDev->touch;
1810*4882a593Smuzhiyun TouchOwnershipEvent *event;
1811*4882a593Smuzhiyun CARD32 ms = GetTimeInMillis();
1812*4882a593Smuzhiyun
1813*4882a593Smuzhiyun if (!pDev->enabled || !t || !ti)
1814*4882a593Smuzhiyun return 0;
1815*4882a593Smuzhiyun
1816*4882a593Smuzhiyun event = &events->touch_ownership_event;
1817*4882a593Smuzhiyun init_touch_ownership(pDev, event, ms);
1818*4882a593Smuzhiyun
1819*4882a593Smuzhiyun event->touchid = ti->client_id;
1820*4882a593Smuzhiyun event->sourceid = ti->sourceid;
1821*4882a593Smuzhiyun event->resource = resource;
1822*4882a593Smuzhiyun event->flags = flags;
1823*4882a593Smuzhiyun event->reason = reason;
1824*4882a593Smuzhiyun
1825*4882a593Smuzhiyun return 1;
1826*4882a593Smuzhiyun }
1827*4882a593Smuzhiyun
1828*4882a593Smuzhiyun /**
1829*4882a593Smuzhiyun * Generate internal events representing this touch event and enqueue them
1830*4882a593Smuzhiyun * on the event queue.
1831*4882a593Smuzhiyun *
1832*4882a593Smuzhiyun * This function is not reentrant. Disable signals before calling.
1833*4882a593Smuzhiyun *
1834*4882a593Smuzhiyun * @param device The device to generate the event for
1835*4882a593Smuzhiyun * @param type Event type, one of XI_TouchBegin, XI_TouchUpdate, XI_TouchEnd
1836*4882a593Smuzhiyun * @param touchid Touch point ID
1837*4882a593Smuzhiyun * @param flags Event modification flags
1838*4882a593Smuzhiyun * @param mask Valuator mask for valuators present for this event.
1839*4882a593Smuzhiyun */
1840*4882a593Smuzhiyun void
QueueTouchEvents(DeviceIntPtr device,int type,uint32_t ddx_touchid,int flags,const ValuatorMask * mask)1841*4882a593Smuzhiyun QueueTouchEvents(DeviceIntPtr device, int type,
1842*4882a593Smuzhiyun uint32_t ddx_touchid, int flags, const ValuatorMask *mask)
1843*4882a593Smuzhiyun {
1844*4882a593Smuzhiyun int nevents;
1845*4882a593Smuzhiyun
1846*4882a593Smuzhiyun nevents =
1847*4882a593Smuzhiyun GetTouchEvents(InputEventList, device, ddx_touchid, type, flags, mask);
1848*4882a593Smuzhiyun queueEventList(device, InputEventList, nevents);
1849*4882a593Smuzhiyun }
1850*4882a593Smuzhiyun
1851*4882a593Smuzhiyun /**
1852*4882a593Smuzhiyun * Get events for a touch. Generates a TouchBegin event if end is not set and
1853*4882a593Smuzhiyun * the touch id is not active. Generates a TouchUpdate event if end is not set
1854*4882a593Smuzhiyun * and the touch id is active. Generates a TouchEnd event if end is set and the
1855*4882a593Smuzhiyun * touch id is active.
1856*4882a593Smuzhiyun *
1857*4882a593Smuzhiyun * events is not NULL-terminated; the return value is the number of events.
1858*4882a593Smuzhiyun * The DDX is responsible for allocating the event structure in the first
1859*4882a593Smuzhiyun * place via GetMaximumEventsNum(), and for freeing it.
1860*4882a593Smuzhiyun *
1861*4882a593Smuzhiyun * @param[out] events The list of events generated
1862*4882a593Smuzhiyun * @param dev The device to generate the events for
1863*4882a593Smuzhiyun * @param ddx_touchid The touch ID as assigned by the DDX
1864*4882a593Smuzhiyun * @param type XI_TouchBegin, XI_TouchUpdate or XI_TouchEnd
1865*4882a593Smuzhiyun * @param flags Event flags
1866*4882a593Smuzhiyun * @param mask_in Valuator information for this event
1867*4882a593Smuzhiyun */
1868*4882a593Smuzhiyun int
GetTouchEvents(InternalEvent * events,DeviceIntPtr dev,uint32_t ddx_touchid,uint16_t type,uint32_t flags,const ValuatorMask * mask_in)1869*4882a593Smuzhiyun GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
1870*4882a593Smuzhiyun uint16_t type, uint32_t flags, const ValuatorMask *mask_in)
1871*4882a593Smuzhiyun {
1872*4882a593Smuzhiyun ScreenPtr scr = dev->spriteInfo->sprite->hotPhys.pScreen;
1873*4882a593Smuzhiyun TouchClassPtr t = dev->touch;
1874*4882a593Smuzhiyun ValuatorClassPtr v = dev->valuator;
1875*4882a593Smuzhiyun DeviceEvent *event;
1876*4882a593Smuzhiyun CARD32 ms = GetTimeInMillis();
1877*4882a593Smuzhiyun ValuatorMask mask;
1878*4882a593Smuzhiyun double screenx = 0.0, screeny = 0.0; /* desktop coordinate system */
1879*4882a593Smuzhiyun double devx = 0.0, devy = 0.0; /* desktop-wide in device coords */
1880*4882a593Smuzhiyun int i;
1881*4882a593Smuzhiyun int num_events = 0;
1882*4882a593Smuzhiyun RawDeviceEvent *raw;
1883*4882a593Smuzhiyun DDXTouchPointInfoPtr ti;
1884*4882a593Smuzhiyun int need_rawevent = TRUE;
1885*4882a593Smuzhiyun Bool emulate_pointer = FALSE;
1886*4882a593Smuzhiyun int client_id = 0;
1887*4882a593Smuzhiyun
1888*4882a593Smuzhiyun #if XSERVER_DTRACE
1889*4882a593Smuzhiyun if (XSERVER_INPUT_EVENT_ENABLED()) {
1890*4882a593Smuzhiyun XSERVER_INPUT_EVENT(dev->id, type, ddx_touchid, flags,
1891*4882a593Smuzhiyun mask_in ? mask_in->last_bit + 1 : 0,
1892*4882a593Smuzhiyun mask_in ? mask_in->mask : NULL,
1893*4882a593Smuzhiyun mask_in ? mask_in->valuators : NULL);
1894*4882a593Smuzhiyun }
1895*4882a593Smuzhiyun #endif
1896*4882a593Smuzhiyun
1897*4882a593Smuzhiyun if (!dev->enabled || !t || !v)
1898*4882a593Smuzhiyun return 0;
1899*4882a593Smuzhiyun
1900*4882a593Smuzhiyun /* Find and/or create the DDX touch info */
1901*4882a593Smuzhiyun
1902*4882a593Smuzhiyun ti = TouchFindByDDXID(dev, ddx_touchid, (type == XI_TouchBegin));
1903*4882a593Smuzhiyun if (!ti) {
1904*4882a593Smuzhiyun ErrorFSigSafe("[dix] %s: unable to %s touch point %u\n", dev->name,
1905*4882a593Smuzhiyun type == XI_TouchBegin ? "begin" : "find", ddx_touchid);
1906*4882a593Smuzhiyun return 0;
1907*4882a593Smuzhiyun }
1908*4882a593Smuzhiyun client_id = ti->client_id;
1909*4882a593Smuzhiyun
1910*4882a593Smuzhiyun emulate_pointer = ti->emulate_pointer;
1911*4882a593Smuzhiyun
1912*4882a593Smuzhiyun if (!IsMaster(dev))
1913*4882a593Smuzhiyun events =
1914*4882a593Smuzhiyun UpdateFromMaster(events, dev, DEVCHANGE_POINTER_EVENT, &num_events);
1915*4882a593Smuzhiyun
1916*4882a593Smuzhiyun valuator_mask_copy(&mask, mask_in);
1917*4882a593Smuzhiyun
1918*4882a593Smuzhiyun if (need_rawevent) {
1919*4882a593Smuzhiyun raw = &events->raw_event;
1920*4882a593Smuzhiyun events++;
1921*4882a593Smuzhiyun num_events++;
1922*4882a593Smuzhiyun init_raw(dev, raw, ms, type, client_id);
1923*4882a593Smuzhiyun set_raw_valuators(raw, &mask, TRUE, raw->valuators.data_raw);
1924*4882a593Smuzhiyun }
1925*4882a593Smuzhiyun
1926*4882a593Smuzhiyun event = &events->device_event;
1927*4882a593Smuzhiyun num_events++;
1928*4882a593Smuzhiyun
1929*4882a593Smuzhiyun init_device_event(event, dev, ms, EVENT_SOURCE_NORMAL);
1930*4882a593Smuzhiyun
1931*4882a593Smuzhiyun switch (type) {
1932*4882a593Smuzhiyun case XI_TouchBegin:
1933*4882a593Smuzhiyun event->type = ET_TouchBegin;
1934*4882a593Smuzhiyun /* If we're starting a touch, we must have x & y co-ordinates. */
1935*4882a593Smuzhiyun if (!mask_in ||
1936*4882a593Smuzhiyun !valuator_mask_isset(mask_in, 0) ||
1937*4882a593Smuzhiyun !valuator_mask_isset(mask_in, 1)) {
1938*4882a593Smuzhiyun ErrorFSigSafe("%s: Attempted to start touch without x/y "
1939*4882a593Smuzhiyun "(driver bug)\n", dev->name);
1940*4882a593Smuzhiyun return 0;
1941*4882a593Smuzhiyun }
1942*4882a593Smuzhiyun break;
1943*4882a593Smuzhiyun case XI_TouchUpdate:
1944*4882a593Smuzhiyun event->type = ET_TouchUpdate;
1945*4882a593Smuzhiyun if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0) {
1946*4882a593Smuzhiyun ErrorFSigSafe("%s: TouchUpdate with no valuators? Driver bug\n",
1947*4882a593Smuzhiyun dev->name);
1948*4882a593Smuzhiyun }
1949*4882a593Smuzhiyun break;
1950*4882a593Smuzhiyun case XI_TouchEnd:
1951*4882a593Smuzhiyun event->type = ET_TouchEnd;
1952*4882a593Smuzhiyun /* We can end the DDX touch here, since we don't use the active
1953*4882a593Smuzhiyun * field below */
1954*4882a593Smuzhiyun TouchEndDDXTouch(dev, ti);
1955*4882a593Smuzhiyun break;
1956*4882a593Smuzhiyun default:
1957*4882a593Smuzhiyun return 0;
1958*4882a593Smuzhiyun }
1959*4882a593Smuzhiyun
1960*4882a593Smuzhiyun /* Get our screen event co-ordinates (root_x/root_y/event_x/event_y):
1961*4882a593Smuzhiyun * these come from the touchpoint in Absolute mode, or the sprite in
1962*4882a593Smuzhiyun * Relative. */
1963*4882a593Smuzhiyun if (t->mode == XIDirectTouch) {
1964*4882a593Smuzhiyun for (i = 0; i < max(valuator_mask_size(&mask), 2); i++) {
1965*4882a593Smuzhiyun double val;
1966*4882a593Smuzhiyun
1967*4882a593Smuzhiyun if (valuator_mask_fetch_double(&mask, i, &val))
1968*4882a593Smuzhiyun valuator_mask_set_double(ti->valuators, i, val);
1969*4882a593Smuzhiyun /* If the device doesn't post new X and Y axis values,
1970*4882a593Smuzhiyun * use the last values posted.
1971*4882a593Smuzhiyun */
1972*4882a593Smuzhiyun else if (i < 2 &&
1973*4882a593Smuzhiyun valuator_mask_fetch_double(ti->valuators, i, &val))
1974*4882a593Smuzhiyun valuator_mask_set_double(&mask, i, val);
1975*4882a593Smuzhiyun }
1976*4882a593Smuzhiyun
1977*4882a593Smuzhiyun transformAbsolute(dev, &mask);
1978*4882a593Smuzhiyun clipAbsolute(dev, &mask);
1979*4882a593Smuzhiyun }
1980*4882a593Smuzhiyun else {
1981*4882a593Smuzhiyun screenx = dev->spriteInfo->sprite->hotPhys.x;
1982*4882a593Smuzhiyun screeny = dev->spriteInfo->sprite->hotPhys.y;
1983*4882a593Smuzhiyun }
1984*4882a593Smuzhiyun if (need_rawevent)
1985*4882a593Smuzhiyun set_raw_valuators(raw, &mask, FALSE, raw->valuators.data);
1986*4882a593Smuzhiyun
1987*4882a593Smuzhiyun /* Indirect device touch coordinates are not used for cursor positioning.
1988*4882a593Smuzhiyun * They are merely informational, and are provided in device coordinates.
1989*4882a593Smuzhiyun * The device sprite is used for positioning instead, and it is already
1990*4882a593Smuzhiyun * scaled. */
1991*4882a593Smuzhiyun if (t->mode == XIDirectTouch)
1992*4882a593Smuzhiyun scr = scale_to_desktop(dev, &mask, &devx, &devy, &screenx, &screeny);
1993*4882a593Smuzhiyun if (emulate_pointer)
1994*4882a593Smuzhiyun scr = positionSprite(dev, Absolute, &mask,
1995*4882a593Smuzhiyun &devx, &devy, &screenx, &screeny, NULL, NULL);
1996*4882a593Smuzhiyun
1997*4882a593Smuzhiyun /* see fill_pointer_events for coordinate systems */
1998*4882a593Smuzhiyun if (emulate_pointer)
1999*4882a593Smuzhiyun updateHistory(dev, &mask, ms);
2000*4882a593Smuzhiyun
2001*4882a593Smuzhiyun clipValuators(dev, &mask);
2002*4882a593Smuzhiyun
2003*4882a593Smuzhiyun if (emulate_pointer)
2004*4882a593Smuzhiyun storeLastValuators(dev, &mask, 0, 1, devx, devy);
2005*4882a593Smuzhiyun
2006*4882a593Smuzhiyun /* Update the MD's co-ordinates, which are always in desktop space. */
2007*4882a593Smuzhiyun if (emulate_pointer && !IsMaster(dev) && !IsFloating(dev)) {
2008*4882a593Smuzhiyun DeviceIntPtr master = GetMaster(dev, MASTER_POINTER);
2009*4882a593Smuzhiyun
2010*4882a593Smuzhiyun master->last.valuators[0] = screenx;
2011*4882a593Smuzhiyun master->last.valuators[1] = screeny;
2012*4882a593Smuzhiyun }
2013*4882a593Smuzhiyun
2014*4882a593Smuzhiyun event->root = scr->root->drawable.id;
2015*4882a593Smuzhiyun
2016*4882a593Smuzhiyun event_set_root_coordinates(event, screenx - scr->x, screeny - scr->y);
2017*4882a593Smuzhiyun event->touchid = client_id;
2018*4882a593Smuzhiyun event->flags = flags;
2019*4882a593Smuzhiyun
2020*4882a593Smuzhiyun if (emulate_pointer) {
2021*4882a593Smuzhiyun event->flags |= TOUCH_POINTER_EMULATED;
2022*4882a593Smuzhiyun event->detail.button = 1;
2023*4882a593Smuzhiyun }
2024*4882a593Smuzhiyun
2025*4882a593Smuzhiyun set_valuators(dev, event, &mask);
2026*4882a593Smuzhiyun for (i = 0; i < v->numAxes; i++) {
2027*4882a593Smuzhiyun if (valuator_mask_isset(&mask, i))
2028*4882a593Smuzhiyun v->axisVal[i] = valuator_mask_get(&mask, i);
2029*4882a593Smuzhiyun }
2030*4882a593Smuzhiyun
2031*4882a593Smuzhiyun return num_events;
2032*4882a593Smuzhiyun }
2033*4882a593Smuzhiyun
2034*4882a593Smuzhiyun void
GetDixTouchEnd(InternalEvent * ievent,DeviceIntPtr dev,TouchPointInfoPtr ti,uint32_t flags)2035*4882a593Smuzhiyun GetDixTouchEnd(InternalEvent *ievent, DeviceIntPtr dev, TouchPointInfoPtr ti,
2036*4882a593Smuzhiyun uint32_t flags)
2037*4882a593Smuzhiyun {
2038*4882a593Smuzhiyun ScreenPtr scr = dev->spriteInfo->sprite->hotPhys.pScreen;
2039*4882a593Smuzhiyun DeviceEvent *event = &ievent->device_event;
2040*4882a593Smuzhiyun CARD32 ms = GetTimeInMillis();
2041*4882a593Smuzhiyun
2042*4882a593Smuzhiyun BUG_WARN(!dev->enabled);
2043*4882a593Smuzhiyun
2044*4882a593Smuzhiyun init_device_event(event, dev, ms, EVENT_SOURCE_NORMAL);
2045*4882a593Smuzhiyun
2046*4882a593Smuzhiyun event->sourceid = ti->sourceid;
2047*4882a593Smuzhiyun event->type = ET_TouchEnd;
2048*4882a593Smuzhiyun
2049*4882a593Smuzhiyun event->root = scr->root->drawable.id;
2050*4882a593Smuzhiyun
2051*4882a593Smuzhiyun /* Get screen event coordinates from the sprite. Is this really the best
2052*4882a593Smuzhiyun * we can do? */
2053*4882a593Smuzhiyun event_set_root_coordinates(event,
2054*4882a593Smuzhiyun dev->last.valuators[0] - scr->x,
2055*4882a593Smuzhiyun dev->last.valuators[1] - scr->y);
2056*4882a593Smuzhiyun event->touchid = ti->client_id;
2057*4882a593Smuzhiyun event->flags = flags;
2058*4882a593Smuzhiyun
2059*4882a593Smuzhiyun if (flags & TOUCH_POINTER_EMULATED) {
2060*4882a593Smuzhiyun event->flags |= TOUCH_POINTER_EMULATED;
2061*4882a593Smuzhiyun event->detail.button = 1;
2062*4882a593Smuzhiyun }
2063*4882a593Smuzhiyun }
2064*4882a593Smuzhiyun
2065*4882a593Smuzhiyun /**
2066*4882a593Smuzhiyun * Synthesize a single motion event for the core pointer.
2067*4882a593Smuzhiyun *
2068*4882a593Smuzhiyun * Used in cursor functions, e.g. when cursor confinement changes, and we need
2069*4882a593Smuzhiyun * to shift the pointer to get it inside the new bounds.
2070*4882a593Smuzhiyun */
2071*4882a593Smuzhiyun void
PostSyntheticMotion(DeviceIntPtr pDev,int x,int y,int screen,unsigned long time)2072*4882a593Smuzhiyun PostSyntheticMotion(DeviceIntPtr pDev,
2073*4882a593Smuzhiyun int x, int y, int screen, unsigned long time)
2074*4882a593Smuzhiyun {
2075*4882a593Smuzhiyun DeviceEvent ev;
2076*4882a593Smuzhiyun
2077*4882a593Smuzhiyun #ifdef PANORAMIX
2078*4882a593Smuzhiyun /* Translate back to the sprite screen since processInputProc
2079*4882a593Smuzhiyun will translate from sprite screen to screen 0 upon reentry
2080*4882a593Smuzhiyun to the DIX layer. */
2081*4882a593Smuzhiyun if (!noPanoramiXExtension) {
2082*4882a593Smuzhiyun x += screenInfo.screens[0]->x - screenInfo.screens[screen]->x;
2083*4882a593Smuzhiyun y += screenInfo.screens[0]->y - screenInfo.screens[screen]->y;
2084*4882a593Smuzhiyun }
2085*4882a593Smuzhiyun #endif
2086*4882a593Smuzhiyun
2087*4882a593Smuzhiyun memset(&ev, 0, sizeof(DeviceEvent));
2088*4882a593Smuzhiyun init_device_event(&ev, pDev, time, EVENT_SOURCE_NORMAL);
2089*4882a593Smuzhiyun ev.root_x = x;
2090*4882a593Smuzhiyun ev.root_y = y;
2091*4882a593Smuzhiyun ev.type = ET_Motion;
2092*4882a593Smuzhiyun ev.time = time;
2093*4882a593Smuzhiyun
2094*4882a593Smuzhiyun /* FIXME: MD/SD considerations? */
2095*4882a593Smuzhiyun (*pDev->public.processInputProc) ((InternalEvent *) &ev, pDev);
2096*4882a593Smuzhiyun }
2097