1706f2543Smrg/*
2706f2543Smrg * Copyright � 1999 Keith Packard
3706f2543Smrg * Copyright � 2006 Nokia Corporation
4706f2543Smrg *
5706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
7706f2543Smrg * the above copyright notice appear in all copies and that both that
8706f2543Smrg * copyright notice and this permission notice appear in supporting
9706f2543Smrg * documentation, and that the name of the authors not be used in
10706f2543Smrg * advertising or publicity pertaining to distribution of the software without
11706f2543Smrg * specific, written prior permission.  The authors make no
12706f2543Smrg * representations about the suitability of this software for any purpose.  It
13706f2543Smrg * is provided "as is" without express or implied warranty.
14706f2543Smrg *
15706f2543Smrg * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17706f2543Smrg * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21706f2543Smrg * PERFORMANCE OF THIS SOFTWARE.
22706f2543Smrg */
23706f2543Smrg
24706f2543Smrg#ifdef HAVE_CONFIG_H
25706f2543Smrg#include <kdrive-config.h>
26706f2543Smrg#endif
27706f2543Smrg#include "kdrive.h"
28706f2543Smrg#include "inputstr.h"
29706f2543Smrg
30706f2543Smrg#define XK_PUBLISHING
31706f2543Smrg#include <X11/keysym.h>
32706f2543Smrg#if HAVE_X11_XF86KEYSYM_H
33706f2543Smrg#include <X11/XF86keysym.h>
34706f2543Smrg#endif
35706f2543Smrg#include <signal.h>
36706f2543Smrg#include <stdio.h>
37706f2543Smrg#ifdef sun
38706f2543Smrg#include <sys/file.h> /* needed for FNONBLOCK & FASYNC */
39706f2543Smrg#endif
40706f2543Smrg
41706f2543Smrg#include "xkbsrv.h"
42706f2543Smrg
43706f2543Smrg#include <X11/extensions/XI.h>
44706f2543Smrg#include <X11/extensions/XIproto.h>
45706f2543Smrg#include "XIstubs.h" /* even though we don't use stubs.  cute, no? */
46706f2543Smrg#include "exevents.h"
47706f2543Smrg#include "extinit.h"
48706f2543Smrg#include "exglobals.h"
49706f2543Smrg#include "eventstr.h"
50706f2543Smrg#include "xserver-properties.h"
51706f2543Smrg#include "inpututils.h"
52706f2543Smrg
53706f2543Smrg#define AtomFromName(x) MakeAtom(x, strlen(x), 1)
54706f2543Smrg
55706f2543Smrgstruct KdConfigDevice {
56706f2543Smrg    char *line;
57706f2543Smrg    struct KdConfigDevice *next;
58706f2543Smrg};
59706f2543Smrg
60706f2543Smrg/* kdKeyboards and kdPointers hold all the real devices. */
61706f2543Smrgstatic KdKeyboardInfo *kdKeyboards         = NULL;
62706f2543Smrgstatic KdPointerInfo  *kdPointers          = NULL;
63706f2543Smrgstatic struct KdConfigDevice *kdConfigKeyboards   = NULL;
64706f2543Smrgstatic struct KdConfigDevice *kdConfigPointers    = NULL;
65706f2543Smrg
66706f2543Smrgstatic KdKeyboardDriver *kdKeyboardDrivers = NULL;
67706f2543Smrgstatic KdPointerDriver  *kdPointerDrivers  = NULL;
68706f2543Smrg
69706f2543Smrgstatic EventListPtr     kdEvents = NULL;
70706f2543Smrg
71706f2543Smrgstatic Bool		kdInputEnabled;
72706f2543Smrgstatic Bool		kdOffScreen;
73706f2543Smrgstatic unsigned long	kdOffScreenTime;
74706f2543Smrgstatic KdPointerMatrix	kdPointerMatrix = {
75706f2543Smrg   { { 1, 0, 0 },
76706f2543Smrg     { 0, 1, 0 } }
77706f2543Smrg};
78706f2543Smrg
79706f2543Smrgvoid KdResetInputMachine (void);
80706f2543Smrg
81706f2543Smrg#define KD_MAX_INPUT_FDS    8
82706f2543Smrg
83706f2543Smrgtypedef struct _kdInputFd {
84706f2543Smrg    int	        fd;
85706f2543Smrg    void        (*read) (int fd, void *closure);
86706f2543Smrg    int	        (*enable) (int fd, void *closure);
87706f2543Smrg    void        (*disable) (int fd, void *closure);
88706f2543Smrg    void        *closure;
89706f2543Smrg} KdInputFd;
90706f2543Smrg
91706f2543Smrgstatic KdInputFd kdInputFds[KD_MAX_INPUT_FDS];
92706f2543Smrgstatic int	 kdNumInputFds;
93706f2543Smrg
94706f2543Smrgextern Bool      kdRawPointerCoordinates;
95706f2543Smrg
96706f2543Smrgstatic void
97706f2543SmrgKdSigio (int sig)
98706f2543Smrg{
99706f2543Smrg    int	i;
100706f2543Smrg
101706f2543Smrg    for (i = 0; i < kdNumInputFds; i++)
102706f2543Smrg	(*kdInputFds[i].read) (kdInputFds[i].fd, kdInputFds[i].closure);
103706f2543Smrg}
104706f2543Smrg
105706f2543Smrgstatic void
106706f2543SmrgKdBlockSigio (void)
107706f2543Smrg{
108706f2543Smrg    sigset_t	set;
109706f2543Smrg
110706f2543Smrg    sigemptyset (&set);
111706f2543Smrg    sigaddset (&set, SIGIO);
112706f2543Smrg    sigprocmask (SIG_BLOCK, &set, 0);
113706f2543Smrg}
114706f2543Smrg
115706f2543Smrgstatic void
116706f2543SmrgKdUnblockSigio (void)
117706f2543Smrg{
118706f2543Smrg    sigset_t	set;
119706f2543Smrg
120706f2543Smrg    sigemptyset (&set);
121706f2543Smrg    sigaddset (&set, SIGIO);
122706f2543Smrg    sigprocmask (SIG_UNBLOCK, &set, 0);
123706f2543Smrg}
124706f2543Smrg
125706f2543Smrg#ifdef DEBUG_SIGIO
126706f2543Smrg
127706f2543Smrgvoid
128706f2543SmrgKdAssertSigioBlocked (char *where)
129706f2543Smrg{
130706f2543Smrg    sigset_t	set, old;
131706f2543Smrg
132706f2543Smrg    sigemptyset (&set);
133706f2543Smrg    sigprocmask (SIG_BLOCK, &set, &old);
134706f2543Smrg    if (!sigismember (&old, SIGIO)) {
135706f2543Smrg	ErrorF ("SIGIO not blocked at %s\n", where);
136706f2543Smrg        KdBacktrace(0);
137706f2543Smrg    }
138706f2543Smrg}
139706f2543Smrg
140706f2543Smrg#else
141706f2543Smrg
142706f2543Smrg#define KdAssertSigioBlocked(s)
143706f2543Smrg
144706f2543Smrg#endif
145706f2543Smrg
146706f2543Smrgstatic int  kdnFds;
147706f2543Smrg
148706f2543Smrg#ifdef FNONBLOCK
149706f2543Smrg#define NOBLOCK FNONBLOCK
150706f2543Smrg#else
151706f2543Smrg#define NOBLOCK FNDELAY
152706f2543Smrg#endif
153706f2543Smrg
154706f2543Smrgvoid
155706f2543SmrgKdResetInputMachine (void)
156706f2543Smrg{
157706f2543Smrg    KdPointerInfo *pi;
158706f2543Smrg
159706f2543Smrg    for (pi = kdPointers; pi; pi = pi->next) {
160706f2543Smrg        pi->mouseState = start;
161706f2543Smrg        pi->eventHeld = FALSE;
162706f2543Smrg    }
163706f2543Smrg}
164706f2543Smrg
165706f2543Smrgstatic void
166706f2543SmrgKdNonBlockFd (int fd)
167706f2543Smrg{
168706f2543Smrg    int	flags;
169706f2543Smrg    flags = fcntl (fd, F_GETFL);
170706f2543Smrg    flags |= FASYNC|NOBLOCK;
171706f2543Smrg    fcntl (fd, F_SETFL, flags);
172706f2543Smrg}
173706f2543Smrg
174706f2543Smrgstatic void
175706f2543SmrgKdAddFd (int fd)
176706f2543Smrg{
177706f2543Smrg    struct sigaction	act;
178706f2543Smrg    sigset_t		set;
179706f2543Smrg
180706f2543Smrg    kdnFds++;
181706f2543Smrg    fcntl (fd, F_SETOWN, getpid());
182706f2543Smrg    KdNonBlockFd (fd);
183706f2543Smrg    AddEnabledDevice (fd);
184706f2543Smrg    memset (&act, '\0', sizeof act);
185706f2543Smrg    act.sa_handler = KdSigio;
186706f2543Smrg    sigemptyset (&act.sa_mask);
187706f2543Smrg    sigaddset (&act.sa_mask, SIGIO);
188706f2543Smrg    sigaddset (&act.sa_mask, SIGALRM);
189706f2543Smrg    sigaddset (&act.sa_mask, SIGVTALRM);
190706f2543Smrg    sigaction (SIGIO, &act, 0);
191706f2543Smrg    sigemptyset (&set);
192706f2543Smrg    sigprocmask (SIG_SETMASK, &set, 0);
193706f2543Smrg}
194706f2543Smrg
195706f2543Smrgstatic void
196706f2543SmrgKdRemoveFd (int fd)
197706f2543Smrg{
198706f2543Smrg    struct sigaction	act;
199706f2543Smrg    int			flags;
200706f2543Smrg
201706f2543Smrg    kdnFds--;
202706f2543Smrg    RemoveEnabledDevice (fd);
203706f2543Smrg    flags = fcntl (fd, F_GETFL);
204706f2543Smrg    flags &= ~(FASYNC|NOBLOCK);
205706f2543Smrg    fcntl (fd, F_SETFL, flags);
206706f2543Smrg    if (kdnFds == 0)
207706f2543Smrg    {
208706f2543Smrg	memset (&act, '\0', sizeof act);
209706f2543Smrg	act.sa_handler = SIG_IGN;
210706f2543Smrg	sigemptyset (&act.sa_mask);
211706f2543Smrg	sigaction (SIGIO, &act, 0);
212706f2543Smrg    }
213706f2543Smrg}
214706f2543Smrg
215706f2543SmrgBool
216706f2543SmrgKdRegisterFd (int fd, void (*read) (int fd, void *closure), void *closure)
217706f2543Smrg{
218706f2543Smrg    if (kdNumInputFds == KD_MAX_INPUT_FDS)
219706f2543Smrg	return FALSE;
220706f2543Smrg    kdInputFds[kdNumInputFds].fd = fd;
221706f2543Smrg    kdInputFds[kdNumInputFds].read = read;
222706f2543Smrg    kdInputFds[kdNumInputFds].enable = 0;
223706f2543Smrg    kdInputFds[kdNumInputFds].disable = 0;
224706f2543Smrg    kdInputFds[kdNumInputFds].closure = closure;
225706f2543Smrg    kdNumInputFds++;
226706f2543Smrg    if (kdInputEnabled)
227706f2543Smrg	KdAddFd (fd);
228706f2543Smrg    return TRUE;
229706f2543Smrg}
230706f2543Smrg
231706f2543Smrgvoid
232706f2543SmrgKdUnregisterFd (void *closure, int fd, Bool do_close)
233706f2543Smrg{
234706f2543Smrg    int	i, j;
235706f2543Smrg
236706f2543Smrg    for (i = 0; i < kdNumInputFds; i++) {
237706f2543Smrg	if (kdInputFds[i].closure == closure &&
238706f2543Smrg            (fd == -1 || kdInputFds[i].fd == fd)) {
239706f2543Smrg	    if (kdInputEnabled)
240706f2543Smrg		KdRemoveFd (kdInputFds[i].fd);
241706f2543Smrg	    if (do_close)
242706f2543Smrg		close (kdInputFds[i].fd);
243706f2543Smrg	    kdNumInputFds--;
244706f2543Smrg	    for (j = i; j < kdNumInputFds; j++)
245706f2543Smrg		kdInputFds[j] = kdInputFds[j+1];
246706f2543Smrg            break;
247706f2543Smrg	}
248706f2543Smrg    }
249706f2543Smrg}
250706f2543Smrg
251706f2543Smrgvoid
252706f2543SmrgKdUnregisterFds (void *closure, Bool do_close)
253706f2543Smrg{
254706f2543Smrg    KdUnregisterFd(closure, -1, do_close);
255706f2543Smrg}
256706f2543Smrg
257706f2543Smrgvoid
258706f2543SmrgKdDisableInput (void)
259706f2543Smrg{
260706f2543Smrg    KdKeyboardInfo *ki;
261706f2543Smrg    KdPointerInfo *pi;
262706f2543Smrg    int found = 0, i = 0;
263706f2543Smrg
264706f2543Smrg    KdBlockSigio();
265706f2543Smrg
266706f2543Smrg    for (ki = kdKeyboards; ki; ki = ki->next) {
267706f2543Smrg        if (ki->driver && ki->driver->Disable)
268706f2543Smrg            (*ki->driver->Disable) (ki);
269706f2543Smrg    }
270706f2543Smrg
271706f2543Smrg    for (pi = kdPointers; pi; pi = pi->next) {
272706f2543Smrg        if (pi->driver && pi->driver->Disable)
273706f2543Smrg            (*pi->driver->Disable) (pi);
274706f2543Smrg    }
275706f2543Smrg
276706f2543Smrg    if (kdNumInputFds) {
277706f2543Smrg        ErrorF("[KdDisableInput] Buggy drivers: still %d input fds left!",
278706f2543Smrg               kdNumInputFds);
279706f2543Smrg        i = 0;
280706f2543Smrg        while (i < kdNumInputFds) {
281706f2543Smrg            found = 0;
282706f2543Smrg            for (ki = kdKeyboards; ki; ki = ki->next) {
283706f2543Smrg                if (ki == kdInputFds[i].closure) {
284706f2543Smrg                    ErrorF("    fd %d belongs to keybd driver %s\n",
285706f2543Smrg                           kdInputFds[i].fd,
286706f2543Smrg                           ki->driver && ki->driver->name ?
287706f2543Smrg                             ki->driver->name : "(unnamed!)");
288706f2543Smrg                    found = 1;
289706f2543Smrg                    break;
290706f2543Smrg                }
291706f2543Smrg            }
292706f2543Smrg
293706f2543Smrg            if (found) {
294706f2543Smrg                i++;
295706f2543Smrg                continue;
296706f2543Smrg            }
297706f2543Smrg
298706f2543Smrg            for (pi = kdPointers; pi; pi = pi->next) {
299706f2543Smrg                if (pi == kdInputFds[i].closure) {
300706f2543Smrg                    ErrorF("    fd %d belongs to pointer driver %s\n",
301706f2543Smrg                           kdInputFds[i].fd,
302706f2543Smrg                           pi->driver && pi->driver->name ?
303706f2543Smrg                             pi->driver->name : "(unnamed!)");
304706f2543Smrg                    break;
305706f2543Smrg                }
306706f2543Smrg            }
307706f2543Smrg
308706f2543Smrg            if (found) {
309706f2543Smrg                i++;
310706f2543Smrg                continue;
311706f2543Smrg            }
312706f2543Smrg
313706f2543Smrg            ErrorF("    fd %d not claimed by any active device!\n",
314706f2543Smrg                   kdInputFds[i].fd);
315706f2543Smrg            KdUnregisterFd(kdInputFds[i].closure, kdInputFds[i].fd, TRUE);
316706f2543Smrg        }
317706f2543Smrg    }
318706f2543Smrg
319706f2543Smrg    kdInputEnabled = FALSE;
320706f2543Smrg}
321706f2543Smrg
322706f2543Smrgvoid
323706f2543SmrgKdEnableInput (void)
324706f2543Smrg{
325706f2543Smrg    InternalEvent ev;
326706f2543Smrg    KdKeyboardInfo *ki;
327706f2543Smrg    KdPointerInfo *pi;
328706f2543Smrg
329706f2543Smrg    kdInputEnabled = TRUE;
330706f2543Smrg
331706f2543Smrg    for (ki = kdKeyboards; ki; ki = ki->next) {
332706f2543Smrg        if (ki->driver && ki->driver->Enable)
333706f2543Smrg            (*ki->driver->Enable) (ki);
334706f2543Smrg    }
335706f2543Smrg
336706f2543Smrg    for (pi = kdPointers; pi; pi = pi->next) {
337706f2543Smrg        if (pi->driver && pi->driver->Enable)
338706f2543Smrg            (*pi->driver->Enable) (pi);
339706f2543Smrg    }
340706f2543Smrg
341706f2543Smrg    /* reset screen saver */
342706f2543Smrg    ev.any.time = GetTimeInMillis ();
343706f2543Smrg    NoticeEventTime (&ev);
344706f2543Smrg
345706f2543Smrg    KdUnblockSigio ();
346706f2543Smrg}
347706f2543Smrg
348706f2543Smrgstatic KdKeyboardDriver *
349706f2543SmrgKdFindKeyboardDriver (char *name)
350706f2543Smrg{
351706f2543Smrg    KdKeyboardDriver *ret;
352706f2543Smrg
353706f2543Smrg    /* ask a stupid question ... */
354706f2543Smrg    if (!name)
355706f2543Smrg        return NULL;
356706f2543Smrg
357706f2543Smrg    for (ret = kdKeyboardDrivers; ret; ret = ret->next) {
358706f2543Smrg        if (strcmp(ret->name, name) == 0)
359706f2543Smrg            return ret;
360706f2543Smrg    }
361706f2543Smrg
362706f2543Smrg    return NULL;
363706f2543Smrg}
364706f2543Smrg
365706f2543Smrgstatic KdPointerDriver *
366706f2543SmrgKdFindPointerDriver (char *name)
367706f2543Smrg{
368706f2543Smrg    KdPointerDriver *ret;
369706f2543Smrg
370706f2543Smrg    /* ask a stupid question ... */
371706f2543Smrg    if (!name)
372706f2543Smrg        return NULL;
373706f2543Smrg
374706f2543Smrg    for (ret = kdPointerDrivers; ret; ret = ret->next) {
375706f2543Smrg        if (strcmp(ret->name, name) == 0)
376706f2543Smrg            return ret;
377706f2543Smrg    }
378706f2543Smrg
379706f2543Smrg    return NULL;
380706f2543Smrg}
381706f2543Smrg
382706f2543Smrgstatic int
383706f2543SmrgKdPointerProc(DeviceIntPtr pDevice, int onoff)
384706f2543Smrg{
385706f2543Smrg    DevicePtr       pDev = (DevicePtr)pDevice;
386706f2543Smrg    KdPointerInfo   *pi;
387706f2543Smrg    Atom            xiclass;
388706f2543Smrg    Atom            *btn_labels;
389706f2543Smrg    Atom            *axes_labels;
390706f2543Smrg
391706f2543Smrg    if (!pDev)
392706f2543Smrg	return BadImplementation;
393706f2543Smrg
394706f2543Smrg    for (pi = kdPointers; pi; pi = pi->next) {
395706f2543Smrg        if (pi->dixdev && pi->dixdev->id == pDevice->id)
396706f2543Smrg            break;
397706f2543Smrg    }
398706f2543Smrg
399706f2543Smrg    if (!pi || !pi->dixdev || pi->dixdev->id != pDevice->id) {
400706f2543Smrg        ErrorF("[KdPointerProc] Failed to find pointer for device %d!\n",
401706f2543Smrg               pDevice->id);
402706f2543Smrg        return BadImplementation;
403706f2543Smrg    }
404706f2543Smrg
405706f2543Smrg    switch (onoff)
406706f2543Smrg    {
407706f2543Smrg    case DEVICE_INIT:
408706f2543Smrg#ifdef DEBUG
409706f2543Smrg        ErrorF("initialising pointer %s ...\n", pi->name);
410706f2543Smrg#endif
411706f2543Smrg        if (!pi->driver) {
412706f2543Smrg            if (!pi->driverPrivate) {
413706f2543Smrg                ErrorF("no driver specified for %s\n", pi->name);
414706f2543Smrg                return BadImplementation;
415706f2543Smrg            }
416706f2543Smrg
417706f2543Smrg            pi->driver = KdFindPointerDriver(pi->driverPrivate);
418706f2543Smrg            if (!pi->driver) {
419706f2543Smrg                ErrorF("Couldn't find pointer driver %s\n",
420706f2543Smrg                       pi->driverPrivate ? (char *) pi->driverPrivate :
421706f2543Smrg                       "(unnamed)");
422706f2543Smrg                return !Success;
423706f2543Smrg            }
424706f2543Smrg            free(pi->driverPrivate);
425706f2543Smrg            pi->driverPrivate = NULL;
426706f2543Smrg        }
427706f2543Smrg
428706f2543Smrg        if (!pi->driver->Init) {
429706f2543Smrg            ErrorF("no init function\n");
430706f2543Smrg            return BadImplementation;
431706f2543Smrg        }
432706f2543Smrg
433706f2543Smrg        if ((*pi->driver->Init) (pi) != Success) {
434706f2543Smrg            return !Success;
435706f2543Smrg        }
436706f2543Smrg
437706f2543Smrg	btn_labels = calloc(pi->nButtons, sizeof(Atom));
438706f2543Smrg	if (!btn_labels)
439706f2543Smrg	    return BadAlloc;
440706f2543Smrg	axes_labels = calloc(pi->nAxes, sizeof(Atom));
441706f2543Smrg	if (!axes_labels) {
442706f2543Smrg	    free(btn_labels);
443706f2543Smrg	    return BadAlloc;
444706f2543Smrg	}
445706f2543Smrg
446706f2543Smrg	switch(pi->nAxes)
447706f2543Smrg	{
448706f2543Smrg	    default:
449706f2543Smrg	    case 7:
450706f2543Smrg		btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
451706f2543Smrg	    case 6:
452706f2543Smrg		btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
453706f2543Smrg	    case 5:
454706f2543Smrg		btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
455706f2543Smrg	    case 4:
456706f2543Smrg		btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
457706f2543Smrg	    case 3:
458706f2543Smrg		btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
459706f2543Smrg	    case 2:
460706f2543Smrg		btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
461706f2543Smrg	    case 1:
462706f2543Smrg		btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
463706f2543Smrg	    case 0:
464706f2543Smrg		break;
465706f2543Smrg	}
466706f2543Smrg
467706f2543Smrg	if (pi->nAxes >= 2) {
468706f2543Smrg	    axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
469706f2543Smrg	    axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
470706f2543Smrg	}
471706f2543Smrg
472706f2543Smrg	InitPointerDeviceStruct(pDev, pi->map, pi->nButtons, btn_labels,
473706f2543Smrg	    (PtrCtrlProcPtr)NoopDDA,
474706f2543Smrg	    GetMotionHistorySize(), pi->nAxes, axes_labels);
475706f2543Smrg
476706f2543Smrg        free(btn_labels);
477706f2543Smrg        free(axes_labels);
478706f2543Smrg
479706f2543Smrg        if (pi->inputClass == KD_TOUCHSCREEN) {
480706f2543Smrg            InitAbsoluteClassDeviceStruct(pDevice);
481706f2543Smrg            xiclass = AtomFromName(XI_TOUCHSCREEN);
482706f2543Smrg        }
483706f2543Smrg        else {
484706f2543Smrg            xiclass = AtomFromName(XI_MOUSE);
485706f2543Smrg        }
486706f2543Smrg
487706f2543Smrg        AssignTypeAndName(pi->dixdev, xiclass,
488706f2543Smrg                          pi->name ? pi->name : "Generic KDrive Pointer");
489706f2543Smrg
490706f2543Smrg	return Success;
491706f2543Smrg
492706f2543Smrg    case DEVICE_ON:
493706f2543Smrg        if (pDev->on == TRUE)
494706f2543Smrg            return Success;
495706f2543Smrg
496706f2543Smrg        if (!pi->driver->Enable) {
497706f2543Smrg            ErrorF("no enable function\n");
498706f2543Smrg            return BadImplementation;
499706f2543Smrg        }
500706f2543Smrg
501706f2543Smrg        if ((*pi->driver->Enable) (pi) == Success) {
502706f2543Smrg            pDev->on = TRUE;
503706f2543Smrg            return Success;
504706f2543Smrg        }
505706f2543Smrg        else {
506706f2543Smrg            return BadImplementation;
507706f2543Smrg        }
508706f2543Smrg
509706f2543Smrg	return Success;
510706f2543Smrg
511706f2543Smrg    case DEVICE_OFF:
512706f2543Smrg        if (pDev->on == FALSE) {
513706f2543Smrg            return Success;
514706f2543Smrg        }
515706f2543Smrg
516706f2543Smrg        if (!pi->driver->Disable) {
517706f2543Smrg            return BadImplementation;
518706f2543Smrg        }
519706f2543Smrg        else {
520706f2543Smrg            (*pi->driver->Disable) (pi);
521706f2543Smrg            pDev->on = FALSE;
522706f2543Smrg            return Success;
523706f2543Smrg        }
524706f2543Smrg
525706f2543Smrg        return Success;
526706f2543Smrg
527706f2543Smrg    case DEVICE_CLOSE:
528706f2543Smrg	if (pDev->on) {
529706f2543Smrg            if (!pi->driver->Disable) {
530706f2543Smrg                return BadImplementation;
531706f2543Smrg            }
532706f2543Smrg            (*pi->driver->Disable) (pi);
533706f2543Smrg            pDev->on = FALSE;
534706f2543Smrg        }
535706f2543Smrg
536706f2543Smrg        if (!pi->driver->Fini)
537706f2543Smrg            return BadImplementation;
538706f2543Smrg
539706f2543Smrg        (*pi->driver->Fini) (pi);
540706f2543Smrg
541706f2543Smrg        KdRemovePointer(pi);
542706f2543Smrg
543706f2543Smrg        return Success;
544706f2543Smrg    }
545706f2543Smrg
546706f2543Smrg    /* NOTREACHED */
547706f2543Smrg    return BadImplementation;
548706f2543Smrg}
549706f2543Smrg
550706f2543SmrgBool
551706f2543SmrgLegalModifier(unsigned int key, DeviceIntPtr pDev)
552706f2543Smrg{
553706f2543Smrg    return TRUE;
554706f2543Smrg}
555706f2543Smrg
556706f2543Smrgstatic void
557706f2543SmrgKdBell (int volume, DeviceIntPtr pDev, pointer arg, int something)
558706f2543Smrg{
559706f2543Smrg    KeybdCtrl *ctrl = arg;
560706f2543Smrg    KdKeyboardInfo *ki = NULL;
561706f2543Smrg
562706f2543Smrg    for (ki = kdKeyboards; ki; ki = ki->next) {
563706f2543Smrg        if (ki->dixdev && ki->dixdev->id == pDev->id)
564706f2543Smrg            break;
565706f2543Smrg    }
566706f2543Smrg
567706f2543Smrg    if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver)
568706f2543Smrg        return;
569706f2543Smrg
570706f2543Smrg    KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration);
571706f2543Smrg}
572706f2543Smrg
573706f2543Smrgvoid
574706f2543SmrgDDXRingBell(int volume, int pitch, int duration)
575706f2543Smrg{
576706f2543Smrg    KdKeyboardInfo *ki = NULL;
577706f2543Smrg
578706f2543Smrg    if (kdOsFuncs->Bell) {
579706f2543Smrg        (*kdOsFuncs->Bell)(volume, pitch, duration);
580706f2543Smrg    }
581706f2543Smrg    else {
582706f2543Smrg        for (ki = kdKeyboards; ki; ki = ki->next) {
583706f2543Smrg            if (ki->dixdev->coreEvents)
584706f2543Smrg                KdRingBell(ki, volume, pitch, duration);
585706f2543Smrg        }
586706f2543Smrg    }
587706f2543Smrg}
588706f2543Smrg
589706f2543Smrgvoid
590706f2543SmrgKdRingBell(KdKeyboardInfo *ki, int volume, int pitch, int duration)
591706f2543Smrg{
592706f2543Smrg    if (!ki || !ki->driver || !ki->driver->Bell)
593706f2543Smrg        return;
594706f2543Smrg
595706f2543Smrg    if (kdInputEnabled)
596706f2543Smrg        (*ki->driver->Bell) (ki, volume, pitch, duration);
597706f2543Smrg}
598706f2543Smrg
599706f2543Smrg
600706f2543Smrgstatic void
601706f2543SmrgKdSetLeds (KdKeyboardInfo *ki, int leds)
602706f2543Smrg{
603706f2543Smrg    if (!ki || !ki->driver)
604706f2543Smrg        return;
605706f2543Smrg
606706f2543Smrg    if (kdInputEnabled) {
607706f2543Smrg        if (ki->driver->Leds)
608706f2543Smrg            (*ki->driver->Leds) (ki, leds);
609706f2543Smrg    }
610706f2543Smrg}
611706f2543Smrg
612706f2543Smrgvoid
613706f2543SmrgKdSetLed (KdKeyboardInfo *ki, int led, Bool on)
614706f2543Smrg{
615706f2543Smrg    if (!ki || !ki->dixdev || !ki->dixdev->kbdfeed)
616706f2543Smrg        return;
617706f2543Smrg
618706f2543Smrg    NoteLedState (ki->dixdev, led, on);
619706f2543Smrg    KdSetLeds (ki, ki->dixdev->kbdfeed->ctrl.leds);
620706f2543Smrg}
621706f2543Smrg
622706f2543Smrgvoid
623706f2543SmrgKdSetPointerMatrix (KdPointerMatrix *matrix)
624706f2543Smrg{
625706f2543Smrg    kdPointerMatrix = *matrix;
626706f2543Smrg}
627706f2543Smrg
628706f2543Smrgvoid
629706f2543SmrgKdComputePointerMatrix (KdPointerMatrix *m, Rotation randr, int width,
630706f2543Smrg                        int height)
631706f2543Smrg{
632706f2543Smrg    int		    x_dir = 1, y_dir = 1;
633706f2543Smrg    int		    i, j;
634706f2543Smrg    int		    size[2];
635706f2543Smrg
636706f2543Smrg    size[0] = width; size[1] = height;
637706f2543Smrg    if (randr & RR_Reflect_X)
638706f2543Smrg	x_dir = -1;
639706f2543Smrg    if (randr & RR_Reflect_Y)
640706f2543Smrg	y_dir = -1;
641706f2543Smrg    switch (randr & (RR_Rotate_All)) {
642706f2543Smrg    case RR_Rotate_0:
643706f2543Smrg	m->matrix[0][0] = x_dir; m->matrix[0][1] = 0;
644706f2543Smrg	m->matrix[1][0] = 0; m->matrix[1][1] = y_dir;
645706f2543Smrg	break;
646706f2543Smrg    case RR_Rotate_90:
647706f2543Smrg	m->matrix[0][0] = 0; m->matrix[0][1] = -x_dir;
648706f2543Smrg	m->matrix[1][0] = y_dir; m->matrix[1][1] = 0;
649706f2543Smrg	break;
650706f2543Smrg    case RR_Rotate_180:
651706f2543Smrg	m->matrix[0][0] = -x_dir; m->matrix[0][1] = 0;
652706f2543Smrg	m->matrix[1][0] = 0; m->matrix[1][1] = -y_dir;
653706f2543Smrg	break;
654706f2543Smrg    case RR_Rotate_270:
655706f2543Smrg	m->matrix[0][0] = 0; m->matrix[0][1] = x_dir;
656706f2543Smrg	m->matrix[1][0] = -y_dir; m->matrix[1][1] = 0;
657706f2543Smrg	break;
658706f2543Smrg    }
659706f2543Smrg    for (i = 0; i < 2; i++)
660706f2543Smrg    {
661706f2543Smrg	m->matrix[i][2] = 0;
662706f2543Smrg	for (j = 0 ; j < 2; j++)
663706f2543Smrg	    if (m->matrix[i][j] < 0)
664706f2543Smrg		m->matrix[i][2] = size[j] - 1;
665706f2543Smrg    }
666706f2543Smrg}
667706f2543Smrg
668706f2543Smrgvoid
669706f2543SmrgKdScreenToPointerCoords (int *x, int *y)
670706f2543Smrg{
671706f2543Smrg    int	(*m)[3] = kdPointerMatrix.matrix;
672706f2543Smrg    int div = m[0][1] * m[1][0] - m[1][1] * m[0][0];
673706f2543Smrg    int sx = *x;
674706f2543Smrg    int sy = *y;
675706f2543Smrg
676706f2543Smrg    *x = (m[0][1] * sy - m[0][1] * m[1][2] + m[1][1] * m[0][2] - m[1][1] * sx) / div;
677706f2543Smrg    *y = (m[1][0] * sx + m[0][0] * m[1][2] - m[1][0] * m[0][2] - m[0][0] * sy) / div;
678706f2543Smrg}
679706f2543Smrg
680706f2543Smrgstatic void
681706f2543SmrgKdKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl)
682706f2543Smrg{
683706f2543Smrg    KdKeyboardInfo *ki;
684706f2543Smrg
685706f2543Smrg    for (ki = kdKeyboards; ki; ki = ki->next) {
686706f2543Smrg        if (ki->dixdev && ki->dixdev->id == pDevice->id)
687706f2543Smrg            break;
688706f2543Smrg    }
689706f2543Smrg
690706f2543Smrg    if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver)
691706f2543Smrg        return;
692706f2543Smrg
693706f2543Smrg    KdSetLeds(ki, ctrl->leds);
694706f2543Smrg    ki->bellPitch = ctrl->bell_pitch;
695706f2543Smrg    ki->bellDuration = ctrl->bell_duration;
696706f2543Smrg}
697706f2543Smrg
698706f2543Smrgextern KeybdCtrl defaultKeyboardControl;
699706f2543Smrg
700706f2543Smrgstatic int
701706f2543SmrgKdKeyboardProc(DeviceIntPtr pDevice, int onoff)
702706f2543Smrg{
703706f2543Smrg    Bool        ret;
704706f2543Smrg    DevicePtr   pDev = (DevicePtr)pDevice;
705706f2543Smrg    KdKeyboardInfo *ki;
706706f2543Smrg    Atom xiclass;
707706f2543Smrg    XkbRMLVOSet rmlvo;
708706f2543Smrg
709706f2543Smrg    if (!pDev)
710706f2543Smrg	return BadImplementation;
711706f2543Smrg
712706f2543Smrg    for (ki = kdKeyboards; ki; ki = ki->next) {
713706f2543Smrg        if (ki->dixdev && ki->dixdev->id == pDevice->id)
714706f2543Smrg            break;
715706f2543Smrg    }
716706f2543Smrg
717706f2543Smrg    if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id) {
718706f2543Smrg        return BadImplementation;
719706f2543Smrg    }
720706f2543Smrg
721706f2543Smrg    switch (onoff)
722706f2543Smrg    {
723706f2543Smrg    case DEVICE_INIT:
724706f2543Smrg#ifdef DEBUG
725706f2543Smrg        ErrorF("initialising keyboard %s\n", ki->name);
726706f2543Smrg#endif
727706f2543Smrg        if (!ki->driver) {
728706f2543Smrg            if (!ki->driverPrivate) {
729706f2543Smrg                ErrorF("no driver specified!\n");
730706f2543Smrg                return BadImplementation;
731706f2543Smrg            }
732706f2543Smrg
733706f2543Smrg            ki->driver = KdFindKeyboardDriver(ki->driverPrivate);
734706f2543Smrg            if (!ki->driver) {
735706f2543Smrg                ErrorF("Couldn't find keyboard driver %s\n",
736706f2543Smrg                       ki->driverPrivate ? (char *) ki->driverPrivate :
737706f2543Smrg                       "(unnamed)");
738706f2543Smrg                return !Success;
739706f2543Smrg            }
740706f2543Smrg            free(ki->driverPrivate);
741706f2543Smrg            ki->driverPrivate = NULL;
742706f2543Smrg        }
743706f2543Smrg
744706f2543Smrg        if (!ki->driver->Init) {
745706f2543Smrg            ErrorF("Keyboard %s: no init function\n", ki->name);
746706f2543Smrg            return BadImplementation;
747706f2543Smrg        }
748706f2543Smrg
749706f2543Smrg        if ((*ki->driver->Init) (ki) != Success) {
750706f2543Smrg            return !Success;
751706f2543Smrg        }
752706f2543Smrg
753706f2543Smrg        memset(&rmlvo, 0, sizeof(rmlvo));
754706f2543Smrg        rmlvo.rules = ki->xkbRules;
755706f2543Smrg        rmlvo.model = ki->xkbModel;
756706f2543Smrg        rmlvo.layout = ki->xkbLayout;
757706f2543Smrg        rmlvo.variant = ki->xkbVariant;
758706f2543Smrg        rmlvo.options = ki->xkbOptions;
759706f2543Smrg        ret = InitKeyboardDeviceStruct (pDevice, &rmlvo, KdBell, KdKbdCtrl);
760706f2543Smrg	if (!ret) {
761706f2543Smrg            ErrorF("Couldn't initialise keyboard %s\n", ki->name);
762706f2543Smrg	    return BadImplementation;
763706f2543Smrg        }
764706f2543Smrg
765706f2543Smrg        xiclass = AtomFromName(XI_KEYBOARD);
766706f2543Smrg        AssignTypeAndName(pDevice, xiclass,
767706f2543Smrg                          ki->name ? ki->name : "Generic KDrive Keyboard");
768706f2543Smrg
769706f2543Smrg        KdResetInputMachine();
770706f2543Smrg
771706f2543Smrg        return Success;
772706f2543Smrg
773706f2543Smrg    case DEVICE_ON:
774706f2543Smrg        if (pDev->on == TRUE)
775706f2543Smrg            return Success;
776706f2543Smrg
777706f2543Smrg        if (!ki->driver->Enable)
778706f2543Smrg            return BadImplementation;
779706f2543Smrg
780706f2543Smrg        if ((*ki->driver->Enable) (ki) != Success) {
781706f2543Smrg            return BadMatch;
782706f2543Smrg        }
783706f2543Smrg
784706f2543Smrg        pDev->on = TRUE;
785706f2543Smrg        return Success;
786706f2543Smrg
787706f2543Smrg    case DEVICE_OFF:
788706f2543Smrg        if (pDev->on == FALSE)
789706f2543Smrg            return Success;
790706f2543Smrg
791706f2543Smrg        if (!ki->driver->Disable)
792706f2543Smrg            return BadImplementation;
793706f2543Smrg
794706f2543Smrg        (*ki->driver->Disable) (ki);
795706f2543Smrg        pDev->on = FALSE;
796706f2543Smrg
797706f2543Smrg        return Success;
798706f2543Smrg
799706f2543Smrg        break;
800706f2543Smrg
801706f2543Smrg    case DEVICE_CLOSE:
802706f2543Smrg	if (pDev->on) {
803706f2543Smrg            if (!ki->driver->Disable)
804706f2543Smrg                return BadImplementation;
805706f2543Smrg
806706f2543Smrg            (*ki->driver->Disable) (ki);
807706f2543Smrg            pDev->on = FALSE;
808706f2543Smrg	}
809706f2543Smrg
810706f2543Smrg        if (!ki->driver->Fini)
811706f2543Smrg            return BadImplementation;
812706f2543Smrg
813706f2543Smrg        (*ki->driver->Fini) (ki);
814706f2543Smrg
815706f2543Smrg        KdRemoveKeyboard(ki);
816706f2543Smrg
817706f2543Smrg        return Success;
818706f2543Smrg    }
819706f2543Smrg
820706f2543Smrg    /* NOTREACHED */
821706f2543Smrg    return BadImplementation;
822706f2543Smrg}
823706f2543Smrg
824706f2543Smrgvoid
825706f2543SmrgKdAddPointerDriver (KdPointerDriver *driver)
826706f2543Smrg{
827706f2543Smrg    KdPointerDriver **prev;
828706f2543Smrg
829706f2543Smrg    if (!driver)
830706f2543Smrg        return;
831706f2543Smrg
832706f2543Smrg    for (prev = &kdPointerDrivers; *prev; prev = &(*prev)->next) {
833706f2543Smrg        if (*prev == driver)
834706f2543Smrg            return;
835706f2543Smrg    }
836706f2543Smrg    *prev = driver;
837706f2543Smrg}
838706f2543Smrg
839706f2543Smrgvoid
840706f2543SmrgKdRemovePointerDriver (KdPointerDriver *driver)
841706f2543Smrg{
842706f2543Smrg    KdPointerDriver *tmp;
843706f2543Smrg
844706f2543Smrg    if (!driver)
845706f2543Smrg        return;
846706f2543Smrg
847706f2543Smrg    /* FIXME remove all pointers using this driver */
848706f2543Smrg    for (tmp = kdPointerDrivers; tmp; tmp = tmp->next) {
849706f2543Smrg        if (tmp->next == driver)
850706f2543Smrg            tmp->next = driver->next;
851706f2543Smrg    }
852706f2543Smrg    if (tmp == driver)
853706f2543Smrg        tmp = NULL;
854706f2543Smrg}
855706f2543Smrg
856706f2543Smrgvoid
857706f2543SmrgKdAddKeyboardDriver (KdKeyboardDriver *driver)
858706f2543Smrg{
859706f2543Smrg    KdKeyboardDriver **prev;
860706f2543Smrg
861706f2543Smrg    if (!driver)
862706f2543Smrg        return;
863706f2543Smrg
864706f2543Smrg    for (prev = &kdKeyboardDrivers; *prev; prev = &(*prev)->next) {
865706f2543Smrg        if (*prev == driver)
866706f2543Smrg            return;
867706f2543Smrg    }
868706f2543Smrg    *prev = driver;
869706f2543Smrg}
870706f2543Smrg
871706f2543Smrgvoid
872706f2543SmrgKdRemoveKeyboardDriver (KdKeyboardDriver *driver)
873706f2543Smrg{
874706f2543Smrg    KdKeyboardDriver *tmp;
875706f2543Smrg
876706f2543Smrg    if (!driver)
877706f2543Smrg        return;
878706f2543Smrg
879706f2543Smrg    /* FIXME remove all keyboards using this driver */
880706f2543Smrg    for (tmp = kdKeyboardDrivers; tmp; tmp = tmp->next) {
881706f2543Smrg        if (tmp->next == driver)
882706f2543Smrg            tmp->next = driver->next;
883706f2543Smrg    }
884706f2543Smrg    if (tmp == driver)
885706f2543Smrg        tmp = NULL;
886706f2543Smrg}
887706f2543Smrg
888706f2543SmrgKdKeyboardInfo *
889706f2543SmrgKdNewKeyboard (void)
890706f2543Smrg{
891706f2543Smrg    KdKeyboardInfo *ki = calloc(sizeof(KdKeyboardInfo), 1);
892706f2543Smrg    if (!ki)
893706f2543Smrg        return NULL;
894706f2543Smrg
895706f2543Smrg    ki->minScanCode = 0;
896706f2543Smrg    ki->maxScanCode = 0;
897706f2543Smrg    ki->leds = 0;
898706f2543Smrg    ki->bellPitch = 1000;
899706f2543Smrg    ki->bellDuration = 200;
900706f2543Smrg    ki->next = NULL;
901706f2543Smrg    ki->options = NULL;
902706f2543Smrg    ki->xkbRules = strdup(XKB_DFLT_RULES);
903706f2543Smrg    ki->xkbModel = strdup(XKB_DFLT_MODEL);
904706f2543Smrg    ki->xkbLayout = strdup(XKB_DFLT_LAYOUT);
905706f2543Smrg    ki->xkbVariant = strdup(XKB_DFLT_VARIANT);
906706f2543Smrg    ki->xkbOptions = strdup(XKB_DFLT_OPTIONS);
907706f2543Smrg
908706f2543Smrg    return ki;
909706f2543Smrg}
910706f2543Smrg
911706f2543Smrgint
912706f2543SmrgKdAddConfigKeyboard (char *keyboard)
913706f2543Smrg{
914706f2543Smrg    struct KdConfigDevice **prev, *new;
915706f2543Smrg
916706f2543Smrg    if (!keyboard)
917706f2543Smrg        return Success;
918706f2543Smrg
919706f2543Smrg    new = (struct KdConfigDevice *) calloc(sizeof(struct KdConfigDevice), 1);
920706f2543Smrg    if (!new)
921706f2543Smrg        return BadAlloc;
922706f2543Smrg
923706f2543Smrg    new->line = strdup(keyboard);
924706f2543Smrg    new->next = NULL;
925706f2543Smrg
926706f2543Smrg    for (prev = &kdConfigKeyboards; *prev; prev = &(*prev)->next);
927706f2543Smrg    *prev = new;
928706f2543Smrg
929706f2543Smrg    return Success;
930706f2543Smrg}
931706f2543Smrg
932706f2543Smrgint
933706f2543SmrgKdAddKeyboard (KdKeyboardInfo *ki)
934706f2543Smrg{
935706f2543Smrg    KdKeyboardInfo **prev;
936706f2543Smrg
937706f2543Smrg    if (!ki)
938706f2543Smrg        return !Success;
939706f2543Smrg
940706f2543Smrg    ki->dixdev = AddInputDevice(serverClient, KdKeyboardProc, TRUE);
941706f2543Smrg    if (!ki->dixdev) {
942706f2543Smrg        ErrorF("Couldn't register keyboard device %s\n",
943706f2543Smrg               ki->name ? ki->name : "(unnamed)");
944706f2543Smrg        return !Success;
945706f2543Smrg    }
946706f2543Smrg
947706f2543Smrg#ifdef DEBUG
948706f2543Smrg    ErrorF("added keyboard %s with dix id %d\n", ki->name, ki->dixdev->id);
949706f2543Smrg#endif
950706f2543Smrg
951706f2543Smrg    for (prev = &kdKeyboards; *prev; prev = &(*prev)->next);
952706f2543Smrg    *prev = ki;
953706f2543Smrg
954706f2543Smrg    return Success;
955706f2543Smrg}
956706f2543Smrg
957706f2543Smrgvoid
958706f2543SmrgKdRemoveKeyboard (KdKeyboardInfo *ki)
959706f2543Smrg{
960706f2543Smrg    KdKeyboardInfo **prev;
961706f2543Smrg
962706f2543Smrg    if (!ki)
963706f2543Smrg        return;
964706f2543Smrg
965706f2543Smrg    for (prev = &kdKeyboards; *prev; prev = &(*prev)->next) {
966706f2543Smrg        if (*prev == ki) {
967706f2543Smrg            *prev = ki->next;
968706f2543Smrg            break;
969706f2543Smrg        }
970706f2543Smrg    }
971706f2543Smrg
972706f2543Smrg    KdFreeKeyboard(ki);
973706f2543Smrg}
974706f2543Smrg
975706f2543Smrgint
976706f2543SmrgKdAddConfigPointer (char *pointer)
977706f2543Smrg{
978706f2543Smrg    struct KdConfigDevice **prev, *new;
979706f2543Smrg
980706f2543Smrg    if (!pointer)
981706f2543Smrg        return Success;
982706f2543Smrg
983706f2543Smrg    new = (struct KdConfigDevice *) calloc(sizeof(struct KdConfigDevice), 1);
984706f2543Smrg    if (!new)
985706f2543Smrg        return BadAlloc;
986706f2543Smrg
987706f2543Smrg    new->line = strdup(pointer);
988706f2543Smrg    new->next = NULL;
989706f2543Smrg
990706f2543Smrg    for (prev = &kdConfigPointers; *prev; prev = &(*prev)->next);
991706f2543Smrg    *prev = new;
992706f2543Smrg
993706f2543Smrg    return Success;
994706f2543Smrg}
995706f2543Smrg
996706f2543Smrgint
997706f2543SmrgKdAddPointer (KdPointerInfo *pi)
998706f2543Smrg{
999706f2543Smrg    KdPointerInfo **prev;
1000706f2543Smrg
1001706f2543Smrg    if (!pi)
1002706f2543Smrg        return Success;
1003706f2543Smrg
1004706f2543Smrg    pi->mouseState = start;
1005706f2543Smrg    pi->eventHeld = FALSE;
1006706f2543Smrg
1007706f2543Smrg    pi->dixdev = AddInputDevice(serverClient, KdPointerProc, TRUE);
1008706f2543Smrg    if (!pi->dixdev) {
1009706f2543Smrg        ErrorF("Couldn't add pointer device %s\n",
1010706f2543Smrg               pi->name ? pi->name : "(unnamed)");
1011706f2543Smrg        return BadDevice;
1012706f2543Smrg    }
1013706f2543Smrg
1014706f2543Smrg    for (prev = &kdPointers; *prev; prev = &(*prev)->next);
1015706f2543Smrg    *prev = pi;
1016706f2543Smrg
1017706f2543Smrg    return Success;
1018706f2543Smrg}
1019706f2543Smrg
1020706f2543Smrgvoid
1021706f2543SmrgKdRemovePointer (KdPointerInfo *pi)
1022706f2543Smrg{
1023706f2543Smrg    KdPointerInfo **prev;
1024706f2543Smrg
1025706f2543Smrg    if (!pi)
1026706f2543Smrg        return;
1027706f2543Smrg
1028706f2543Smrg    for (prev = &kdPointers; *prev; prev = &(*prev)->next) {
1029706f2543Smrg        if (*prev == pi) {
1030706f2543Smrg            *prev = pi->next;
1031706f2543Smrg            break;
1032706f2543Smrg        }
1033706f2543Smrg    }
1034706f2543Smrg
1035706f2543Smrg    KdFreePointer(pi);
1036706f2543Smrg}
1037706f2543Smrg
1038706f2543Smrg/*
1039706f2543Smrg * You can call your kdriver server with something like:
1040706f2543Smrg * $ ./hw/kdrive/yourserver/X :1 -mouse evdev,,device=/dev/input/event4 -keybd
1041706f2543Smrg * evdev,,device=/dev/input/event1,xkbmodel=abnt2,xkblayout=br
1042706f2543Smrg */
1043706f2543Smrgstatic Bool
1044706f2543SmrgKdGetOptions (InputOption **options, char *string)
1045706f2543Smrg{
1046706f2543Smrg    InputOption     *newopt = NULL, **tmpo = NULL;
1047706f2543Smrg    int             tam_key = 0;
1048706f2543Smrg
1049706f2543Smrg    newopt = calloc(1, sizeof (InputOption));
1050706f2543Smrg    if (!newopt)
1051706f2543Smrg        return FALSE;
1052706f2543Smrg
1053706f2543Smrg    for (tmpo = options; *tmpo; tmpo = &(*tmpo)->next)
1054706f2543Smrg        ; /* Hello, I'm here */
1055706f2543Smrg    *tmpo = newopt;
1056706f2543Smrg
1057706f2543Smrg    if (strchr(string, '='))
1058706f2543Smrg    {
1059706f2543Smrg        tam_key = (strchr(string, '=') - string);
1060706f2543Smrg        newopt->key = (char *)malloc(tam_key);
1061706f2543Smrg        strncpy(newopt->key, string, tam_key);
1062706f2543Smrg        newopt->key[tam_key] = '\0';
1063706f2543Smrg        newopt->value = strdup(strchr(string, '=') + 1);
1064706f2543Smrg    }
1065706f2543Smrg    else
1066706f2543Smrg    {
1067706f2543Smrg        newopt->key = strdup(string);
1068706f2543Smrg        newopt->value = NULL;
1069706f2543Smrg    }
1070706f2543Smrg    newopt->next = NULL;
1071706f2543Smrg
1072706f2543Smrg    return TRUE;
1073706f2543Smrg}
1074706f2543Smrg
1075706f2543Smrgstatic void
1076706f2543SmrgKdParseKbdOptions (KdKeyboardInfo *ki)
1077706f2543Smrg{
1078706f2543Smrg    InputOption *option = NULL;
1079706f2543Smrg
1080706f2543Smrg    for (option = ki->options; option; option = option->next)
1081706f2543Smrg    {
1082706f2543Smrg        if (strcasecmp(option->key, "XkbRules") == 0)
1083706f2543Smrg            ki->xkbRules = option->value;
1084706f2543Smrg        else if (strcasecmp(option->key, "XkbModel") == 0)
1085706f2543Smrg            ki->xkbModel = option->value;
1086706f2543Smrg        else if (strcasecmp(option->key, "XkbLayout") == 0)
1087706f2543Smrg            ki->xkbLayout = option->value;
1088706f2543Smrg        else if (strcasecmp(option->key, "XkbVariant") == 0)
1089706f2543Smrg            ki->xkbVariant = option->value;
1090706f2543Smrg        else if (strcasecmp(option->key, "XkbOptions") == 0)
1091706f2543Smrg            ki->xkbOptions = option->value;
1092706f2543Smrg        else if (!strcasecmp (option->key, "device"))
1093706f2543Smrg            ki->path = strdup(option->value);
1094706f2543Smrg        else
1095706f2543Smrg           ErrorF("Kbd option key (%s) of value (%s) not assigned!\n",
1096706f2543Smrg                    option->key, option->value);
1097706f2543Smrg    }
1098706f2543Smrg}
1099706f2543Smrg
1100706f2543SmrgKdKeyboardInfo *
1101706f2543SmrgKdParseKeyboard (char *arg)
1102706f2543Smrg{
1103706f2543Smrg    char            save[1024];
1104706f2543Smrg    char            delim;
1105706f2543Smrg    InputOption     *options = NULL;
1106706f2543Smrg    KdKeyboardInfo     *ki = NULL;
1107706f2543Smrg
1108706f2543Smrg    ki = KdNewKeyboard();
1109706f2543Smrg    if (!ki)
1110706f2543Smrg        return NULL;
1111706f2543Smrg
1112706f2543Smrg    ki->name = strdup("Unknown KDrive Keyboard");
1113706f2543Smrg    ki->path = NULL;
1114706f2543Smrg    ki->driver = NULL;
1115706f2543Smrg    ki->driverPrivate = NULL;
1116706f2543Smrg    ki->next = NULL;
1117706f2543Smrg
1118706f2543Smrg    if (!arg)
1119706f2543Smrg    {
1120706f2543Smrg        ErrorF("keybd: no arg\n");
1121706f2543Smrg        KdFreeKeyboard (ki);
1122706f2543Smrg        return NULL;
1123706f2543Smrg    }
1124706f2543Smrg
1125706f2543Smrg    if (strlen (arg) >= sizeof (save))
1126706f2543Smrg    {
1127706f2543Smrg        ErrorF("keybd: arg too long\n");
1128706f2543Smrg        KdFreeKeyboard (ki);
1129706f2543Smrg        return NULL;
1130706f2543Smrg    }
1131706f2543Smrg
1132706f2543Smrg    arg = KdParseFindNext (arg, ",", save, &delim);
1133706f2543Smrg    if (!save[0])
1134706f2543Smrg    {
1135706f2543Smrg        ErrorF("keybd: failed on save[0]\n");
1136706f2543Smrg        KdFreeKeyboard (ki);
1137706f2543Smrg        return NULL;
1138706f2543Smrg    }
1139706f2543Smrg
1140706f2543Smrg    if (strcmp (save, "auto") == 0)
1141706f2543Smrg        ki->driverPrivate = NULL;
1142706f2543Smrg    else
1143706f2543Smrg        ki->driverPrivate = strdup(save);
1144706f2543Smrg
1145706f2543Smrg    if (delim != ',')
1146706f2543Smrg    {
1147706f2543Smrg        return ki;
1148706f2543Smrg    }
1149706f2543Smrg
1150706f2543Smrg    arg = KdParseFindNext (arg, ",", save, &delim);
1151706f2543Smrg
1152706f2543Smrg    while (delim == ',')
1153706f2543Smrg    {
1154706f2543Smrg        arg = KdParseFindNext (arg, ",", save, &delim);
1155706f2543Smrg
1156706f2543Smrg	if (!KdGetOptions(&options, save))
1157706f2543Smrg	{
1158706f2543Smrg	    KdFreeKeyboard(ki);
1159706f2543Smrg	    return NULL;
1160706f2543Smrg        }
1161706f2543Smrg    }
1162706f2543Smrg
1163706f2543Smrg    if (options)
1164706f2543Smrg    {
1165706f2543Smrg        ki->options = options;
1166706f2543Smrg        KdParseKbdOptions(ki);
1167706f2543Smrg    }
1168706f2543Smrg
1169706f2543Smrg    return ki;
1170706f2543Smrg}
1171706f2543Smrg
1172706f2543Smrgstatic void
1173706f2543SmrgKdParsePointerOptions (KdPointerInfo *pi)
1174706f2543Smrg{
1175706f2543Smrg    InputOption *option = NULL;
1176706f2543Smrg
1177706f2543Smrg    for (option = pi->options; option; option = option->next)
1178706f2543Smrg    {
1179706f2543Smrg        if (!strcmp (option->key, "emulatemiddle"))
1180706f2543Smrg            pi->emulateMiddleButton = TRUE;
1181706f2543Smrg        else if (!strcmp (option->key, "noemulatemiddle"))
1182706f2543Smrg            pi->emulateMiddleButton = FALSE;
1183706f2543Smrg        else if (!strcmp (option->key, "transformcoord"))
1184706f2543Smrg            pi->transformCoordinates = TRUE;
1185706f2543Smrg        else if (!strcmp (option->key, "rawcoord"))
1186706f2543Smrg            pi->transformCoordinates = FALSE;
1187706f2543Smrg        else if (!strcasecmp (option->key, "device"))
1188706f2543Smrg            pi->path = strdup(option->value);
1189706f2543Smrg        else if (!strcasecmp (option->key, "protocol"))
1190706f2543Smrg            pi->protocol = strdup(option->value);
1191706f2543Smrg        else
1192706f2543Smrg            ErrorF("Pointer option key (%s) of value (%s) not assigned!\n",
1193706f2543Smrg                    option->key, option->value);
1194706f2543Smrg    }
1195706f2543Smrg}
1196706f2543Smrg
1197706f2543SmrgKdPointerInfo *
1198706f2543SmrgKdParsePointer (char *arg)
1199706f2543Smrg{
1200706f2543Smrg    char            save[1024];
1201706f2543Smrg    char            delim;
1202706f2543Smrg    KdPointerInfo   *pi = NULL;
1203706f2543Smrg    InputOption     *options = NULL;
1204706f2543Smrg    int             i = 0;
1205706f2543Smrg
1206706f2543Smrg    pi = KdNewPointer();
1207706f2543Smrg    if (!pi)
1208706f2543Smrg        return NULL;
1209706f2543Smrg    pi->emulateMiddleButton = kdEmulateMiddleButton;
1210706f2543Smrg    pi->transformCoordinates = !kdRawPointerCoordinates;
1211706f2543Smrg    pi->protocol = NULL;
1212706f2543Smrg    pi->nButtons = 5; /* XXX should not be hardcoded */
1213706f2543Smrg    pi->inputClass = KD_MOUSE;
1214706f2543Smrg
1215706f2543Smrg    if (!arg)
1216706f2543Smrg    {
1217706f2543Smrg        ErrorF("mouse: no arg\n");
1218706f2543Smrg        KdFreePointer (pi);
1219706f2543Smrg        return NULL;
1220706f2543Smrg    }
1221706f2543Smrg
1222706f2543Smrg    if (strlen (arg) >= sizeof (save))
1223706f2543Smrg    {
1224706f2543Smrg        ErrorF("mouse: arg too long\n");
1225706f2543Smrg        KdFreePointer (pi);
1226706f2543Smrg        return NULL;
1227706f2543Smrg    }
1228706f2543Smrg    arg = KdParseFindNext (arg, ",", save, &delim);
1229706f2543Smrg    if (!save[0])
1230706f2543Smrg    {
1231706f2543Smrg        ErrorF("failed on save[0]\n");
1232706f2543Smrg        KdFreePointer (pi);
1233706f2543Smrg        return NULL;
1234706f2543Smrg    }
1235706f2543Smrg
1236706f2543Smrg    if (strcmp(save, "auto") == 0)
1237706f2543Smrg        pi->driverPrivate = NULL;
1238706f2543Smrg    else
1239706f2543Smrg        pi->driverPrivate = strdup(save);
1240706f2543Smrg
1241706f2543Smrg    if (delim != ',')
1242706f2543Smrg    {
1243706f2543Smrg        return pi;
1244706f2543Smrg    }
1245706f2543Smrg
1246706f2543Smrg    arg = KdParseFindNext (arg, ",", save, &delim);
1247706f2543Smrg
1248706f2543Smrg    while (delim == ',')
1249706f2543Smrg    {
1250706f2543Smrg        arg = KdParseFindNext (arg, ",", save, &delim);
1251706f2543Smrg        if (save[0] == '{')
1252706f2543Smrg        {
1253706f2543Smrg            char *s = save + 1;
1254706f2543Smrg             i = 0;
1255706f2543Smrg             while (*s && *s != '}')
1256706f2543Smrg             {
1257706f2543Smrg                if ('1' <= *s && *s <= '0' + pi->nButtons)
1258706f2543Smrg                    pi->map[i] = *s - '0';
1259706f2543Smrg                else
1260706f2543Smrg                    UseMsg ();
1261706f2543Smrg                s++;
1262706f2543Smrg             }
1263706f2543Smrg        }
1264706f2543Smrg        else
1265706f2543Smrg        {
1266706f2543Smrg            if (!KdGetOptions(&options, save))
1267706f2543Smrg            {
1268706f2543Smrg                KdFreePointer(pi);
1269706f2543Smrg                return NULL;
1270706f2543Smrg            }
1271706f2543Smrg        }
1272706f2543Smrg    }
1273706f2543Smrg
1274706f2543Smrg    if (options)
1275706f2543Smrg    {
1276706f2543Smrg        pi->options = options;
1277706f2543Smrg        KdParsePointerOptions(pi);
1278706f2543Smrg    }
1279706f2543Smrg
1280706f2543Smrg    return pi;
1281706f2543Smrg}
1282706f2543Smrg
1283706f2543Smrg
1284706f2543Smrgvoid
1285706f2543SmrgKdInitInput (void)
1286706f2543Smrg{
1287706f2543Smrg    KdPointerInfo *pi;
1288706f2543Smrg    KdKeyboardInfo *ki;
1289706f2543Smrg    struct KdConfigDevice *dev;
1290706f2543Smrg
1291706f2543Smrg    kdInputEnabled = TRUE;
1292706f2543Smrg
1293706f2543Smrg    for (dev = kdConfigPointers; dev; dev = dev->next) {
1294706f2543Smrg        pi = KdParsePointer(dev->line);
1295706f2543Smrg        if (!pi)
1296706f2543Smrg            ErrorF("Failed to parse pointer\n");
1297706f2543Smrg        if (KdAddPointer(pi) != Success)
1298706f2543Smrg            ErrorF("Failed to add pointer!\n");
1299706f2543Smrg    }
1300706f2543Smrg    for (dev = kdConfigKeyboards; dev; dev = dev->next) {
1301706f2543Smrg        ki = KdParseKeyboard(dev->line);
1302706f2543Smrg        if (!ki)
1303706f2543Smrg            ErrorF("Failed to parse keyboard\n");
1304706f2543Smrg        if (KdAddKeyboard(ki) != Success)
1305706f2543Smrg            ErrorF("Failed to add keyboard!\n");
1306706f2543Smrg    }
1307706f2543Smrg
1308706f2543Smrg    mieqInit();
1309706f2543Smrg}
1310706f2543Smrg
1311706f2543Smrg/*
1312706f2543Smrg * Middle button emulation state machine
1313706f2543Smrg *
1314706f2543Smrg *  Possible transitions:
1315706f2543Smrg *	Button 1 press	    v1
1316706f2543Smrg *	Button 1 release    ^1
1317706f2543Smrg *	Button 2 press	    v2
1318706f2543Smrg *	Button 2 release    ^2
1319706f2543Smrg *	Button 3 press	    v3
1320706f2543Smrg *	Button 3 release    ^3
1321706f2543Smrg *	Button other press  vo
1322706f2543Smrg *	Button other release ^o
1323706f2543Smrg *	Mouse motion	    <>
1324706f2543Smrg *	Keyboard event	    k
1325706f2543Smrg *	timeout		    ...
1326706f2543Smrg *	outside box	    <->
1327706f2543Smrg *
1328706f2543Smrg *  States:
1329706f2543Smrg *	start
1330706f2543Smrg *	button_1_pend
1331706f2543Smrg *	button_1_down
1332706f2543Smrg *	button_2_down
1333706f2543Smrg *	button_3_pend
1334706f2543Smrg *	button_3_down
1335706f2543Smrg *	synthetic_2_down_13
1336706f2543Smrg *	synthetic_2_down_3
1337706f2543Smrg *	synthetic_2_down_1
1338706f2543Smrg *
1339706f2543Smrg *  Transition diagram
1340706f2543Smrg *
1341706f2543Smrg *  start
1342706f2543Smrg *	v1  -> (hold) (settimeout) button_1_pend
1343706f2543Smrg *	^1  -> (deliver) start
1344706f2543Smrg *	v2  -> (deliver) button_2_down
1345706f2543Smrg *	^2  -> (deliever) start
1346706f2543Smrg *	v3  -> (hold) (settimeout) button_3_pend
1347706f2543Smrg *	^3  -> (deliver) start
1348706f2543Smrg *	vo  -> (deliver) start
1349706f2543Smrg *	^o  -> (deliver) start
1350706f2543Smrg *	<>  -> (deliver) start
1351706f2543Smrg *	k   -> (deliver) start
1352706f2543Smrg *
1353706f2543Smrg *  button_1_pend	(button 1 is down, timeout pending)
1354706f2543Smrg *	^1  -> (release) (deliver) start
1355706f2543Smrg *	v2  -> (release) (deliver) button_1_down
1356706f2543Smrg *	^2  -> (release) (deliver) button_1_down
1357706f2543Smrg *	v3  -> (cleartimeout) (generate v2) synthetic_2_down_13
1358706f2543Smrg *	^3  -> (release) (deliver) button_1_down
1359706f2543Smrg *	vo  -> (release) (deliver) button_1_down
1360706f2543Smrg *	^o  -> (release) (deliver) button_1_down
1361706f2543Smrg *	<-> -> (release) (deliver) button_1_down
1362706f2543Smrg *	<>  -> (deliver) button_1_pend
1363706f2543Smrg *	k   -> (release) (deliver) button_1_down
1364706f2543Smrg *	... -> (release) button_1_down
1365706f2543Smrg *
1366706f2543Smrg *  button_1_down	(button 1 is down)
1367706f2543Smrg *	^1  -> (deliver) start
1368706f2543Smrg *	v2  -> (deliver) button_1_down
1369706f2543Smrg *	^2  -> (deliver) button_1_down
1370706f2543Smrg *	v3  -> (deliver) button_1_down
1371706f2543Smrg *	^3  -> (deliver) button_1_down
1372706f2543Smrg *	vo  -> (deliver) button_1_down
1373706f2543Smrg *	^o  -> (deliver) button_1_down
1374706f2543Smrg *	<>  -> (deliver) button_1_down
1375706f2543Smrg *	k   -> (deliver) button_1_down
1376706f2543Smrg *
1377706f2543Smrg *  button_2_down	(button 2 is down)
1378706f2543Smrg *	v1  -> (deliver) button_2_down
1379706f2543Smrg *	^1  -> (deliver) button_2_down
1380706f2543Smrg *	^2  -> (deliver) start
1381706f2543Smrg *	v3  -> (deliver) button_2_down
1382706f2543Smrg *	^3  -> (deliver) button_2_down
1383706f2543Smrg *	vo  -> (deliver) button_2_down
1384706f2543Smrg *	^o  -> (deliver) button_2_down
1385706f2543Smrg *	<>  -> (deliver) button_2_down
1386706f2543Smrg *	k   -> (deliver) button_2_down
1387706f2543Smrg *
1388706f2543Smrg *  button_3_pend	(button 3 is down, timeout pending)
1389706f2543Smrg *	v1  -> (generate v2) synthetic_2_down
1390706f2543Smrg *	^1  -> (release) (deliver) button_3_down
1391706f2543Smrg *	v2  -> (release) (deliver) button_3_down
1392706f2543Smrg *	^2  -> (release) (deliver) button_3_down
1393706f2543Smrg *	^3  -> (release) (deliver) start
1394706f2543Smrg *	vo  -> (release) (deliver) button_3_down
1395706f2543Smrg *	^o  -> (release) (deliver) button_3_down
1396706f2543Smrg *	<-> -> (release) (deliver) button_3_down
1397706f2543Smrg *	<>  -> (deliver) button_3_pend
1398706f2543Smrg *	k   -> (release) (deliver) button_3_down
1399706f2543Smrg *	... -> (release) button_3_down
1400706f2543Smrg *
1401706f2543Smrg *  button_3_down	(button 3 is down)
1402706f2543Smrg *	v1  -> (deliver) button_3_down
1403706f2543Smrg *	^1  -> (deliver) button_3_down
1404706f2543Smrg *	v2  -> (deliver) button_3_down
1405706f2543Smrg *	^2  -> (deliver) button_3_down
1406706f2543Smrg *	^3  -> (deliver) start
1407706f2543Smrg *	vo  -> (deliver) button_3_down
1408706f2543Smrg *	^o  -> (deliver) button_3_down
1409706f2543Smrg *	<>  -> (deliver) button_3_down
1410706f2543Smrg *	k   -> (deliver) button_3_down
1411706f2543Smrg *
1412706f2543Smrg *  synthetic_2_down_13	(button 1 and 3 are down)
1413706f2543Smrg *	^1  -> (generate ^2) synthetic_2_down_3
1414706f2543Smrg *	v2  -> synthetic_2_down_13
1415706f2543Smrg *	^2  -> synthetic_2_down_13
1416706f2543Smrg *	^3  -> (generate ^2) synthetic_2_down_1
1417706f2543Smrg *	vo  -> (deliver) synthetic_2_down_13
1418706f2543Smrg *	^o  -> (deliver) synthetic_2_down_13
1419706f2543Smrg *	<>  -> (deliver) synthetic_2_down_13
1420706f2543Smrg *	k   -> (deliver) synthetic_2_down_13
1421706f2543Smrg *
1422706f2543Smrg *  synthetic_2_down_3 (button 3 is down)
1423706f2543Smrg *	v1  -> (deliver) synthetic_2_down_3
1424706f2543Smrg *	^1  -> (deliver) synthetic_2_down_3
1425706f2543Smrg *	v2  -> synthetic_2_down_3
1426706f2543Smrg *	^2  -> synthetic_2_down_3
1427706f2543Smrg *	^3  -> start
1428706f2543Smrg *	vo  -> (deliver) synthetic_2_down_3
1429706f2543Smrg *	^o  -> (deliver) synthetic_2_down_3
1430706f2543Smrg *	<>  -> (deliver) synthetic_2_down_3
1431706f2543Smrg *	k   -> (deliver) synthetic_2_down_3
1432706f2543Smrg *
1433706f2543Smrg *  synthetic_2_down_1 (button 1 is down)
1434706f2543Smrg *	^1  -> start
1435706f2543Smrg *	v2  -> synthetic_2_down_1
1436706f2543Smrg *	^2  -> synthetic_2_down_1
1437706f2543Smrg *	v3  -> (deliver) synthetic_2_down_1
1438706f2543Smrg *	^3  -> (deliver) synthetic_2_down_1
1439706f2543Smrg *	vo  -> (deliver) synthetic_2_down_1
1440706f2543Smrg *	^o  -> (deliver) synthetic_2_down_1
1441706f2543Smrg *	<>  -> (deliver) synthetic_2_down_1
1442706f2543Smrg *	k   -> (deliver) synthetic_2_down_1
1443706f2543Smrg */
1444706f2543Smrg
1445706f2543Smrgtypedef enum _inputClass {
1446706f2543Smrg    down_1, up_1,
1447706f2543Smrg    down_2, up_2,
1448706f2543Smrg    down_3, up_3,
1449706f2543Smrg    down_o, up_o,
1450706f2543Smrg    motion, outside_box,
1451706f2543Smrg    keyboard, timeout,
1452706f2543Smrg    num_input_class
1453706f2543Smrg} KdInputClass;
1454706f2543Smrg
1455706f2543Smrgtypedef enum _inputAction {
1456706f2543Smrg    noop,
1457706f2543Smrg    hold,
1458706f2543Smrg    setto,
1459706f2543Smrg    deliver,
1460706f2543Smrg    release,
1461706f2543Smrg    clearto,
1462706f2543Smrg    gen_down_2,
1463706f2543Smrg    gen_up_2
1464706f2543Smrg} KdInputAction;
1465706f2543Smrg
1466706f2543Smrg#define MAX_ACTIONS 2
1467706f2543Smrg
1468706f2543Smrgtypedef struct _inputTransition {
1469706f2543Smrg    KdInputAction  actions[MAX_ACTIONS];
1470706f2543Smrg    KdPointerState nextState;
1471706f2543Smrg} KdInputTransition;
1472706f2543Smrg
1473706f2543Smrgstatic const
1474706f2543SmrgKdInputTransition  kdInputMachine[num_input_states][num_input_class] = {
1475706f2543Smrg    /* start */
1476706f2543Smrg    {
1477706f2543Smrg	{ { hold, setto },	    button_1_pend },	/* v1 */
1478706f2543Smrg	{ { deliver, noop },	    start },		/* ^1 */
1479706f2543Smrg	{ { deliver, noop },	    button_2_down },	/* v2 */
1480706f2543Smrg	{ { deliver, noop },	    start },		/* ^2 */
1481706f2543Smrg	{ { hold, setto },	    button_3_pend },	/* v3 */
1482706f2543Smrg	{ { deliver, noop },	    start },		/* ^3 */
1483706f2543Smrg	{ { deliver, noop },	    start },		/* vo */
1484706f2543Smrg	{ { deliver, noop },	    start },		/* ^o */
1485706f2543Smrg	{ { deliver, noop },	    start },		/* <> */
1486706f2543Smrg	{ { deliver, noop },	    start },		/* <-> */
1487706f2543Smrg	{ { noop, noop },	    start },		/* k */
1488706f2543Smrg	{ { noop, noop },	    start },		/* ... */
1489706f2543Smrg    },
1490706f2543Smrg    /* button_1_pend */
1491706f2543Smrg    {
1492706f2543Smrg	{ { noop, noop },	    button_1_pend },	/* v1 */
1493706f2543Smrg	{ { release, deliver },	    start },		/* ^1 */
1494706f2543Smrg	{ { release, deliver },	    button_1_down },	/* v2 */
1495706f2543Smrg	{ { release, deliver },	    button_1_down },	/* ^2 */
1496706f2543Smrg	{ { clearto, gen_down_2 },  synth_2_down_13 },	/* v3 */
1497706f2543Smrg	{ { release, deliver },	    button_1_down },	/* ^3 */
1498706f2543Smrg	{ { release, deliver },	    button_1_down },	/* vo */
1499706f2543Smrg	{ { release, deliver },	    button_1_down },	/* ^o */
1500706f2543Smrg	{ { deliver, noop },	    button_1_pend },	/* <> */
1501706f2543Smrg	{ { release, deliver },	    button_1_down },	/* <-> */
1502706f2543Smrg	{ { noop, noop },	    button_1_down },	/* k */
1503706f2543Smrg	{ { release, noop },	    button_1_down },	/* ... */
1504706f2543Smrg    },
1505706f2543Smrg    /* button_1_down */
1506706f2543Smrg    {
1507706f2543Smrg	{ { noop, noop },	    button_1_down },	/* v1 */
1508706f2543Smrg	{ { deliver, noop },	    start },		/* ^1 */
1509706f2543Smrg	{ { deliver, noop },	    button_1_down },	/* v2 */
1510706f2543Smrg	{ { deliver, noop },	    button_1_down },	/* ^2 */
1511706f2543Smrg	{ { deliver, noop },	    button_1_down },	/* v3 */
1512706f2543Smrg	{ { deliver, noop },	    button_1_down },	/* ^3 */
1513706f2543Smrg	{ { deliver, noop },	    button_1_down },	/* vo */
1514706f2543Smrg	{ { deliver, noop },	    button_1_down },	/* ^o */
1515706f2543Smrg	{ { deliver, noop },	    button_1_down },	/* <> */
1516706f2543Smrg	{ { deliver, noop },	    button_1_down },	/* <-> */
1517706f2543Smrg	{ { noop, noop },	    button_1_down },	/* k */
1518706f2543Smrg	{ { noop, noop },	    button_1_down },	/* ... */
1519706f2543Smrg    },
1520706f2543Smrg    /* button_2_down */
1521706f2543Smrg    {
1522706f2543Smrg	{ { deliver, noop },	    button_2_down },	/* v1 */
1523706f2543Smrg	{ { deliver, noop },	    button_2_down },	/* ^1 */
1524706f2543Smrg	{ { noop, noop },	    button_2_down },	/* v2 */
1525706f2543Smrg	{ { deliver, noop },	    start },		/* ^2 */
1526706f2543Smrg	{ { deliver, noop },	    button_2_down },	/* v3 */
1527706f2543Smrg	{ { deliver, noop },	    button_2_down },	/* ^3 */
1528706f2543Smrg	{ { deliver, noop },	    button_2_down },	/* vo */
1529706f2543Smrg	{ { deliver, noop },	    button_2_down },	/* ^o */
1530706f2543Smrg	{ { deliver, noop },	    button_2_down },	/* <> */
1531706f2543Smrg	{ { deliver, noop },	    button_2_down },	/* <-> */
1532706f2543Smrg	{ { noop, noop },	    button_2_down },	/* k */
1533706f2543Smrg	{ { noop, noop },	    button_2_down },	/* ... */
1534706f2543Smrg    },
1535706f2543Smrg    /* button_3_pend */
1536706f2543Smrg    {
1537706f2543Smrg	{ { clearto, gen_down_2 },  synth_2_down_13 },	/* v1 */
1538706f2543Smrg	{ { release, deliver },	    button_3_down },	/* ^1 */
1539706f2543Smrg	{ { release, deliver },	    button_3_down },	/* v2 */
1540706f2543Smrg	{ { release, deliver },	    button_3_down },	/* ^2 */
1541706f2543Smrg	{ { release, deliver },	    button_3_down },	/* v3 */
1542706f2543Smrg	{ { release, deliver },	    start },		/* ^3 */
1543706f2543Smrg	{ { release, deliver },	    button_3_down },	/* vo */
1544706f2543Smrg	{ { release, deliver },	    button_3_down },	/* ^o */
1545706f2543Smrg	{ { deliver, noop },	    button_3_pend },	/* <> */
1546706f2543Smrg	{ { release, deliver },	    button_3_down },	/* <-> */
1547706f2543Smrg	{ { release, noop },	    button_3_down },	/* k */
1548706f2543Smrg	{ { release, noop },	    button_3_down },	/* ... */
1549706f2543Smrg    },
1550706f2543Smrg    /* button_3_down */
1551706f2543Smrg    {
1552706f2543Smrg	{ { deliver, noop },	    button_3_down },	/* v1 */
1553706f2543Smrg	{ { deliver, noop },	    button_3_down },	/* ^1 */
1554706f2543Smrg	{ { deliver, noop },	    button_3_down },	/* v2 */
1555706f2543Smrg	{ { deliver, noop },	    button_3_down },	/* ^2 */
1556706f2543Smrg	{ { noop, noop },	    button_3_down },	/* v3 */
1557706f2543Smrg	{ { deliver, noop },	    start },		/* ^3 */
1558706f2543Smrg	{ { deliver, noop },	    button_3_down },	/* vo */
1559706f2543Smrg	{ { deliver, noop },	    button_3_down },	/* ^o */
1560706f2543Smrg	{ { deliver, noop },	    button_3_down },	/* <> */
1561706f2543Smrg	{ { deliver, noop },	    button_3_down },	/* <-> */
1562706f2543Smrg	{ { noop, noop },	    button_3_down },	/* k */
1563706f2543Smrg	{ { noop, noop },	    button_3_down },	/* ... */
1564706f2543Smrg    },
1565706f2543Smrg    /* synthetic_2_down_13 */
1566706f2543Smrg    {
1567706f2543Smrg	{ { noop, noop },	    synth_2_down_13 },	/* v1 */
1568706f2543Smrg	{ { gen_up_2, noop },	    synth_2_down_3 },	/* ^1 */
1569706f2543Smrg	{ { noop, noop },	    synth_2_down_13 },	/* v2 */
1570706f2543Smrg	{ { noop, noop },	    synth_2_down_13 },	/* ^2 */
1571706f2543Smrg	{ { noop, noop },	    synth_2_down_13 },	/* v3 */
1572706f2543Smrg	{ { gen_up_2, noop },	    synth_2_down_1 },	/* ^3 */
1573706f2543Smrg	{ { deliver, noop },	    synth_2_down_13 },	/* vo */
1574706f2543Smrg	{ { deliver, noop },	    synth_2_down_13 },	/* ^o */
1575706f2543Smrg	{ { deliver, noop },	    synth_2_down_13 },	/* <> */
1576706f2543Smrg	{ { deliver, noop },	    synth_2_down_13 },	/* <-> */
1577706f2543Smrg	{ { noop, noop },	    synth_2_down_13 },	/* k */
1578706f2543Smrg	{ { noop, noop },	    synth_2_down_13 },	/* ... */
1579706f2543Smrg    },
1580706f2543Smrg    /* synthetic_2_down_3 */
1581706f2543Smrg    {
1582706f2543Smrg	{ { deliver, noop },	    synth_2_down_3 },	/* v1 */
1583706f2543Smrg	{ { deliver, noop },	    synth_2_down_3 },	/* ^1 */
1584706f2543Smrg	{ { deliver, noop },	    synth_2_down_3 },	/* v2 */
1585706f2543Smrg	{ { deliver, noop },	    synth_2_down_3 },	/* ^2 */
1586706f2543Smrg	{ { noop, noop },	    synth_2_down_3 },	/* v3 */
1587706f2543Smrg	{ { noop, noop },	    start },		/* ^3 */
1588706f2543Smrg	{ { deliver, noop },	    synth_2_down_3 },	/* vo */
1589706f2543Smrg	{ { deliver, noop },	    synth_2_down_3 },	/* ^o */
1590706f2543Smrg	{ { deliver, noop },	    synth_2_down_3 },	/* <> */
1591706f2543Smrg	{ { deliver, noop },	    synth_2_down_3 },	/* <-> */
1592706f2543Smrg	{ { noop, noop },	    synth_2_down_3 },	/* k */
1593706f2543Smrg	{ { noop, noop },	    synth_2_down_3 },	/* ... */
1594706f2543Smrg    },
1595706f2543Smrg    /* synthetic_2_down_1 */
1596706f2543Smrg    {
1597706f2543Smrg	{ { noop, noop },	    synth_2_down_1 },	/* v1 */
1598706f2543Smrg	{ { noop, noop },	    start },		/* ^1 */
1599706f2543Smrg	{ { deliver, noop },	    synth_2_down_1 },	/* v2 */
1600706f2543Smrg	{ { deliver, noop },	    synth_2_down_1 },	/* ^2 */
1601706f2543Smrg	{ { deliver, noop },	    synth_2_down_1 },	/* v3 */
1602706f2543Smrg	{ { deliver, noop },	    synth_2_down_1 },	/* ^3 */
1603706f2543Smrg	{ { deliver, noop },	    synth_2_down_1 },	/* vo */
1604706f2543Smrg	{ { deliver, noop },	    synth_2_down_1 },	/* ^o */
1605706f2543Smrg	{ { deliver, noop },	    synth_2_down_1 },	/* <> */
1606706f2543Smrg	{ { deliver, noop },	    synth_2_down_1 },	/* <-> */
1607706f2543Smrg	{ { noop, noop },	    synth_2_down_1 },	/* k */
1608706f2543Smrg	{ { noop, noop },	    synth_2_down_1 },	/* ... */
1609706f2543Smrg    },
1610706f2543Smrg};
1611706f2543Smrg
1612706f2543Smrg#define EMULATION_WINDOW    10
1613706f2543Smrg#define EMULATION_TIMEOUT   100
1614706f2543Smrg
1615706f2543Smrgstatic int
1616706f2543SmrgKdInsideEmulationWindow (KdPointerInfo *pi, int x, int y, int z)
1617706f2543Smrg{
1618706f2543Smrg    pi->emulationDx = pi->heldEvent.x - x;
1619706f2543Smrg    pi->emulationDy = pi->heldEvent.y - y;
1620706f2543Smrg
1621706f2543Smrg    return (abs (pi->emulationDx) < EMULATION_WINDOW &&
1622706f2543Smrg	    abs (pi->emulationDy) < EMULATION_WINDOW);
1623706f2543Smrg}
1624706f2543Smrg
1625706f2543Smrgstatic KdInputClass
1626706f2543SmrgKdClassifyInput (KdPointerInfo *pi, int type, int x, int y, int z, int b)
1627706f2543Smrg{
1628706f2543Smrg    switch (type) {
1629706f2543Smrg    case ButtonPress:
1630706f2543Smrg	switch (b) {
1631706f2543Smrg	case 1: return down_1;
1632706f2543Smrg	case 2: return down_2;
1633706f2543Smrg	case 3: return down_3;
1634706f2543Smrg	default: return down_o;
1635706f2543Smrg	}
1636706f2543Smrg	break;
1637706f2543Smrg    case ButtonRelease:
1638706f2543Smrg	switch (b) {
1639706f2543Smrg	case 1: return up_1;
1640706f2543Smrg	case 2: return up_2;
1641706f2543Smrg	case 3: return up_3;
1642706f2543Smrg	default: return up_o;
1643706f2543Smrg	}
1644706f2543Smrg	break;
1645706f2543Smrg    case MotionNotify:
1646706f2543Smrg	if (pi->eventHeld && !KdInsideEmulationWindow(pi, x, y, z))
1647706f2543Smrg	    return outside_box;
1648706f2543Smrg	else
1649706f2543Smrg	    return motion;
1650706f2543Smrg    default:
1651706f2543Smrg	return keyboard;
1652706f2543Smrg    }
1653706f2543Smrg    return keyboard;
1654706f2543Smrg}
1655706f2543Smrg
1656706f2543Smrg#ifdef DEBUG
1657706f2543Smrgchar	*kdStateNames[] = {
1658706f2543Smrg    "start",
1659706f2543Smrg    "button_1_pend",
1660706f2543Smrg    "button_1_down",
1661706f2543Smrg    "button_2_down",
1662706f2543Smrg    "button_3_pend",
1663706f2543Smrg    "button_3_down",
1664706f2543Smrg    "synth_2_down_13",
1665706f2543Smrg    "synth_2_down_3",
1666706f2543Smrg    "synthetic_2_down_1",
1667706f2543Smrg    "num_input_states"
1668706f2543Smrg};
1669706f2543Smrg
1670706f2543Smrgchar	*kdClassNames[] = {
1671706f2543Smrg    "down_1", "up_1",
1672706f2543Smrg    "down_2", "up_2",
1673706f2543Smrg    "down_3", "up_3",
1674706f2543Smrg    "motion", "ouside_box",
1675706f2543Smrg    "keyboard", "timeout",
1676706f2543Smrg    "num_input_class"
1677706f2543Smrg};
1678706f2543Smrg
1679706f2543Smrgchar *kdActionNames[] = {
1680706f2543Smrg    "noop",
1681706f2543Smrg    "hold",
1682706f2543Smrg    "setto",
1683706f2543Smrg    "deliver",
1684706f2543Smrg    "release",
1685706f2543Smrg    "clearto",
1686706f2543Smrg    "gen_down_2",
1687706f2543Smrg    "gen_up_2",
1688706f2543Smrg};
1689706f2543Smrg#endif /* DEBUG */
1690706f2543Smrg
1691706f2543Smrgstatic void
1692706f2543SmrgKdQueueEvent (DeviceIntPtr pDev, InternalEvent *ev)
1693706f2543Smrg{
1694706f2543Smrg    KdAssertSigioBlocked ("KdQueueEvent");
1695706f2543Smrg    mieqEnqueue (pDev, ev);
1696706f2543Smrg}
1697706f2543Smrg
1698706f2543Smrg/* We return true if we're stealing the event. */
1699706f2543Smrgstatic Bool
1700706f2543SmrgKdRunMouseMachine (KdPointerInfo *pi, KdInputClass c, int type, int x, int y,
1701706f2543Smrg                   int z, int b, int absrel)
1702706f2543Smrg{
1703706f2543Smrg    const KdInputTransition *t;
1704706f2543Smrg    int	a;
1705706f2543Smrg
1706706f2543Smrg    c = KdClassifyInput(pi, type, x, y, z, b);
1707706f2543Smrg    t = &kdInputMachine[pi->mouseState][c];
1708706f2543Smrg    for (a = 0; a < MAX_ACTIONS; a++)
1709706f2543Smrg    {
1710706f2543Smrg	switch (t->actions[a]) {
1711706f2543Smrg	case noop:
1712706f2543Smrg	    break;
1713706f2543Smrg	case hold:
1714706f2543Smrg	    pi->eventHeld = TRUE;
1715706f2543Smrg	    pi->emulationDx = 0;
1716706f2543Smrg	    pi->emulationDy = 0;
1717706f2543Smrg	    pi->heldEvent.type = type;
1718706f2543Smrg            pi->heldEvent.x = x;
1719706f2543Smrg            pi->heldEvent.y = y;
1720706f2543Smrg            pi->heldEvent.z = z;
1721706f2543Smrg            pi->heldEvent.flags = b;
1722706f2543Smrg            pi->heldEvent.absrel = absrel;
1723706f2543Smrg            return TRUE;
1724706f2543Smrg	    break;
1725706f2543Smrg	case setto:
1726706f2543Smrg	    pi->emulationTimeout = GetTimeInMillis () + EMULATION_TIMEOUT;
1727706f2543Smrg	    pi->timeoutPending = TRUE;
1728706f2543Smrg	    break;
1729706f2543Smrg	case deliver:
1730706f2543Smrg            _KdEnqueuePointerEvent (pi, pi->heldEvent.type, pi->heldEvent.x,
1731706f2543Smrg                                    pi->heldEvent.y, pi->heldEvent.z,
1732706f2543Smrg                                    pi->heldEvent.flags, pi->heldEvent.absrel,
1733706f2543Smrg                                    TRUE);
1734706f2543Smrg	    break;
1735706f2543Smrg	case release:
1736706f2543Smrg	    pi->eventHeld = FALSE;
1737706f2543Smrg	    pi->timeoutPending = FALSE;
1738706f2543Smrg            _KdEnqueuePointerEvent (pi, pi->heldEvent.type, pi->heldEvent.x,
1739706f2543Smrg                                    pi->heldEvent.y, pi->heldEvent.z,
1740706f2543Smrg                                    pi->heldEvent.flags, pi->heldEvent.absrel,
1741706f2543Smrg                                    TRUE);
1742706f2543Smrg            return TRUE;
1743706f2543Smrg	    break;
1744706f2543Smrg	case clearto:
1745706f2543Smrg	    pi->timeoutPending = FALSE;
1746706f2543Smrg	    break;
1747706f2543Smrg	case gen_down_2:
1748706f2543Smrg            _KdEnqueuePointerEvent (pi, ButtonPress, x, y, z, 2, absrel,
1749706f2543Smrg                                    TRUE);
1750706f2543Smrg	    pi->eventHeld = FALSE;
1751706f2543Smrg            return TRUE;
1752706f2543Smrg	    break;
1753706f2543Smrg	case gen_up_2:
1754706f2543Smrg            _KdEnqueuePointerEvent (pi, ButtonRelease, x, y, z, 2, absrel,
1755706f2543Smrg                                    TRUE);
1756706f2543Smrg            return TRUE;
1757706f2543Smrg	    break;
1758706f2543Smrg	}
1759706f2543Smrg    }
1760706f2543Smrg    pi->mouseState = t->nextState;
1761706f2543Smrg    return FALSE;
1762706f2543Smrg}
1763706f2543Smrg
1764706f2543Smrgstatic int
1765706f2543SmrgKdHandlePointerEvent (KdPointerInfo *pi, int type, int x, int y, int z, int b,
1766706f2543Smrg                      int absrel)
1767706f2543Smrg{
1768706f2543Smrg    if (pi->emulateMiddleButton)
1769706f2543Smrg        return KdRunMouseMachine (pi, KdClassifyInput(pi, type, x, y, z, b),
1770706f2543Smrg                                  type, x, y, z, b, absrel);
1771706f2543Smrg    return FALSE;
1772706f2543Smrg}
1773706f2543Smrg
1774706f2543Smrgstatic void
1775706f2543SmrgKdReceiveTimeout (KdPointerInfo *pi)
1776706f2543Smrg{
1777706f2543Smrg    KdRunMouseMachine (pi, timeout, 0, 0, 0, 0, 0, 0);
1778706f2543Smrg}
1779706f2543Smrg
1780706f2543Smrg/*
1781706f2543Smrg * kdCheckTermination
1782706f2543Smrg *
1783706f2543Smrg * This function checks for the key sequence that terminates the server.  When
1784706f2543Smrg * detected, it sets the dispatchException flag and returns.  The key sequence
1785706f2543Smrg * is:
1786706f2543Smrg *	Control-Alt
1787706f2543Smrg * It's assumed that the server will be waken up by the caller when this
1788706f2543Smrg * function returns.
1789706f2543Smrg */
1790706f2543Smrg
1791706f2543Smrgextern int nClients;
1792706f2543Smrg
1793706f2543Smrgvoid
1794706f2543SmrgKdReleaseAllKeys (void)
1795706f2543Smrg{
1796706f2543Smrg#if 0
1797706f2543Smrg    int	key, nEvents, i;
1798706f2543Smrg    KdKeyboardInfo *ki;
1799706f2543Smrg
1800706f2543Smrg    KdBlockSigio ();
1801706f2543Smrg
1802706f2543Smrg    for (ki = kdKeyboards; ki; ki = ki->next) {
1803706f2543Smrg        for (key = ki->keySyms.minKeyCode; key < ki->keySyms.maxKeyCode;
1804706f2543Smrg             key++) {
1805706f2543Smrg            if (key_is_down(ki->dixdev, key, KEY_POSTED | KEY_PROCESSED)) {
1806706f2543Smrg                KdHandleKeyboardEvent(ki, KeyRelease, key);
1807706f2543Smrg                GetEventList(&kdEvents);
1808706f2543Smrg                nEvents = GetKeyboardEvents(kdEvents, ki->dixdev, KeyRelease, key);
1809706f2543Smrg                for (i = 0; i < nEvents; i++)
1810706f2543Smrg                    KdQueueEvent (ki->dixdev, (kdEvents + i)->event);
1811706f2543Smrg            }
1812706f2543Smrg        }
1813706f2543Smrg    }
1814706f2543Smrg
1815706f2543Smrg    KdUnblockSigio ();
1816706f2543Smrg#endif
1817706f2543Smrg}
1818706f2543Smrg
1819706f2543Smrgstatic void
1820706f2543SmrgKdCheckLock (void)
1821706f2543Smrg{
1822706f2543Smrg    KeyClassPtr	    keyc = NULL;
1823706f2543Smrg    Bool	    isSet = FALSE, shouldBeSet = FALSE;
1824706f2543Smrg    KdKeyboardInfo     *tmp = NULL;
1825706f2543Smrg
1826706f2543Smrg    for (tmp = kdKeyboards; tmp; tmp = tmp->next) {
1827706f2543Smrg        if (tmp->LockLed && tmp->dixdev && tmp->dixdev->key) {
1828706f2543Smrg            keyc = tmp->dixdev->key;
1829706f2543Smrg            isSet = (tmp->leds & (1 << (tmp->LockLed-1))) != 0;
1830706f2543Smrg            /* FIXME: Just use XKB indicators! */
1831706f2543Smrg            shouldBeSet = !!(XkbStateFieldFromRec(&keyc->xkbInfo->state) & LockMask);
1832706f2543Smrg            if (isSet != shouldBeSet)
1833706f2543Smrg                KdSetLed (tmp, tmp->LockLed, shouldBeSet);
1834706f2543Smrg        }
1835706f2543Smrg    }
1836706f2543Smrg}
1837706f2543Smrg
1838706f2543Smrgvoid
1839706f2543SmrgKdEnqueueKeyboardEvent(KdKeyboardInfo   *ki,
1840706f2543Smrg                       unsigned char scan_code,
1841706f2543Smrg		       unsigned char is_up)
1842706f2543Smrg{
1843706f2543Smrg    unsigned char key_code;
1844706f2543Smrg    KeyClassPtr	keyc = NULL;
1845706f2543Smrg    KeybdCtrl *ctrl = NULL;
1846706f2543Smrg    int type, nEvents, i;
1847706f2543Smrg
1848706f2543Smrg    if (!ki || !ki->dixdev || !ki->dixdev->kbdfeed || !ki->dixdev->key)
1849706f2543Smrg	return;
1850706f2543Smrg
1851706f2543Smrg    keyc = ki->dixdev->key;
1852706f2543Smrg    ctrl = &ki->dixdev->kbdfeed->ctrl;
1853706f2543Smrg
1854706f2543Smrg    if (scan_code >= ki->minScanCode && scan_code <= ki->maxScanCode)
1855706f2543Smrg    {
1856706f2543Smrg	key_code = scan_code + KD_MIN_KEYCODE - ki->minScanCode;
1857706f2543Smrg
1858706f2543Smrg	/*
1859706f2543Smrg	 * Set up this event -- the type may be modified below
1860706f2543Smrg	 */
1861706f2543Smrg	if (is_up)
1862706f2543Smrg	    type = KeyRelease;
1863706f2543Smrg	else
1864706f2543Smrg	    type = KeyPress;
1865706f2543Smrg
1866706f2543Smrg        GetEventList(&kdEvents);
1867706f2543Smrg
1868706f2543Smrg        nEvents = GetKeyboardEvents(kdEvents, ki->dixdev, type, key_code);
1869706f2543Smrg        for (i = 0; i < nEvents; i++)
1870706f2543Smrg            KdQueueEvent(ki->dixdev, (InternalEvent *)((kdEvents + i)->event));
1871706f2543Smrg    }
1872706f2543Smrg    else {
1873706f2543Smrg        ErrorF("driver %s wanted to post scancode %d outside of [%d, %d]!\n",
1874706f2543Smrg               ki->name, scan_code, ki->minScanCode, ki->maxScanCode);
1875706f2543Smrg    }
1876706f2543Smrg}
1877706f2543Smrg
1878706f2543Smrg/*
1879706f2543Smrg * kdEnqueuePointerEvent
1880706f2543Smrg *
1881706f2543Smrg * This function converts hardware mouse event information into X event
1882706f2543Smrg * information.  A mouse movement event is passed off to MI to generate
1883706f2543Smrg * a MotionNotify event, if appropriate.  Button events are created and
1884706f2543Smrg * passed off to MI for enqueueing.
1885706f2543Smrg */
1886706f2543Smrg
1887706f2543Smrg/* FIXME do something a little more clever to deal with multiple axes here */
1888706f2543Smrgvoid
1889706f2543SmrgKdEnqueuePointerEvent(KdPointerInfo *pi, unsigned long flags, int rx, int ry,
1890706f2543Smrg                      int rz)
1891706f2543Smrg{
1892706f2543Smrg    CARD32        ms;
1893706f2543Smrg    unsigned char buttons;
1894706f2543Smrg    int           x, y, z;
1895706f2543Smrg    int           (*matrix)[3] = kdPointerMatrix.matrix;
1896706f2543Smrg    unsigned long button;
1897706f2543Smrg    int           n;
1898706f2543Smrg    int           dixflags = 0;
1899706f2543Smrg
1900706f2543Smrg    if (!pi)
1901706f2543Smrg	return;
1902706f2543Smrg
1903706f2543Smrg    ms = GetTimeInMillis();
1904706f2543Smrg
1905706f2543Smrg    /* we don't need to transform z, so we don't. */
1906706f2543Smrg    if (flags & KD_MOUSE_DELTA) {
1907706f2543Smrg	if (pi->transformCoordinates) {
1908706f2543Smrg	    x = matrix[0][0] * rx + matrix[0][1] * ry;
1909706f2543Smrg	    y = matrix[1][0] * rx + matrix[1][1] * ry;
1910706f2543Smrg	}
1911706f2543Smrg	else {
1912706f2543Smrg	    x = rx;
1913706f2543Smrg	    y = ry;
1914706f2543Smrg	}
1915706f2543Smrg    }
1916706f2543Smrg    else {
1917706f2543Smrg	if (pi->transformCoordinates) {
1918706f2543Smrg	    x = matrix[0][0] * rx + matrix[0][1] * ry + matrix[0][2];
1919706f2543Smrg	    y = matrix[1][0] * rx + matrix[1][1] * ry + matrix[1][2];
1920706f2543Smrg	}
1921706f2543Smrg	else {
1922706f2543Smrg	    x = rx;
1923706f2543Smrg	    y = ry;
1924706f2543Smrg	}
1925706f2543Smrg    }
1926706f2543Smrg    z = rz;
1927706f2543Smrg
1928706f2543Smrg    if (flags & KD_MOUSE_DELTA)
1929706f2543Smrg    {
1930706f2543Smrg        if (x || y || z)
1931706f2543Smrg        {
1932706f2543Smrg            dixflags = POINTER_RELATIVE | POINTER_ACCELERATE;
1933706f2543Smrg            _KdEnqueuePointerEvent(pi, MotionNotify, x, y, z, 0, dixflags, FALSE);
1934706f2543Smrg        }
1935706f2543Smrg    } else
1936706f2543Smrg    {
1937706f2543Smrg        dixflags = POINTER_ABSOLUTE;
1938706f2543Smrg        if (x != pi->dixdev->last.valuators[0] ||
1939706f2543Smrg            y != pi->dixdev->last.valuators[1])
1940706f2543Smrg            _KdEnqueuePointerEvent(pi, MotionNotify, x, y, z, 0, dixflags, FALSE);
1941706f2543Smrg    }
1942706f2543Smrg
1943706f2543Smrg    buttons = flags;
1944706f2543Smrg
1945706f2543Smrg    for (button = KD_BUTTON_1, n = 1; n <= pi->nButtons;
1946706f2543Smrg         button <<= 1, n++) {
1947706f2543Smrg        if (((pi->buttonState & button) ^ (buttons & button)) &&
1948706f2543Smrg           !(buttons & button)) {
1949706f2543Smrg            _KdEnqueuePointerEvent(pi, ButtonRelease, x, y, z, n,
1950706f2543Smrg                                   dixflags, FALSE);
1951706f2543Smrg	}
1952706f2543Smrg    }
1953706f2543Smrg    for (button = KD_BUTTON_1, n = 1; n <= pi->nButtons;
1954706f2543Smrg         button <<= 1, n++) {
1955706f2543Smrg	if (((pi->buttonState & button) ^ (buttons & button)) &&
1956706f2543Smrg	    (buttons & button)) {
1957706f2543Smrg            _KdEnqueuePointerEvent(pi, ButtonPress, x, y, z, n,
1958706f2543Smrg                                   dixflags, FALSE);
1959706f2543Smrg        }
1960706f2543Smrg    }
1961706f2543Smrg
1962706f2543Smrg    pi->buttonState = buttons;
1963706f2543Smrg}
1964706f2543Smrg
1965706f2543Smrgvoid
1966706f2543Smrg_KdEnqueuePointerEvent (KdPointerInfo *pi, int type, int x, int y, int z,
1967706f2543Smrg                        int b, int absrel, Bool force)
1968706f2543Smrg{
1969706f2543Smrg    int nEvents = 0, i = 0;
1970706f2543Smrg    int valuators[3] = { x, y, z };
1971706f2543Smrg    ValuatorMask mask;
1972706f2543Smrg
1973706f2543Smrg    /* TRUE from KdHandlePointerEvent, means 'we swallowed the event'. */
1974706f2543Smrg    if (!force && KdHandlePointerEvent(pi, type, x, y, z, b, absrel))
1975706f2543Smrg        return;
1976706f2543Smrg
1977706f2543Smrg    valuator_mask_set_range(&mask, 0, 3, valuators);
1978706f2543Smrg
1979706f2543Smrg    GetEventList(&kdEvents);
1980706f2543Smrg    nEvents = GetPointerEvents(kdEvents, pi->dixdev, type, b, absrel, &mask);
1981706f2543Smrg    for (i = 0; i < nEvents; i++)
1982706f2543Smrg        KdQueueEvent(pi->dixdev, (InternalEvent *)((kdEvents + i)->event));
1983706f2543Smrg}
1984706f2543Smrg
1985706f2543Smrgvoid
1986706f2543SmrgKdBlockHandler (int		screen,
1987706f2543Smrg		pointer		blockData,
1988706f2543Smrg		pointer		timeout,
1989706f2543Smrg		pointer		readmask)
1990706f2543Smrg{
1991706f2543Smrg    KdPointerInfo		    *pi;
1992706f2543Smrg    int myTimeout=0;
1993706f2543Smrg
1994706f2543Smrg    for (pi = kdPointers; pi; pi = pi->next)
1995706f2543Smrg    {
1996706f2543Smrg	if (pi->timeoutPending)
1997706f2543Smrg	{
1998706f2543Smrg	    int	ms;
1999706f2543Smrg
2000706f2543Smrg	    ms = pi->emulationTimeout - GetTimeInMillis ();
2001706f2543Smrg	    if (ms < 1)
2002706f2543Smrg		ms = 1;
2003706f2543Smrg	    if(ms<myTimeout || myTimeout==0)
2004706f2543Smrg		    myTimeout=ms;
2005706f2543Smrg	}
2006706f2543Smrg    }
2007706f2543Smrg    /* if we need to poll for events, do that */
2008706f2543Smrg    if(kdOsFuncs->pollEvents)
2009706f2543Smrg    {
2010706f2543Smrg	    (*kdOsFuncs->pollEvents)();
2011706f2543Smrg	    myTimeout=20;
2012706f2543Smrg    }
2013706f2543Smrg    if(myTimeout>0)
2014706f2543Smrg    	AdjustWaitForDelay (timeout, myTimeout);
2015706f2543Smrg}
2016706f2543Smrg
2017706f2543Smrgvoid
2018706f2543SmrgKdWakeupHandler (int		screen,
2019706f2543Smrg		 pointer    	data,
2020706f2543Smrg		 unsigned long	lresult,
2021706f2543Smrg		 pointer	readmask)
2022706f2543Smrg{
2023706f2543Smrg    int		result = (int) lresult;
2024706f2543Smrg    fd_set	*pReadmask = (fd_set *) readmask;
2025706f2543Smrg    int		i;
2026706f2543Smrg    KdPointerInfo	*pi;
2027706f2543Smrg
2028706f2543Smrg    if (kdInputEnabled && result > 0)
2029706f2543Smrg    {
2030706f2543Smrg	for (i = 0; i < kdNumInputFds; i++)
2031706f2543Smrg	    if (FD_ISSET (kdInputFds[i].fd, pReadmask))
2032706f2543Smrg	    {
2033706f2543Smrg		KdBlockSigio ();
2034706f2543Smrg		(*kdInputFds[i].read) (kdInputFds[i].fd, kdInputFds[i].closure);
2035706f2543Smrg		KdUnblockSigio ();
2036706f2543Smrg	    }
2037706f2543Smrg    }
2038706f2543Smrg    for (pi = kdPointers; pi; pi = pi->next)
2039706f2543Smrg    {
2040706f2543Smrg	if (pi->timeoutPending)
2041706f2543Smrg	{
2042706f2543Smrg	    if ((long) (GetTimeInMillis () - pi->emulationTimeout) >= 0)
2043706f2543Smrg	    {
2044706f2543Smrg		pi->timeoutPending = FALSE;
2045706f2543Smrg		KdBlockSigio ();
2046706f2543Smrg		KdReceiveTimeout (pi);
2047706f2543Smrg		KdUnblockSigio ();
2048706f2543Smrg	    }
2049706f2543Smrg	}
2050706f2543Smrg    }
2051706f2543Smrg    if (kdSwitchPending)
2052706f2543Smrg	KdProcessSwitch ();
2053706f2543Smrg}
2054706f2543Smrg
2055706f2543Smrg#define KdScreenOrigin(pScreen) (&(KdGetScreenPriv(pScreen)->screen->origin))
2056706f2543Smrg
2057706f2543Smrgstatic Bool
2058706f2543SmrgKdCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
2059706f2543Smrg{
2060706f2543Smrg    ScreenPtr	pScreen  = *ppScreen;
2061706f2543Smrg    ScreenPtr	pNewScreen;
2062706f2543Smrg    int		n;
2063706f2543Smrg    int		dx, dy;
2064706f2543Smrg    int		best_x, best_y;
2065706f2543Smrg    int		n_best_x, n_best_y;
2066706f2543Smrg    CARD32	ms;
2067706f2543Smrg
2068706f2543Smrg    if (kdDisableZaphod || screenInfo.numScreens <= 1)
2069706f2543Smrg	return FALSE;
2070706f2543Smrg
2071706f2543Smrg    if (0 <= *x && *x < pScreen->width && 0 <= *y && *y < pScreen->height)
2072706f2543Smrg	return FALSE;
2073706f2543Smrg
2074706f2543Smrg    ms = GetTimeInMillis ();
2075706f2543Smrg    if (kdOffScreen && (int) (ms - kdOffScreenTime) < 1000)
2076706f2543Smrg	return FALSE;
2077706f2543Smrg    kdOffScreen = TRUE;
2078706f2543Smrg    kdOffScreenTime = ms;
2079706f2543Smrg    n_best_x = -1;
2080706f2543Smrg    best_x = 32767;
2081706f2543Smrg    n_best_y = -1;
2082706f2543Smrg    best_y = 32767;
2083706f2543Smrg    for (n = 0; n < screenInfo.numScreens; n++)
2084706f2543Smrg    {
2085706f2543Smrg	pNewScreen = screenInfo.screens[n];
2086706f2543Smrg	if (pNewScreen == pScreen)
2087706f2543Smrg	    continue;
2088706f2543Smrg	dx = KdScreenOrigin(pNewScreen)->x - KdScreenOrigin(pScreen)->x;
2089706f2543Smrg	dy = KdScreenOrigin(pNewScreen)->y - KdScreenOrigin(pScreen)->y;
2090706f2543Smrg	if (*x < 0)
2091706f2543Smrg	{
2092706f2543Smrg	    if (dx <= 0 && -dx < best_x)
2093706f2543Smrg	    {
2094706f2543Smrg		best_x = -dx;
2095706f2543Smrg		n_best_x = n;
2096706f2543Smrg	    }
2097706f2543Smrg	}
2098706f2543Smrg	else if (*x >= pScreen->width)
2099706f2543Smrg	{
2100706f2543Smrg	    if (dx >= 0 && dx < best_x)
2101706f2543Smrg	    {
2102706f2543Smrg		best_x = dx;
2103706f2543Smrg		n_best_x = n;
2104706f2543Smrg	    }
2105706f2543Smrg	}
2106706f2543Smrg	if (*y < 0)
2107706f2543Smrg	{
2108706f2543Smrg	    if (dy <= 0 && -dy < best_y)
2109706f2543Smrg	    {
2110706f2543Smrg		best_y = -dy;
2111706f2543Smrg		n_best_y = n;
2112706f2543Smrg	    }
2113706f2543Smrg	}
2114706f2543Smrg	else if (*y >= pScreen->height)
2115706f2543Smrg	{
2116706f2543Smrg	    if (dy >= 0 && dy < best_y)
2117706f2543Smrg	    {
2118706f2543Smrg		best_y = dy;
2119706f2543Smrg		n_best_y = n;
2120706f2543Smrg	    }
2121706f2543Smrg	}
2122706f2543Smrg    }
2123706f2543Smrg    if (best_y < best_x)
2124706f2543Smrg	n_best_x = n_best_y;
2125706f2543Smrg    if (n_best_x == -1)
2126706f2543Smrg	return FALSE;
2127706f2543Smrg    pNewScreen = screenInfo.screens[n_best_x];
2128706f2543Smrg
2129706f2543Smrg    if (*x < 0)
2130706f2543Smrg	*x += pNewScreen->width;
2131706f2543Smrg    if (*y < 0)
2132706f2543Smrg	*y += pNewScreen->height;
2133706f2543Smrg
2134706f2543Smrg    if (*x >= pScreen->width)
2135706f2543Smrg	*x -= pScreen->width;
2136706f2543Smrg    if (*y >= pScreen->height)
2137706f2543Smrg	*y -= pScreen->height;
2138706f2543Smrg
2139706f2543Smrg    *ppScreen = pNewScreen;
2140706f2543Smrg    return TRUE;
2141706f2543Smrg}
2142706f2543Smrg
2143706f2543Smrgstatic void
2144706f2543SmrgKdCrossScreen(ScreenPtr pScreen, Bool entering)
2145706f2543Smrg{
2146706f2543Smrg}
2147706f2543Smrg
2148706f2543Smrgint KdCurScreen;	/* current event screen */
2149706f2543Smrg
2150706f2543Smrgstatic void
2151706f2543SmrgKdWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
2152706f2543Smrg{
2153706f2543Smrg    KdBlockSigio ();
2154706f2543Smrg    KdCurScreen = pScreen->myNum;
2155706f2543Smrg    miPointerWarpCursor(pDev, pScreen, x, y);
2156706f2543Smrg    KdUnblockSigio ();
2157706f2543Smrg}
2158706f2543Smrg
2159706f2543SmrgmiPointerScreenFuncRec kdPointerScreenFuncs =
2160706f2543Smrg{
2161706f2543Smrg    KdCursorOffScreen,
2162706f2543Smrg    KdCrossScreen,
2163706f2543Smrg    KdWarpCursor
2164706f2543Smrg};
2165706f2543Smrg
2166706f2543Smrgvoid
2167706f2543SmrgProcessInputEvents (void)
2168706f2543Smrg{
2169706f2543Smrg    mieqProcessInputEvents();
2170706f2543Smrg    miPointerUpdateSprite(inputInfo.pointer);
2171706f2543Smrg    if (kdSwitchPending)
2172706f2543Smrg	KdProcessSwitch ();
2173706f2543Smrg    KdCheckLock ();
2174706f2543Smrg}
2175706f2543Smrg
2176706f2543Smrg/* At the moment, absolute/relative is up to the client. */
2177706f2543Smrgint
2178706f2543SmrgSetDeviceMode(register ClientPtr client, DeviceIntPtr pDev, int mode)
2179706f2543Smrg{
2180706f2543Smrg    return BadMatch;
2181706f2543Smrg}
2182706f2543Smrg
2183706f2543Smrgint
2184706f2543SmrgSetDeviceValuators(register ClientPtr client, DeviceIntPtr pDev,
2185706f2543Smrg                   int *valuators, int first_valuator, int num_valuators)
2186706f2543Smrg{
2187706f2543Smrg    return BadMatch;
2188706f2543Smrg}
2189706f2543Smrg
2190706f2543Smrgint
2191706f2543SmrgChangeDeviceControl(register ClientPtr client, DeviceIntPtr pDev,
2192706f2543Smrg                        xDeviceCtl *control)
2193706f2543Smrg{
2194706f2543Smrg    switch (control->control) {
2195706f2543Smrg    case DEVICE_RESOLUTION:
2196706f2543Smrg        /* FIXME do something more intelligent here */
2197706f2543Smrg        return BadMatch;
2198706f2543Smrg
2199706f2543Smrg    case DEVICE_ABS_CALIB:
2200706f2543Smrg    case DEVICE_ABS_AREA:
2201706f2543Smrg        return Success;
2202706f2543Smrg
2203706f2543Smrg    case DEVICE_CORE:
2204706f2543Smrg        return BadMatch;
2205706f2543Smrg    case DEVICE_ENABLE:
2206706f2543Smrg        return Success;
2207706f2543Smrg
2208706f2543Smrg    default:
2209706f2543Smrg        return BadMatch;
2210706f2543Smrg    }
2211706f2543Smrg
2212706f2543Smrg    /* NOTREACHED */
2213706f2543Smrg    return BadImplementation;
2214706f2543Smrg}
2215706f2543Smrg
2216706f2543Smrgint
2217706f2543SmrgNewInputDeviceRequest(InputOption *options, InputAttributes *attrs,
2218706f2543Smrg                      DeviceIntPtr *pdev)
2219706f2543Smrg{
2220706f2543Smrg    InputOption *option = NULL;
2221706f2543Smrg    KdPointerInfo *pi = NULL;
2222706f2543Smrg    KdKeyboardInfo *ki = NULL;
2223706f2543Smrg
2224706f2543Smrg    for (option = options; option; option = option->next) {
2225706f2543Smrg        if (strcmp(option->key, "type") == 0) {
2226706f2543Smrg            if (strcmp(option->value, "pointer") == 0) {
2227706f2543Smrg                pi = KdNewPointer();
2228706f2543Smrg                if (!pi)
2229706f2543Smrg                    return BadAlloc;
2230706f2543Smrg            }
2231706f2543Smrg            else if (strcmp(option->value, "keyboard") == 0) {
2232706f2543Smrg                ki = KdNewKeyboard();
2233706f2543Smrg                if (!ki)
2234706f2543Smrg                    return BadAlloc;
2235706f2543Smrg            }
2236706f2543Smrg            else {
2237706f2543Smrg                ErrorF("unrecognised device type!\n");
2238706f2543Smrg                return BadValue;
2239706f2543Smrg            }
2240706f2543Smrg        }
2241706f2543Smrg#ifdef CONFIG_HAL
2242706f2543Smrg        else if (strcmp(option->key, "_source") == 0 &&
2243706f2543Smrg                 strcmp(option->value, "server/hal") == 0)
2244706f2543Smrg        {
2245706f2543Smrg            ErrorF("Ignoring device from HAL.\n");
2246706f2543Smrg            return BadValue;
2247706f2543Smrg        }
2248706f2543Smrg#endif
2249706f2543Smrg#ifdef CONFIG_UDEV
2250706f2543Smrg        else if (strcmp(option->key, "_source") == 0 &&
2251706f2543Smrg                 strcmp(option->value, "server/udev") == 0)
2252706f2543Smrg        {
2253706f2543Smrg            ErrorF("Ignoring device from udev.\n");
2254706f2543Smrg            return BadValue;
2255706f2543Smrg        }
2256706f2543Smrg#endif
2257706f2543Smrg    }
2258706f2543Smrg
2259706f2543Smrg    if (!ki && !pi) {
2260706f2543Smrg        ErrorF("unrecognised device identifier!\n");
2261706f2543Smrg        return BadValue;
2262706f2543Smrg    }
2263706f2543Smrg
2264706f2543Smrg    /* FIXME: change this code below to use KdParseKbdOptions and
2265706f2543Smrg     * KdParsePointerOptions */
2266706f2543Smrg    for (option = options; option; option = option->next) {
2267706f2543Smrg        if (strcmp(option->key, "device") == 0) {
2268706f2543Smrg            if (pi && option->value)
2269706f2543Smrg                pi->path = strdup(option->value);
2270706f2543Smrg            else if (ki && option->value)
2271706f2543Smrg                ki->path = strdup(option->value);
2272706f2543Smrg        }
2273706f2543Smrg        else if (strcmp(option->key, "driver") == 0) {
2274706f2543Smrg            if (pi) {
2275706f2543Smrg                pi->driver = KdFindPointerDriver(option->value);
2276706f2543Smrg                if (!pi->driver) {
2277706f2543Smrg                    ErrorF("couldn't find driver!\n");
2278706f2543Smrg                    KdFreePointer(pi);
2279706f2543Smrg                    return BadValue;
2280706f2543Smrg                }
2281706f2543Smrg                pi->options = options;
2282706f2543Smrg            }
2283706f2543Smrg            else if (ki) {
2284706f2543Smrg                ki->driver = KdFindKeyboardDriver(option->value);
2285706f2543Smrg                if (!ki->driver) {
2286706f2543Smrg                    ErrorF("couldn't find driver!\n");
2287706f2543Smrg                    KdFreeKeyboard(ki);
2288706f2543Smrg                    return BadValue;
2289706f2543Smrg                }
2290706f2543Smrg                ki->options = options;
2291706f2543Smrg            }
2292706f2543Smrg        }
2293706f2543Smrg    }
2294706f2543Smrg
2295706f2543Smrg    if (pi) {
2296706f2543Smrg        if (KdAddPointer(pi) != Success ||
2297706f2543Smrg            ActivateDevice(pi->dixdev, TRUE) != Success ||
2298706f2543Smrg            EnableDevice(pi->dixdev, TRUE) != TRUE) {
2299706f2543Smrg            ErrorF("couldn't add or enable pointer\n");
2300706f2543Smrg            return BadImplementation;
2301706f2543Smrg        }
2302706f2543Smrg    }
2303706f2543Smrg    else if (ki) {
2304706f2543Smrg        if (KdAddKeyboard(ki) != Success ||
2305706f2543Smrg            ActivateDevice(ki->dixdev, TRUE) != Success ||
2306706f2543Smrg            EnableDevice(ki->dixdev, TRUE) != TRUE) {
2307706f2543Smrg            ErrorF("couldn't add or enable keyboard\n");
2308706f2543Smrg            return BadImplementation;
2309706f2543Smrg        }
2310706f2543Smrg    }
2311706f2543Smrg
2312706f2543Smrg    if (pi) {
2313706f2543Smrg        *pdev = pi->dixdev;
2314706f2543Smrg    } else if(ki) {
2315706f2543Smrg        *pdev = ki->dixdev;
2316706f2543Smrg    }
2317706f2543Smrg
2318706f2543Smrg    return Success;
2319706f2543Smrg}
2320706f2543Smrg
2321706f2543Smrgvoid
2322706f2543SmrgDeleteInputDeviceRequest(DeviceIntPtr pDev)
2323706f2543Smrg{
2324706f2543Smrg    RemoveDevice(pDev, TRUE);
2325706f2543Smrg}
2326