Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / common / xf86Xinput.c
CommitLineData
a09e091a
JB
1/*
2 * Copyright 1995-1999 by Frederic Lepied, France. <Lepied@XFree86.org>
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Frederic Lepied not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Frederic Lepied makes no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
13 *
14 * FREDERIC LEPIED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL FREDERIC LEPIED BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 *
22 */
23/*
24 * Copyright (c) 2000-2002 by The XFree86 Project, Inc.
25 *
26 * Permission is hereby granted, free of charge, to any person obtaining a
27 * copy of this software and associated documentation files (the "Software"),
28 * to deal in the Software without restriction, including without limitation
29 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
30 * and/or sell copies of the Software, and to permit persons to whom the
31 * Software is furnished to do so, subject to the following conditions:
32 *
33 * The above copyright notice and this permission notice shall be included in
34 * all copies or substantial portions of the Software.
35 *
36 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
39 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
40 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
41 * OTHER DEALINGS IN THE SOFTWARE.
42 *
43 * Except as contained in this notice, the name of the copyright holder(s)
44 * and author(s) shall not be used in advertising or otherwise to promote
45 * the sale, use or other dealings in this Software without prior written
46 * authorization from the copyright holder(s) and author(s).
47 */
48
49#ifdef HAVE_XORG_CONFIG_H
50#include <xorg-config.h>
51#endif
52
53#include <X11/Xfuncproto.h>
54#include <X11/Xmd.h>
55#include <X11/extensions/XI.h>
56#include <X11/extensions/XIproto.h>
57#include <X11/Xatom.h>
58#include "xf86.h"
59#include "xf86Priv.h"
60#include "xf86Config.h"
61#include "xf86Xinput.h"
62#include "xf86Optrec.h"
63#include "mipointer.h"
64#include "extinit.h"
65#include "loaderProcs.h"
66
67#include "exevents.h" /* AddInputDevice */
68#include "exglobals.h"
69#include "eventstr.h"
70#include "inpututils.h"
71#include "optionstr.h"
72
73#include <string.h> /* InputClassMatches */
74#ifdef HAVE_FNMATCH_H
75#include <fnmatch.h>
76#endif
77#ifdef HAVE_SYS_UTSNAME_H
78#include <sys/utsname.h>
79#endif
80
81#include <stdarg.h>
82#include <stdint.h> /* for int64_t */
83
84#include "mi.h"
85
86#include <ptrveloc.h> /* dix pointer acceleration */
87#include <xserver-properties.h>
88
89#ifdef XFreeXDGA
90#include "dgaproc.h"
91#endif
92
93#include "xkbsrv.h"
94
95/* Valuator verification macro */
96#define XI_VERIFY_VALUATORS(num_valuators) \
97 if (num_valuators > MAX_VALUATORS) { \
98 xf86Msg(X_ERROR, "%s: num_valuator %d is greater than" \
99 " MAX_VALUATORS\n", __FUNCTION__, num_valuators); \
100 return; \
101 }
102
103static int
104 xf86InputDevicePostInit(DeviceIntPtr dev);
105
106/**
107 * Eval config and modify DeviceVelocityRec accordingly
108 */
109static void
110ProcessVelocityConfiguration(DeviceIntPtr pDev, char *devname, pointer list,
111 DeviceVelocityPtr s)
112{
113 int tempi;
114 float tempf;
115 Atom float_prop = XIGetKnownProperty(XATOM_FLOAT);
116 Atom prop;
117
118 if (!s)
119 return;
120
121 /* common settings (available via device properties) */
122 tempf = xf86SetRealOption(list, "ConstantDeceleration", 1.0);
123 if (tempf > 1.0) {
124 xf86Msg(X_CONFIG, "%s: (accel) constant deceleration by %.1f\n",
125 devname, tempf);
126 prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION);
127 XIChangeDeviceProperty(pDev, prop, float_prop, 32,
128 PropModeReplace, 1, &tempf, FALSE);
129 }
130
131 tempf = xf86SetRealOption(list, "AdaptiveDeceleration", 1.0);
132 if (tempf > 1.0) {
133 xf86Msg(X_CONFIG, "%s: (accel) adaptive deceleration by %.1f\n",
134 devname, tempf);
135 prop = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION);
136 XIChangeDeviceProperty(pDev, prop, float_prop, 32,
137 PropModeReplace, 1, &tempf, FALSE);
138 }
139
140 /* select profile by number */
141 tempi = xf86SetIntOption(list, "AccelerationProfile",
142 s->statistics.profile_number);
143
144 prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER);
145 if (XIChangeDeviceProperty(pDev, prop, XA_INTEGER, 32,
146 PropModeReplace, 1, &tempi, FALSE) == Success) {
147 xf86Msg(X_CONFIG, "%s: (accel) acceleration profile %i\n", devname,
148 tempi);
149 }
150 else {
151 xf86Msg(X_CONFIG, "%s: (accel) acceleration profile %i is unknown\n",
152 devname, tempi);
153 }
154
155 /* set scaling */
156 tempf = xf86SetRealOption(list, "ExpectedRate", 0);
157 prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING);
158 if (tempf > 0) {
159 tempf = 1000.0 / tempf;
160 XIChangeDeviceProperty(pDev, prop, float_prop, 32,
161 PropModeReplace, 1, &tempf, FALSE);
162 }
163 else {
164 tempf = xf86SetRealOption(list, "VelocityScale", s->corr_mul);
165 XIChangeDeviceProperty(pDev, prop, float_prop, 32,
166 PropModeReplace, 1, &tempf, FALSE);
167 }
168
169 tempi = xf86SetIntOption(list, "VelocityTrackerCount", -1);
170 if (tempi > 1)
171 InitTrackers(s, tempi);
172
173 s->initial_range = xf86SetIntOption(list, "VelocityInitialRange",
174 s->initial_range);
175
176 s->max_diff = xf86SetRealOption(list, "VelocityAbsDiff", s->max_diff);
177
178 tempf = xf86SetRealOption(list, "VelocityRelDiff", -1);
179 if (tempf >= 0) {
180 xf86Msg(X_CONFIG, "%s: (accel) max rel. velocity difference: %.1f%%\n",
181 devname, tempf * 100.0);
182 s->max_rel_diff = tempf;
183 }
184
185 /* Configure softening. If const deceleration is used, this is expected
186 * to provide better subpixel information so we enable
187 * softening by default only if ConstantDeceleration is not used
188 */
189 s->use_softening = xf86SetBoolOption(list, "Softening",
190 s->const_acceleration == 1.0);
191
192 s->average_accel = xf86SetBoolOption(list, "AccelerationProfileAveraging",
193 s->average_accel);
194
195 s->reset_time = xf86SetIntOption(list, "VelocityReset", s->reset_time);
196}
197
198static void
199ApplyAccelerationSettings(DeviceIntPtr dev)
200{
201 int scheme, i;
202 DeviceVelocityPtr pVel;
203 InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
204 char *schemeStr;
205
206 if (dev->valuator && dev->ptrfeed) {
207 schemeStr = xf86SetStrOption(pInfo->options, "AccelerationScheme", "");
208
209 scheme = dev->valuator->accelScheme.number;
210
211 if (!xf86NameCmp(schemeStr, "predictable"))
212 scheme = PtrAccelPredictable;
213
214 if (!xf86NameCmp(schemeStr, "lightweight"))
215 scheme = PtrAccelLightweight;
216
217 if (!xf86NameCmp(schemeStr, "none"))
218 scheme = PtrAccelNoOp;
219
220 /* reinit scheme if needed */
221 if (dev->valuator->accelScheme.number != scheme) {
222 if (dev->valuator->accelScheme.AccelCleanupProc) {
223 dev->valuator->accelScheme.AccelCleanupProc(dev);
224 }
225
226 if (InitPointerAccelerationScheme(dev, scheme)) {
227 xf86Msg(X_CONFIG, "%s: (accel) selected scheme %s/%i\n",
228 pInfo->name, schemeStr, scheme);
229 }
230 else {
231 xf86Msg(X_CONFIG, "%s: (accel) could not init scheme %s\n",
232 pInfo->name, schemeStr);
233 scheme = dev->valuator->accelScheme.number;
234 }
235 }
236 else {
237 xf86Msg(X_CONFIG, "%s: (accel) keeping acceleration scheme %i\n",
238 pInfo->name, scheme);
239 }
240
241 free(schemeStr);
242
243 /* process special configuration */
244 switch (scheme) {
245 case PtrAccelPredictable:
246 pVel = GetDevicePredictableAccelData(dev);
247 ProcessVelocityConfiguration(dev, pInfo->name, pInfo->options,
248 pVel);
249 break;
250 }
251
252 i = xf86SetIntOption(pInfo->options, "AccelerationNumerator",
253 dev->ptrfeed->ctrl.num);
254 if (i >= 0)
255 dev->ptrfeed->ctrl.num = i;
256
257 i = xf86SetIntOption(pInfo->options, "AccelerationDenominator",
258 dev->ptrfeed->ctrl.den);
259 if (i > 0)
260 dev->ptrfeed->ctrl.den = i;
261
262 i = xf86SetIntOption(pInfo->options, "AccelerationThreshold",
263 dev->ptrfeed->ctrl.threshold);
264 if (i >= 0)
265 dev->ptrfeed->ctrl.threshold = i;
266
267 xf86Msg(X_CONFIG, "%s: (accel) acceleration factor: %.3f\n",
268 pInfo->name, ((float) dev->ptrfeed->ctrl.num) /
269 ((float) dev->ptrfeed->ctrl.den));
270 xf86Msg(X_CONFIG, "%s: (accel) acceleration threshold: %i\n",
271 pInfo->name, dev->ptrfeed->ctrl.threshold);
272 }
273}
274
275static void
276ApplyTransformationMatrix(DeviceIntPtr dev)
277{
278 InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
279 char *str;
280 int rc;
281 float matrix[9] = { 0 };
282
283 if (!dev->valuator)
284 return;
285
286 str = xf86SetStrOption(pInfo->options, "TransformationMatrix", NULL);
287 if (!str)
288 return;
289
290 rc = sscanf(str, "%f %f %f %f %f %f %f %f %f", &matrix[0], &matrix[1],
291 &matrix[2], &matrix[3], &matrix[4], &matrix[5], &matrix[6],
292 &matrix[7], &matrix[8]);
293 if (rc != 9) {
294 xf86Msg(X_ERROR,
295 "%s: invalid format for transformation matrix. Ignoring configuration.\n",
296 pInfo->name);
297 return;
298 }
299
300 XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_TRANSFORM),
301 XIGetKnownProperty(XATOM_FLOAT), 32,
302 PropModeReplace, 9, matrix, FALSE);
303}
304
305/***********************************************************************
306 *
307 * xf86ProcessCommonOptions --
308 *
309 * Process global options.
310 *
311 ***********************************************************************
312 */
313void
314xf86ProcessCommonOptions(InputInfoPtr pInfo, XF86OptionPtr list)
315{
316 if (xf86SetBoolOption(list, "Floating", 0) ||
317 !xf86SetBoolOption(list, "AlwaysCore", 1) ||
318 !xf86SetBoolOption(list, "SendCoreEvents", 1) ||
319 !xf86SetBoolOption(list, "CorePointer", 1) ||
320 !xf86SetBoolOption(list, "CoreKeyboard", 1)) {
321 xf86Msg(X_CONFIG, "%s: doesn't report core events\n", pInfo->name);
322 }
323 else {
324 pInfo->flags |= XI86_ALWAYS_CORE;
325 xf86Msg(X_CONFIG, "%s: always reports core events\n", pInfo->name);
326 }
327}
328
329/***********************************************************************
330 *
331 * xf86ActivateDevice --
332 *
333 * Initialize an input device.
334 *
335 * Returns TRUE on success, or FALSE otherwise.
336 ***********************************************************************
337 */
338static DeviceIntPtr
339xf86ActivateDevice(InputInfoPtr pInfo)
340{
341 DeviceIntPtr dev;
342 Atom atom;
343
344 dev = AddInputDevice(serverClient, pInfo->device_control, TRUE);
345
346 if (dev == NULL) {
347 xf86Msg(X_ERROR, "Too many input devices. Ignoring %s\n", pInfo->name);
348 pInfo->dev = NULL;
349 return NULL;
350 }
351
352 atom = MakeAtom(pInfo->type_name, strlen(pInfo->type_name), TRUE);
353 AssignTypeAndName(dev, atom, pInfo->name);
354 dev->public.devicePrivate = pInfo;
355 pInfo->dev = dev;
356
357 dev->coreEvents = pInfo->flags & XI86_ALWAYS_CORE;
358 dev->type = SLAVE;
359 dev->spriteInfo->spriteOwner = FALSE;
360
361 dev->config_info = xf86SetStrOption(pInfo->options, "config_info", NULL);
362
363 if (serverGeneration == 1)
364 xf86Msg(X_INFO,
365 "XINPUT: Adding extended input device \"%s\" (type: %s, id %d)\n",
366 pInfo->name, pInfo->type_name, dev->id);
367
368 return dev;
369}
370
371/****************************************************************************
372 *
373 * Caller: ProcXSetDeviceMode
374 *
375 * Change the mode of an extension device.
376 * This function is used to change the mode of a device from reporting
377 * relative motion to reporting absolute positional information, and
378 * vice versa.
379 * The default implementation below is that no such devices are supported.
380 *
381 ***********************************************************************
382 */
383
384int
385SetDeviceMode(ClientPtr client, DeviceIntPtr dev, int mode)
386{
387 InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
388
389 if (pInfo->switch_mode) {
390 return (*pInfo->switch_mode) (client, dev, mode);
391 }
392 else
393 return BadMatch;
394}
395
396/***********************************************************************
397 *
398 * Caller: ProcXSetDeviceValuators
399 *
400 * Set the value of valuators on an extension input device.
401 * This function is used to set the initial value of valuators on
402 * those input devices that are capable of reporting either relative
403 * motion or an absolute position, and allow an initial position to be set.
404 * The default implementation below is that no such devices are supported.
405 *
406 ***********************************************************************
407 */
408
409int
410SetDeviceValuators(ClientPtr client, DeviceIntPtr dev, int *valuators,
411 int first_valuator, int num_valuators)
412{
413 InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
414
415 if (pInfo->set_device_valuators)
416 return (*pInfo->set_device_valuators) (pInfo, valuators, first_valuator,
417 num_valuators);
418
419 return BadMatch;
420}
421
422/***********************************************************************
423 *
424 * Caller: ProcXChangeDeviceControl
425 *
426 * Change the specified device controls on an extension input device.
427 *
428 ***********************************************************************
429 */
430
431int
432ChangeDeviceControl(ClientPtr client, DeviceIntPtr dev, xDeviceCtl * control)
433{
434 InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
435
436 if (!pInfo->control_proc) {
437 switch (control->control) {
438 case DEVICE_CORE:
439 case DEVICE_ABS_CALIB:
440 case DEVICE_ABS_AREA:
441 return BadMatch;
442 case DEVICE_RESOLUTION:
443 case DEVICE_ENABLE:
444 return Success;
445 default:
446 return BadMatch;
447 }
448 }
449 else {
450 return (*pInfo->control_proc) (pInfo, control);
451 }
452}
453
454/*
455 * Get the operating system name from uname and store it statically to avoid
456 * repeating the system call each time MatchOS is checked.
457 */
458static const char *
459HostOS(void)
460{
461#ifdef HAVE_SYS_UTSNAME_H
462 struct utsname name;
463 static char host_os[sizeof(name.sysname)] = "";
464
465 if (*host_os == '\0') {
466 if (uname(&name) >= 0)
467 strlcpy(host_os, name.sysname, sizeof(host_os));
468 else {
469 strlcpy(host_os, "unknown", sizeof(host_os));
470 }
471 }
472 return host_os;
473#else
474 return "";
475#endif
476}
477
478static int
479match_substring(const char *attr, const char *pattern)
480{
481 return (strstr(attr, pattern)) ? 0 : -1;
482}
483
484#ifdef HAVE_FNMATCH_H
485static int
486match_pattern(const char *attr, const char *pattern)
487{
488 return fnmatch(pattern, attr, 0);
489}
490#else
491#define match_pattern match_substring
492#endif
493
494#ifdef HAVE_FNMATCH_H
495static int
496match_path_pattern(const char *attr, const char *pattern)
497{
498 return fnmatch(pattern, attr, FNM_PATHNAME);
499}
500#else
501#define match_path_pattern match_substring
502#endif
503
504/*
505 * If no Layout section is found, xf86ServerLayout.id becomes "(implicit)"
506 * It is convenient that "" in patterns means "no explicit layout"
507 */
508static int
509match_string_implicit(const char *attr, const char *pattern)
510{
511 if (strlen(pattern)) {
512 return strcmp(attr, pattern);
513 }
514 else {
515 return strcmp(attr, "(implicit)");
516 }
517}
518
519/*
520 * Match an attribute against a list of NULL terminated arrays of patterns.
521 * If a pattern in each list entry is matched, return TRUE.
522 */
523static Bool
524MatchAttrToken(const char *attr, struct xorg_list *patterns,
525 int (*compare) (const char *attr, const char *pattern))
526{
527 const xf86MatchGroup *group;
528
529 /* If there are no patterns, accept the match */
530 if (xorg_list_is_empty(patterns))
531 return TRUE;
532
533 /* If there are patterns but no attribute, reject the match */
534 if (!attr)
535 return FALSE;
536
537 /*
538 * Otherwise, iterate the list of patterns ensuring each entry has a
539 * match. Each list entry is a separate Match line of the same type.
540 */
541 xorg_list_for_each_entry(group, patterns, entry) {
542 char *const *cur;
543 Bool match = FALSE;
544
545 for (cur = group->values; *cur; cur++)
546 if ((*compare) (attr, *cur) == 0) {
547 match = TRUE;
548 break;
549 }
550 if (!match)
551 return FALSE;
552 }
553
554 /* All the entries in the list matched the attribute */
555 return TRUE;
556}
557
558/*
559 * Classes without any Match statements match all devices. Otherwise, all
560 * statements must match.
561 */
562static Bool
563InputClassMatches(const XF86ConfInputClassPtr iclass, const InputInfoPtr idev,
564 const InputAttributes * attrs)
565{
566 /* MatchProduct substring */
567 if (!MatchAttrToken
568 (attrs->product, &iclass->match_product, match_substring))
569 return FALSE;
570
571 /* MatchVendor substring */
572 if (!MatchAttrToken(attrs->vendor, &iclass->match_vendor, match_substring))
573 return FALSE;
574
575 /* MatchDevicePath pattern */
576 if (!MatchAttrToken
577 (attrs->device, &iclass->match_device, match_path_pattern))
578 return FALSE;
579
580 /* MatchOS case-insensitive string */
581 if (!MatchAttrToken(HostOS(), &iclass->match_os, strcasecmp))
582 return FALSE;
583
584 /* MatchPnPID pattern */
585 if (!MatchAttrToken(attrs->pnp_id, &iclass->match_pnpid, match_pattern))
586 return FALSE;
587
588 /* MatchUSBID pattern */
589 if (!MatchAttrToken(attrs->usb_id, &iclass->match_usbid, match_pattern))
590 return FALSE;
591
592 /* MatchDriver string */
593 if (!MatchAttrToken(idev->driver, &iclass->match_driver, strcmp))
594 return FALSE;
595
596 /*
597 * MatchTag string
598 * See if any of the device's tags match any of the MatchTag tokens.
599 */
600 if (!xorg_list_is_empty(&iclass->match_tag)) {
601 char *const *tag;
602 Bool match;
603
604 if (!attrs->tags)
605 return FALSE;
606 for (tag = attrs->tags, match = FALSE; *tag; tag++) {
607 if (MatchAttrToken(*tag, &iclass->match_tag, strcmp)) {
608 match = TRUE;
609 break;
610 }
611 }
612 if (!match)
613 return FALSE;
614 }
615
616 /* MatchLayout string */
617 if (!xorg_list_is_empty(&iclass->match_layout)) {
618 if (!MatchAttrToken(xf86ConfigLayout.id,
619 &iclass->match_layout, match_string_implicit))
620 return FALSE;
621 }
622
623 /* MatchIs* booleans */
624 if (iclass->is_keyboard.set &&
625 iclass->is_keyboard.val != ! !(attrs->flags & ATTR_KEYBOARD))
626 return FALSE;
627 if (iclass->is_pointer.set &&
628 iclass->is_pointer.val != ! !(attrs->flags & ATTR_POINTER))
629 return FALSE;
630 if (iclass->is_joystick.set &&
631 iclass->is_joystick.val != ! !(attrs->flags & ATTR_JOYSTICK))
632 return FALSE;
633 if (iclass->is_tablet.set &&
634 iclass->is_tablet.val != ! !(attrs->flags & ATTR_TABLET))
635 return FALSE;
636 if (iclass->is_touchpad.set &&
637 iclass->is_touchpad.val != ! !(attrs->flags & ATTR_TOUCHPAD))
638 return FALSE;
639 if (iclass->is_touchscreen.set &&
640 iclass->is_touchscreen.val != ! !(attrs->flags & ATTR_TOUCHSCREEN))
641 return FALSE;
642
643 return TRUE;
644}
645
646/*
647 * Merge in any InputClass configurations. Options in each InputClass
648 * section have more priority than the original device configuration as
649 * well as any previous InputClass sections.
650 */
651static int
652MergeInputClasses(const InputInfoPtr idev, const InputAttributes * attrs)
653{
654 XF86ConfInputClassPtr cl;
655 XF86OptionPtr classopts;
656
657 for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
658 if (!InputClassMatches(cl, idev, attrs))
659 continue;
660
661 /* Collect class options and driver settings */
662 classopts = xf86optionListDup(cl->option_lst);
663 if (cl->driver) {
664 free(idev->driver);
665 idev->driver = xstrdup(cl->driver);
666 if (!idev->driver) {
667 xf86Msg(X_ERROR, "Failed to allocate memory while merging "
668 "InputClass configuration");
669 return BadAlloc;
670 }
671 classopts = xf86ReplaceStrOption(classopts, "driver", idev->driver);
672 }
673
674 /* Apply options to device with InputClass settings preferred. */
675 xf86Msg(X_CONFIG, "%s: Applying InputClass \"%s\"\n",
676 idev->name, cl->identifier);
677 idev->options = xf86optionListMerge(idev->options, classopts);
678 }
679
680 return Success;
681}
682
683/*
684 * Iterate the list of classes and look for Option "Ignore". Return the
685 * value of the last matching class and holler when returning TRUE.
686 */
687static Bool
688IgnoreInputClass(const InputInfoPtr idev, const InputAttributes * attrs)
689{
690 XF86ConfInputClassPtr cl;
691 Bool ignore = FALSE;
692 const char *ignore_class;
693
694 for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
695 if (!InputClassMatches(cl, idev, attrs))
696 continue;
697 if (xf86findOption(cl->option_lst, "Ignore")) {
698 ignore = xf86CheckBoolOption(cl->option_lst, "Ignore", FALSE);
699 ignore_class = cl->identifier;
700 }
701 }
702
703 if (ignore)
704 xf86Msg(X_CONFIG, "%s: Ignoring device from InputClass \"%s\"\n",
705 idev->name, ignore_class);
706 return ignore;
707}
708
709InputInfoPtr
710xf86AllocateInput(void)
711{
712 InputInfoPtr pInfo;
713
714 pInfo = calloc(sizeof(*pInfo), 1);
715 if (!pInfo)
716 return NULL;
717
718 pInfo->fd = -1;
719 pInfo->type_name = "UNKNOWN";
720
721 return pInfo;
722}
723
724/* Append InputInfoRec to the tail of xf86InputDevs. */
725static void
726xf86AddInput(InputDriverPtr drv, InputInfoPtr pInfo)
727{
728 InputInfoPtr *prev = NULL;
729
730 pInfo->drv = drv;
731 pInfo->module = DuplicateModule(drv->module, NULL);
732
733 for (prev = &xf86InputDevs; *prev; prev = &(*prev)->next);
734
735 *prev = pInfo;
736 pInfo->next = NULL;
737
738 xf86CollectInputOptions(pInfo, (const char **) drv->default_options);
739 xf86OptionListReport(pInfo->options);
740 xf86ProcessCommonOptions(pInfo, pInfo->options);
741}
742
743/*
744 * Remove an entry from xf86InputDevs and free all the device's information.
745 */
746void
747xf86DeleteInput(InputInfoPtr pInp, int flags)
748{
749 /* First check if the inputdev is valid. */
750 if (pInp == NULL)
751 return;
752
753 if (pInp->module)
754 UnloadModule(pInp->module);
755
756 /* This should *really* be handled in drv->UnInit(dev) call instead, but
757 * if the driver forgets about it make sure we free it or at least crash
758 * with flying colors */
759 free(pInp->private);
760
761 FreeInputAttributes(pInp->attrs);
762
763 /* Remove the entry from the list. */
764 if (pInp == xf86InputDevs)
765 xf86InputDevs = pInp->next;
766 else {
767 InputInfoPtr p = xf86InputDevs;
768
769 while (p && p->next != pInp)
770 p = p->next;
771 if (p)
772 p->next = pInp->next;
773 /* Else the entry wasn't in the xf86InputDevs list (ignore this). */
774 }
775
776 free(pInp->driver);
777 free(pInp->name);
778 xf86optionListFree(pInp->options);
779 free(pInp);
780}
781
782/*
783 * Apply backend-specific initialization. Invoked after ActivateDevice(),
784 * i.e. after the driver successfully completed DEVICE_INIT and the device
785 * is advertised.
786 * @param dev the device
787 * @return Success or an error code
788 */
789static int
790xf86InputDevicePostInit(DeviceIntPtr dev)
791{
792 ApplyAccelerationSettings(dev);
793 ApplyTransformationMatrix(dev);
794 return Success;
795}
796
797/**
798 * Create a new input device, activate and enable it.
799 *
800 * Possible return codes:
801 * BadName .. a bad driver name was supplied.
802 * BadImplementation ... The driver does not have a PreInit function. This
803 * is a driver bug.
804 * BadMatch .. device initialization failed.
805 * BadAlloc .. too many input devices
806 *
807 * @param idev The device, already set up with identifier, driver, and the
808 * options.
809 * @param pdev Pointer to the new device, if Success was reported.
810 * @param enable Enable the device after activating it.
811 *
812 * @return Success or an error code
813 */
814_X_INTERNAL int
815xf86NewInputDevice(InputInfoPtr pInfo, DeviceIntPtr *pdev, BOOL enable)
816{
817 InputDriverPtr drv = NULL;
818 DeviceIntPtr dev = NULL;
819 int rval;
820
821 /* Memory leak for every attached device if we don't
822 * test if the module is already loaded first */
823 drv = xf86LookupInputDriver(pInfo->driver);
824 if (!drv)
825 if (xf86LoadOneModule(pInfo->driver, NULL))
826 drv = xf86LookupInputDriver(pInfo->driver);
827 if (!drv) {
828 xf86Msg(X_ERROR, "No input driver matching `%s'\n", pInfo->driver);
829 rval = BadName;
830 goto unwind;
831 }
832
833 xf86Msg(X_INFO, "Using input driver '%s' for '%s'\n", drv->driverName,
834 pInfo->name);
835
836 if (!drv->PreInit) {
837 xf86Msg(X_ERROR,
838 "Input driver `%s' has no PreInit function (ignoring)\n",
839 drv->driverName);
840 rval = BadImplementation;
841 goto unwind;
842 }
843
844 xf86AddInput(drv, pInfo);
845
846 rval = drv->PreInit(drv, pInfo, 0);
847
848 if (rval != Success) {
849 xf86Msg(X_ERROR, "PreInit returned %d for \"%s\"\n", rval, pInfo->name);
850 goto unwind;
851 }
852
853 if (!(dev = xf86ActivateDevice(pInfo))) {
854 rval = BadAlloc;
855 goto unwind;
856 }
857
858 rval = ActivateDevice(dev, TRUE);
859 if (rval != Success) {
860 xf86Msg(X_ERROR, "Couldn't init device \"%s\"\n", pInfo->name);
861 RemoveDevice(dev, TRUE);
862 goto unwind;
863 }
864
865 rval = xf86InputDevicePostInit(dev);
866 if (rval != Success) {
867 xf86Msg(X_ERROR, "Couldn't post-init device \"%s\"\n", pInfo->name);
868 RemoveDevice(dev, TRUE);
869 goto unwind;
870 }
871
872 /* Enable it if it's properly initialised and we're currently in the VT */
873 if (enable && dev->inited && dev->startup && xf86VTOwner()) {
874 OsBlockSignals();
875 EnableDevice(dev, TRUE);
876 if (!dev->enabled) {
877 OsReleaseSignals();
878 xf86Msg(X_ERROR, "Couldn't init device \"%s\"\n", pInfo->name);
879 RemoveDevice(dev, TRUE);
880 rval = BadMatch;
881 goto unwind;
882 }
883 /* send enter/leave event, update sprite window */
884 CheckMotion(NULL, dev);
885 OsReleaseSignals();
886 }
887
888 *pdev = dev;
889 return Success;
890
891 unwind:
892 if (pInfo) {
893 if (drv && drv->UnInit)
894 drv->UnInit(drv, pInfo, 0);
895 else
896 xf86DeleteInput(pInfo, 0);
897 }
898 return rval;
899}
900
901int
902NewInputDeviceRequest(InputOption *options, InputAttributes * attrs,
903 DeviceIntPtr *pdev)
904{
905 InputInfoPtr pInfo = NULL;
906 InputOption *option = NULL;
907 int rval = Success;
908 int is_auto = 0;
909
910 pInfo = xf86AllocateInput();
911 if (!pInfo)
912 return BadAlloc;
913
914 nt_list_for_each_entry(option, options, list.next) {
915 const char *key = input_option_get_key(option);
916 const char *value = input_option_get_value(option);
917
918 if (strcasecmp(key, "driver") == 0) {
919 if (pInfo->driver) {
920 rval = BadRequest;
921 goto unwind;
922 }
923 pInfo->driver = xstrdup(value);
924 if (!pInfo->driver) {
925 rval = BadAlloc;
926 goto unwind;
927 }
928 }
929
930 if (strcasecmp(key, "name") == 0 || strcasecmp(key, "identifier") == 0) {
931 if (pInfo->name) {
932 rval = BadRequest;
933 goto unwind;
934 }
935 pInfo->name = xstrdup(value);
936 if (!pInfo->name) {
937 rval = BadAlloc;
938 goto unwind;
939 }
940 }
941
942 if (strcmp(key, "_source") == 0 &&
943 (strcmp(value, "server/hal") == 0 ||
944 strcmp(value, "server/udev") == 0 ||
945 strcmp(value, "server/wscons") == 0)) {
946 is_auto = 1;
947 if (!xf86Info.autoAddDevices) {
948 rval = BadMatch;
949 goto unwind;
950 }
951 }
952 }
953
954 nt_list_for_each_entry(option, options, list.next) {
955 /* Copy option key/value strings from the provided list */
956 pInfo->options = xf86AddNewOption(pInfo->options,
957 input_option_get_key(option),
958 input_option_get_value(option));
959 }
960
961 /* Apply InputClass settings */
962 if (attrs) {
963 if (IgnoreInputClass(pInfo, attrs)) {
964 rval = BadIDChoice;
965 goto unwind;
966 }
967
968 rval = MergeInputClasses(pInfo, attrs);
969 if (rval != Success)
970 goto unwind;
971
972 pInfo->attrs = DuplicateInputAttributes(attrs);
973 }
974
975 if (!pInfo->name) {
976 xf86Msg(X_INFO, "No identifier specified, ignoring this device.\n");
977 rval = BadRequest;
978 goto unwind;
979 }
980
981 if (!pInfo->driver) {
982 xf86Msg(X_INFO, "No input driver specified, ignoring this device.\n");
983 xf86Msg(X_INFO,
984 "This device may have been added with another device file.\n");
985 rval = BadRequest;
986 goto unwind;
987 }
988
989 rval = xf86NewInputDevice(pInfo, pdev,
990 (!is_auto ||
991 (is_auto && xf86Info.autoEnableDevices)));
992
993 return rval;
994
995 unwind:
996 if (is_auto && !xf86Info.autoAddDevices)
997 xf86Msg(X_INFO, "AutoAddDevices is off - not adding device.\n");
998 xf86DeleteInput(pInfo, 0);
999 return rval;
1000}
1001
1002void
1003DeleteInputDeviceRequest(DeviceIntPtr pDev)
1004{
1005 InputInfoPtr pInfo = (InputInfoPtr) pDev->public.devicePrivate;
1006 InputDriverPtr drv = NULL;
1007 Bool isMaster = IsMaster(pDev);
1008
1009 if (pInfo) /* need to get these before RemoveDevice */
1010 drv = pInfo->drv;
1011
1012 OsBlockSignals();
1013 RemoveDevice(pDev, TRUE);
1014
1015 if (!isMaster && pInfo != NULL) {
1016 if (drv->UnInit)
1017 drv->UnInit(drv, pInfo, 0);
1018 else
1019 xf86DeleteInput(pInfo, 0);
1020 }
1021 OsReleaseSignals();
1022}
1023
1024/*
1025 * convenient functions to post events
1026 */
1027
1028void
1029xf86PostMotionEvent(DeviceIntPtr device,
1030 int is_absolute, int first_valuator, int num_valuators, ...)
1031{
1032 va_list var;
1033 int i = 0;
1034 ValuatorMask mask;
1035
1036 XI_VERIFY_VALUATORS(num_valuators);
1037
1038 valuator_mask_zero(&mask);
1039 va_start(var, num_valuators);
1040 for (i = 0; i < num_valuators; i++)
1041 valuator_mask_set(&mask, first_valuator + i, va_arg(var, int));
1042
1043 va_end(var);
1044
1045 xf86PostMotionEventM(device, is_absolute, &mask);
1046}
1047
1048void
1049xf86PostMotionEventP(DeviceIntPtr device,
1050 int is_absolute,
1051 int first_valuator,
1052 int num_valuators, const int *valuators)
1053{
1054 ValuatorMask mask;
1055
1056 XI_VERIFY_VALUATORS(num_valuators);
1057
1058 valuator_mask_set_range(&mask, first_valuator, num_valuators, valuators);
1059 xf86PostMotionEventM(device, is_absolute, &mask);
1060}
1061
1062static int
1063xf86CheckMotionEvent4DGA(DeviceIntPtr device, int is_absolute,
1064 const ValuatorMask *mask)
1065{
1066 int stolen = 0;
1067
1068#if XFreeXDGA
1069 ScreenPtr scr = NULL;
1070 int idx, i;
1071
1072 /* The evdev driver may not always send all axes across. */
1073 if (valuator_mask_isset(mask, 0) || valuator_mask_isset(mask, 1)) {
1074 scr = miPointerGetScreen(device);
1075 if (scr) {
1076 int dx = 0, dy = 0;
1077
1078 idx = scr->myNum;
1079
1080 if (valuator_mask_isset(mask, 0)) {
1081 dx = valuator_mask_get(mask, 0);
1082 if (is_absolute)
1083 dx -= device->last.valuators[0];
1084 }
1085
1086 if (valuator_mask_isset(mask, 1)) {
1087 dy = valuator_mask_get(mask, 1);
1088 if (is_absolute)
1089 dy -= device->last.valuators[1];
1090 }
1091
1092 if (DGAStealMotionEvent(device, idx, dx, dy))
1093 stolen = 1;
1094 }
1095 }
1096
1097 for (i = 2; i < valuator_mask_size(mask); i++) {
1098 AxisInfoPtr ax;
1099 double incr;
1100 int val, button;
1101
1102 if (i >= device->valuator->numAxes)
1103 break;
1104
1105 if (!valuator_mask_isset(mask, i))
1106 continue;
1107
1108 ax = &device->valuator->axes[i];
1109
1110 if (ax->scroll.type == SCROLL_TYPE_NONE)
1111 continue;
1112
1113 if (!scr) {
1114 scr = miPointerGetScreen(device);
1115 if (!scr)
1116 break;
1117 idx = scr->myNum;
1118 }
1119
1120 incr = ax->scroll.increment;
1121 val = valuator_mask_get(mask, i);
1122
1123 if (ax->scroll.type == SCROLL_TYPE_VERTICAL) {
1124 if (incr * val < 0)
1125 button = 4; /* up */
1126 else
1127 button = 5; /* down */
1128 } else { /* SCROLL_TYPE_HORIZONTAL */
1129 if (incr * val < 0)
1130 button = 6; /* left */
1131 else
1132 button = 7; /* right */
1133 }
1134
1135 if (DGAStealButtonEvent(device, idx, button, 1) &&
1136 DGAStealButtonEvent(device, idx, button, 0))
1137 stolen = 1;
1138 }
1139
1140#endif
1141
1142 return stolen;
1143}
1144
1145void
1146xf86PostMotionEventM(DeviceIntPtr device,
1147 int is_absolute, const ValuatorMask *mask)
1148{
1149 int flags = 0;
1150
1151 if (xf86CheckMotionEvent4DGA(device, is_absolute, mask))
1152 return;
1153
1154 if (valuator_mask_num_valuators(mask) > 0) {
1155 if (is_absolute)
1156 flags = POINTER_ABSOLUTE;
1157 else
1158 flags = POINTER_RELATIVE | POINTER_ACCELERATE;
1159 }
1160
1161 QueuePointerEvents(device, MotionNotify, 0, flags, mask);
1162}
1163
1164void
1165xf86PostProximityEvent(DeviceIntPtr device,
1166 int is_in, int first_valuator, int num_valuators, ...)
1167{
1168 va_list var;
1169 int i;
1170 ValuatorMask mask;
1171
1172 XI_VERIFY_VALUATORS(num_valuators);
1173
1174 valuator_mask_zero(&mask);
1175 va_start(var, num_valuators);
1176 for (i = 0; i < num_valuators; i++)
1177 valuator_mask_set(&mask, first_valuator + i, va_arg(var, int));
1178
1179 va_end(var);
1180
1181 xf86PostProximityEventM(device, is_in, &mask);
1182}
1183
1184void
1185xf86PostProximityEventP(DeviceIntPtr device,
1186 int is_in,
1187 int first_valuator,
1188 int num_valuators, const int *valuators)
1189{
1190 ValuatorMask mask;
1191
1192 XI_VERIFY_VALUATORS(num_valuators);
1193
1194 valuator_mask_set_range(&mask, first_valuator, num_valuators, valuators);
1195 xf86PostProximityEventM(device, is_in, &mask);
1196}
1197
1198void
1199xf86PostProximityEventM(DeviceIntPtr device,
1200 int is_in, const ValuatorMask *mask)
1201{
1202 QueueProximityEvents(device, is_in ? ProximityIn : ProximityOut, mask);
1203}
1204
1205void
1206xf86PostButtonEvent(DeviceIntPtr device,
1207 int is_absolute,
1208 int button,
1209 int is_down, int first_valuator, int num_valuators, ...)
1210{
1211 va_list var;
1212 ValuatorMask mask;
1213 int i = 0;
1214
1215 XI_VERIFY_VALUATORS(num_valuators);
1216
1217 valuator_mask_zero(&mask);
1218
1219 va_start(var, num_valuators);
1220 for (i = 0; i < num_valuators; i++)
1221 valuator_mask_set(&mask, first_valuator + i, va_arg(var, int));
1222
1223 va_end(var);
1224
1225 xf86PostButtonEventM(device, is_absolute, button, is_down, &mask);
1226}
1227
1228void
1229xf86PostButtonEventP(DeviceIntPtr device,
1230 int is_absolute,
1231 int button,
1232 int is_down,
1233 int first_valuator,
1234 int num_valuators, const int *valuators)
1235{
1236 ValuatorMask mask;
1237
1238 XI_VERIFY_VALUATORS(num_valuators);
1239
1240 valuator_mask_set_range(&mask, first_valuator, num_valuators, valuators);
1241 xf86PostButtonEventM(device, is_absolute, button, is_down, &mask);
1242}
1243
1244void
1245xf86PostButtonEventM(DeviceIntPtr device,
1246 int is_absolute,
1247 int button, int is_down, const ValuatorMask *mask)
1248{
1249 int flags = 0;
1250
1251 if (valuator_mask_num_valuators(mask) > 0) {
1252 if (is_absolute)
1253 flags = POINTER_ABSOLUTE;
1254 else
1255 flags = POINTER_RELATIVE | POINTER_ACCELERATE;
1256 }
1257
1258#if XFreeXDGA
1259 if (miPointerGetScreen(device)) {
1260 int index = miPointerGetScreen(device)->myNum;
1261
1262 if (DGAStealButtonEvent(device, index, button, is_down))
1263 return;
1264 }
1265#endif
1266
1267 QueuePointerEvents(device,
1268 is_down ? ButtonPress : ButtonRelease, button,
1269 flags, mask);
1270}
1271
1272void
1273xf86PostKeyEvent(DeviceIntPtr device,
1274 unsigned int key_code,
1275 int is_down,
1276 int is_absolute, int first_valuator, int num_valuators, ...)
1277{
1278 va_list var;
1279 int i = 0;
1280 ValuatorMask mask;
1281
1282 XI_VERIFY_VALUATORS(num_valuators);
1283
1284 valuator_mask_zero(&mask);
1285
1286 va_start(var, num_valuators);
1287 for (i = 0; i < num_valuators; i++)
1288 valuator_mask_set(&mask, first_valuator + i, va_arg(var, int));
1289
1290 va_end(var);
1291
1292 xf86PostKeyEventM(device, key_code, is_down, is_absolute, &mask);
1293}
1294
1295void
1296xf86PostKeyEventP(DeviceIntPtr device,
1297 unsigned int key_code,
1298 int is_down,
1299 int is_absolute,
1300 int first_valuator, int num_valuators, const int *valuators)
1301{
1302 ValuatorMask mask;
1303
1304 XI_VERIFY_VALUATORS(num_valuators);
1305
1306 valuator_mask_set_range(&mask, first_valuator, num_valuators, valuators);
1307 xf86PostKeyEventM(device, key_code, is_down, is_absolute, &mask);
1308}
1309
1310void
1311xf86PostKeyEventM(DeviceIntPtr device,
1312 unsigned int key_code,
1313 int is_down, int is_absolute, const ValuatorMask *mask)
1314{
1315#if XFreeXDGA
1316 DeviceIntPtr pointer;
1317
1318 /* Some pointers send key events, paired device is wrong then. */
1319 pointer = GetMaster(device, POINTER_OR_FLOAT);
1320
1321 if (miPointerGetScreen(pointer)) {
1322 int index = miPointerGetScreen(pointer)->myNum;
1323
1324 if (DGAStealKeyEvent(device, index, key_code, is_down))
1325 return;
1326 }
1327#endif
1328
1329 QueueKeyboardEvents(device,
1330 is_down ? KeyPress : KeyRelease, key_code, mask);
1331}
1332
1333void
1334xf86PostKeyboardEvent(DeviceIntPtr device, unsigned int key_code, int is_down)
1335{
1336 ValuatorMask mask;
1337
1338 valuator_mask_zero(&mask);
1339 xf86PostKeyEventM(device, key_code, is_down, 0, &mask);
1340}
1341
1342InputInfoPtr
1343xf86FirstLocalDevice(void)
1344{
1345 return xf86InputDevs;
1346}
1347
1348/*
1349 * Cx - raw data from touch screen
1350 * to_max - scaled highest dimension
1351 * (remember, this is of rows - 1 because of 0 origin)
1352 * to_min - scaled lowest dimension
1353 * from_max - highest raw value from touch screen calibration
1354 * from_min - lowest raw value from touch screen calibration
1355 *
1356 * This function is the same for X or Y coordinates.
1357 * You may have to reverse the high and low values to compensate for
1358 * different orgins on the touch screen vs X.
1359 *
1360 * e.g. to scale from device coordinates into screen coordinates, call
1361 * xf86ScaleAxis(x, 0, screen_width, dev_min, dev_max);
1362 */
1363
1364int
1365xf86ScaleAxis(int Cx, int to_max, int to_min, int from_max, int from_min)
1366{
1367 int X;
1368 int64_t to_width = to_max - to_min;
1369 int64_t from_width = from_max - from_min;
1370
1371 if (from_width) {
1372 X = (int) (((to_width * (Cx - from_min)) / from_width) + to_min);
1373 }
1374 else {
1375 X = 0;
1376 ErrorF("Divide by Zero in xf86ScaleAxis\n");
1377 }
1378
1379 if (X > to_max)
1380 X = to_max;
1381 if (X < to_min)
1382 X = to_min;
1383
1384 return X;
1385}
1386
1387Bool
1388xf86InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval,
1389 int maxval, int resolution, int min_res, int max_res,
1390 int mode)
1391{
1392 if (!dev || !dev->valuator)
1393 return FALSE;
1394
1395 return InitValuatorAxisStruct(dev, axnum, label, minval, maxval, resolution,
1396 min_res, max_res, mode);
1397}
1398
1399/*
1400 * Set the valuator values to be in sync with dix/event.c
1401 * DefineInitialRootWindow().
1402 */
1403void
1404xf86InitValuatorDefaults(DeviceIntPtr dev, int axnum)
1405{
1406 if (axnum == 0) {
1407 dev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2;
1408 dev->last.valuators[0] = dev->valuator->axisVal[0];
1409 }
1410 else if (axnum == 1) {
1411 dev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
1412 dev->last.valuators[1] = dev->valuator->axisVal[1];
1413 }
1414}
1415
1416/**
1417 * Deactivate a device. Call this function from the driver if you receive a
1418 * read error or something else that spoils your day.
1419 * Device will be moved to the off_devices list, but it will still be there
1420 * until you really clean up after it.
1421 * Notifies the client about an inactive device.
1422 *
1423 * @param panic True if device is unrecoverable and needs to be removed.
1424 */
1425void
1426xf86DisableDevice(DeviceIntPtr dev, Bool panic)
1427{
1428 if (!panic) {
1429 DisableDevice(dev, TRUE);
1430 }
1431 else {
1432 SendDevicePresenceEvent(dev->id, DeviceUnrecoverable);
1433 DeleteInputDeviceRequest(dev);
1434 }
1435}
1436
1437/**
1438 * Reactivate a device. Call this function from the driver if you just found
1439 * out that the read error wasn't quite that bad after all.
1440 * Device will be re-activated, and an event sent to the client.
1441 */
1442void
1443xf86EnableDevice(DeviceIntPtr dev)
1444{
1445 EnableDevice(dev, TRUE);
1446}
1447
1448/**
1449 * Post a touch event with optional valuators. If this is the first touch in
1450 * the sequence, at least x & y valuators must be provided. The driver is
1451 * responsible for maintaining the correct event sequence (TouchBegin, TouchUpdate,
1452 * TouchEnd). Submitting an update or end event for a unregistered touchid will
1453 * result in errors.
1454 * Touch IDs may be reused by the driver but only after a TouchEnd has been
1455 * submitted for that touch ID.
1456 *
1457 * @param dev The device to post the event for
1458 * @param touchid The touchid of the current touch event. Must be an
1459 * existing ID for TouchUpdate or TouchEnd events
1460 * @param type One of XI_TouchBegin, XI_TouchUpdate, XI_TouchEnd
1461 * @param flags Flags for this event
1462 * @param The valuator mask with all valuators set for this event.
1463 */
1464void
1465xf86PostTouchEvent(DeviceIntPtr dev, uint32_t touchid, uint16_t type,
1466 uint32_t flags, const ValuatorMask *mask)
1467{
1468
1469 QueueTouchEvents(dev, type, touchid, flags, mask);
1470}
1471
1472/* end of xf86Xinput.c */