1706f2543Smrg/*
2706f2543Smrg * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina.
3706f2543Smrg *
4706f2543Smrg * All Rights Reserved.
5706f2543Smrg *
6706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining
7706f2543Smrg * a copy of this software and associated documentation files (the
8706f2543Smrg * "Software"), to deal in the Software without restriction, including
9706f2543Smrg * without limitation on the rights to use, copy, modify, merge,
10706f2543Smrg * publish, distribute, sublicense, and/or sell copies of the Software,
11706f2543Smrg * and to permit persons to whom the Software is furnished to do so,
12706f2543Smrg * subject to the following conditions:
13706f2543Smrg *
14706f2543Smrg * The above copyright notice and this permission notice (including the
15706f2543Smrg * next paragraph) shall be included in all copies or substantial
16706f2543Smrg * portions of the Software.
17706f2543Smrg *
18706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19706f2543Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20706f2543Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21706f2543Smrg * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22706f2543Smrg * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23706f2543Smrg * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24706f2543Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25706f2543Smrg * SOFTWARE.
26706f2543Smrg */
27706f2543Smrg
28706f2543Smrg/*
29706f2543Smrg * Authors:
30706f2543Smrg *   David H. Dawes <dawes@xfree86.org>
31706f2543Smrg *   Kevin E. Martin <kem@redhat.com>
32706f2543Smrg *   Rickard E. (Rik) Faith <faith@redhat.com>
33706f2543Smrg */
34706f2543Smrg
35706f2543Smrg/** \file
36706f2543Smrg *
37706f2543Smrg * This file implements common routines used by the backend and console
38706f2543Smrg * input devices.
39706f2543Smrg */
40706f2543Smrg
41706f2543Smrg#ifdef HAVE_DMX_CONFIG_H
42706f2543Smrg#include <dmx-config.h>
43706f2543Smrg#endif
44706f2543Smrg
45706f2543Smrg#define DMX_STATE_DEBUG 0
46706f2543Smrg
47706f2543Smrg#include "dmxinputinit.h"
48706f2543Smrg#include "dmxcommon.h"
49706f2543Smrg#include "dmxconsole.h"
50706f2543Smrg#include "dmxprop.h"
51706f2543Smrg#include "dmxsync.h"
52706f2543Smrg#include "dmxmap.h"
53706f2543Smrg
54706f2543Smrg#include "inputstr.h"
55706f2543Smrg#include "input.h"
56706f2543Smrg#include <X11/keysym.h>
57706f2543Smrg#include "mipointer.h"
58706f2543Smrg#include "scrnintstr.h"
59706f2543Smrg
60706f2543Smrg#include <unistd.h>             /* For usleep() */
61706f2543Smrg
62706f2543Smrg#if DMX_STATE_DEBUG
63706f2543Smrg#define DMXDBG0(f)               dmxLog(dmxDebug,f)
64706f2543Smrg#else
65706f2543Smrg#define DMXDBG0(f)
66706f2543Smrg#endif
67706f2543Smrg
68706f2543Smrg/** Each device has a private area that is visible only from inside the
69706f2543Smrg * driver code. */
70706f2543Smrgtypedef struct _myPrivate {
71706f2543Smrg    DMX_COMMON_PRIVATE;
72706f2543Smrg} myPrivate;
73706f2543Smrg
74706f2543Smrgstatic void dmxCommonKbdSetAR(Display *display,
75706f2543Smrg                              unsigned char *old, unsigned char *new)
76706f2543Smrg{
77706f2543Smrg    XKeyboardControl kc;
78706f2543Smrg    XKeyboardState   ks;
79706f2543Smrg    unsigned long    mask = KBKey | KBAutoRepeatMode;
80706f2543Smrg    int              i, j;
81706f2543Smrg    int              minKeycode, maxKeycode;
82706f2543Smrg
83706f2543Smrg    if (!old) {
84706f2543Smrg        XGetKeyboardControl(display, &ks);
85706f2543Smrg        old = (unsigned char *)ks.auto_repeats;
86706f2543Smrg    }
87706f2543Smrg
88706f2543Smrg    XDisplayKeycodes(display, &minKeycode, &maxKeycode);
89706f2543Smrg    for (i = 1; i < 32; i++) {
90706f2543Smrg        if (!old || old[i] != new[i]) {
91706f2543Smrg            for (j = 0; j < 8; j++) {
92706f2543Smrg                if ((new[i] & (1 << j)) != (old[i] & (1 << j))) {
93706f2543Smrg                    kc.key              = i * 8 + j;
94706f2543Smrg                    kc.auto_repeat_mode = ((new[i] & (1 << j))
95706f2543Smrg                                           ? AutoRepeatModeOn
96706f2543Smrg                                           : AutoRepeatModeOff);
97706f2543Smrg                    if (kc.key >= minKeycode && kc.key <= maxKeycode)
98706f2543Smrg                        XChangeKeyboardControl(display, mask, &kc);
99706f2543Smrg                }
100706f2543Smrg            }
101706f2543Smrg        }
102706f2543Smrg    }
103706f2543Smrg}
104706f2543Smrg
105706f2543Smrgstatic void dmxCommonKbdSetLeds(Display *display, unsigned long new)
106706f2543Smrg{
107706f2543Smrg    int              i;
108706f2543Smrg    XKeyboardControl kc;
109706f2543Smrg
110706f2543Smrg    for (i = 0; i < 32; i++) {
111706f2543Smrg        kc.led      = i + 1;
112706f2543Smrg        kc.led_mode = (new & (1 << i)) ? LedModeOn : LedModeOff;
113706f2543Smrg        XChangeKeyboardControl(display, KBLed | KBLedMode, &kc);
114706f2543Smrg    }
115706f2543Smrg}
116706f2543Smrg
117706f2543Smrgstatic void dmxCommonKbdSetCtrl(Display *display,
118706f2543Smrg                                KeybdCtrl *old, KeybdCtrl *new)
119706f2543Smrg{
120706f2543Smrg    XKeyboardControl kc;
121706f2543Smrg    unsigned long    mask = KBKeyClickPercent | KBAutoRepeatMode;
122706f2543Smrg
123706f2543Smrg    if (!old
124706f2543Smrg        || old->click         != new->click
125706f2543Smrg        || old->autoRepeat    != new->autoRepeat) {
126706f2543Smrg
127706f2543Smrg        kc.key_click_percent = new->click;
128706f2543Smrg        kc.auto_repeat_mode  = new->autoRepeat;
129706f2543Smrg
130706f2543Smrg        XChangeKeyboardControl(display, mask, &kc);
131706f2543Smrg    }
132706f2543Smrg
133706f2543Smrg    dmxCommonKbdSetLeds(display, new->leds);
134706f2543Smrg    dmxCommonKbdSetAR(display, old ? old->autoRepeats : NULL,
135706f2543Smrg                      new->autoRepeats);
136706f2543Smrg}
137706f2543Smrg
138706f2543Smrgstatic void dmxCommonMouSetCtrl(Display *display, PtrCtrl *old, PtrCtrl *new)
139706f2543Smrg{
140706f2543Smrg    Bool do_accel, do_threshold;
141706f2543Smrg
142706f2543Smrg    if (!old
143706f2543Smrg        || old->num != new->num
144706f2543Smrg        || old->den != new->den
145706f2543Smrg        || old->threshold != new->threshold) {
146706f2543Smrg        do_accel     = (new->num > 0 && new->den > 0);
147706f2543Smrg        do_threshold = (new->threshold > 0);
148706f2543Smrg        if (do_accel || do_threshold) {
149706f2543Smrg            XChangePointerControl(display, do_accel, do_threshold,
150706f2543Smrg                                  new->num, new->den, new->threshold);
151706f2543Smrg        }
152706f2543Smrg    }
153706f2543Smrg}
154706f2543Smrg
155706f2543Smrg/** Update the keyboard control. */
156706f2543Smrgvoid dmxCommonKbdCtrl(DevicePtr pDev, KeybdCtrl *ctrl)
157706f2543Smrg{
158706f2543Smrg    GETPRIVFROMPDEV;
159706f2543Smrg
160706f2543Smrg    if (!priv->stateSaved && priv->be) dmxCommonSaveState(priv);
161706f2543Smrg    if (!priv->display || !priv->stateSaved) return;
162706f2543Smrg    dmxCommonKbdSetCtrl(priv->display,
163706f2543Smrg                        priv->kctrlset ? &priv->kctrl : NULL,
164706f2543Smrg                        ctrl);
165706f2543Smrg    priv->kctrl    = *ctrl;
166706f2543Smrg    priv->kctrlset = 1;
167706f2543Smrg}
168706f2543Smrg
169706f2543Smrg/** Update the mouse control. */
170706f2543Smrgvoid dmxCommonMouCtrl(DevicePtr pDev, PtrCtrl *ctrl)
171706f2543Smrg{
172706f2543Smrg    GETPRIVFROMPDEV;
173706f2543Smrg
174706f2543Smrg                                /* Don't set the acceleration for the
175706f2543Smrg                                 * console, because that should be
176706f2543Smrg                                 * controlled by the X server that the
177706f2543Smrg                                 * console is running on.  Otherwise,
178706f2543Smrg                                 * the acceleration for the console
179706f2543Smrg                                 * window would be unexpected for the
180706f2543Smrg                                 * scale of the window. */
181706f2543Smrg    if (priv->be) {
182706f2543Smrg        dmxCommonMouSetCtrl(priv->display,
183706f2543Smrg                            priv->mctrlset ? &priv->mctrl : NULL,
184706f2543Smrg                            ctrl);
185706f2543Smrg        priv->mctrl    = *ctrl;
186706f2543Smrg        priv->mctrlset = 1;
187706f2543Smrg    }
188706f2543Smrg}
189706f2543Smrg
190706f2543Smrg/** Sound they keyboard bell. */
191706f2543Smrgvoid dmxCommonKbdBell(DevicePtr pDev, int percent,
192706f2543Smrg                      int volume, int pitch, int duration)
193706f2543Smrg{
194706f2543Smrg    GETPRIVFROMPDEV;
195706f2543Smrg    XKeyboardControl kc;
196706f2543Smrg    XKeyboardState   ks;
197706f2543Smrg    unsigned long    mask = KBBellPercent | KBBellPitch | KBBellDuration;
198706f2543Smrg
199706f2543Smrg    if (!priv->be) XGetKeyboardControl(priv->display, &ks);
200706f2543Smrg    kc.bell_percent  = volume;
201706f2543Smrg    kc.bell_pitch    = pitch;
202706f2543Smrg    kc.bell_duration = duration;
203706f2543Smrg    XChangeKeyboardControl(priv->display, mask, &kc);
204706f2543Smrg    XBell(priv->display, percent);
205706f2543Smrg    if (!priv->be) {
206706f2543Smrg        kc.bell_percent  = ks.bell_percent;
207706f2543Smrg        kc.bell_pitch    = ks.bell_pitch;
208706f2543Smrg        kc.bell_duration = ks.bell_duration;
209706f2543Smrg        XChangeKeyboardControl(priv->display, mask, &kc);
210706f2543Smrg    }
211706f2543Smrg}
212706f2543Smrg
213706f2543Smrg/** Get the keyboard mapping. */
214706f2543Smrgvoid dmxCommonKbdGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap)
215706f2543Smrg{
216706f2543Smrg    GETPRIVFROMPDEV;
217706f2543Smrg    int             min_keycode;
218706f2543Smrg    int             max_keycode;
219706f2543Smrg    int             map_width;
220706f2543Smrg    KeySym          *keyboard_mapping;
221706f2543Smrg    XModifierKeymap *modifier_mapping;
222706f2543Smrg    int             i, j;
223706f2543Smrg
224706f2543Smrg                                /* Compute pKeySyms.  Cast
225706f2543Smrg                                 * XGetKeyboardMapping because of
226706f2543Smrg                                 * compiler warning on 64-bit machines.
227706f2543Smrg                                 * We assume pointers to 32-bit and
228706f2543Smrg                                 * 64-bit ints are the same. */
229706f2543Smrg    XDisplayKeycodes(priv->display, &min_keycode, &max_keycode);
230706f2543Smrg    keyboard_mapping     = (KeySym *)XGetKeyboardMapping(priv->display,
231706f2543Smrg                                                         min_keycode,
232706f2543Smrg                                                         max_keycode
233706f2543Smrg                                                         - min_keycode + 1,
234706f2543Smrg                                                         &map_width);
235706f2543Smrg    pKeySyms->minKeyCode = min_keycode;
236706f2543Smrg    pKeySyms->maxKeyCode = max_keycode;
237706f2543Smrg    pKeySyms->mapWidth   = map_width;
238706f2543Smrg    pKeySyms->map        = keyboard_mapping;
239706f2543Smrg
240706f2543Smrg
241706f2543Smrg                                /* Compute pModMap  */
242706f2543Smrg    modifier_mapping     = XGetModifierMapping(priv->display);
243706f2543Smrg    for (i = 0; i < MAP_LENGTH; i++)
244706f2543Smrg        pModMap[i] = 0;
245706f2543Smrg    for (j = 0; j < 8; j++) {
246706f2543Smrg        int max_keypermod = modifier_mapping->max_keypermod;
247706f2543Smrg
248706f2543Smrg        for (i = 0; i < max_keypermod; i++) {
249706f2543Smrg            CARD8 keycode = modifier_mapping->modifiermap[j*max_keypermod + i];
250706f2543Smrg            if (keycode)
251706f2543Smrg                pModMap[keycode] |= 1 << j;
252706f2543Smrg        }
253706f2543Smrg    }
254706f2543Smrg    XFreeModifiermap(modifier_mapping);
255706f2543Smrg}
256706f2543Smrg
257706f2543Smrg/** Fill in the XKEYBOARD parts of the \a info structure for the
258706f2543Smrg * specified \a pDev. */
259706f2543Smrgvoid dmxCommonKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
260706f2543Smrg{
261706f2543Smrg    GETPRIVFROMPDEV;
262706f2543Smrg    GETDMXINPUTFROMPRIV;
263706f2543Smrg    char *pt;
264706f2543Smrg
265706f2543Smrg    dmxCommonSaveState(priv);
266706f2543Smrg    if (priv->xkb) {
267706f2543Smrg#define NAME(x) \
268706f2543Smrg priv->xkb->names->x ? XGetAtomName(priv->display,priv->xkb->names->x) : NULL
269706f2543Smrg        info->names.keycodes = NAME(keycodes);
270706f2543Smrg        info->names.types    = NAME(types);
271706f2543Smrg        info->names.compat   = NAME(compat);
272706f2543Smrg        info->names.symbols  = NAME(symbols);
273706f2543Smrg        info->names.geometry = NAME(geometry);
274706f2543Smrg        info->freenames      = 1;
275706f2543Smrg#undef NAME
276706f2543Smrg        dmxLogInput(dmxInput,
277706f2543Smrg                    "XKEYBOARD: keycodes = %s\n", info->names.keycodes);
278706f2543Smrg        dmxLogInput(dmxInput,
279706f2543Smrg                    "XKEYBOARD: symbols  = %s\n", info->names.symbols);
280706f2543Smrg        dmxLogInput(dmxInput,
281706f2543Smrg                    "XKEYBOARD: geometry = %s\n", info->names.geometry);
282706f2543Smrg        if ((pt = strchr(info->names.keycodes, '+'))) *pt = '\0';
283706f2543Smrg    }
284706f2543Smrg    dmxCommonRestoreState(priv);
285706f2543Smrg}
286706f2543Smrg
287706f2543Smrg/** Turn \a pDev on (i.e., take input from \a pDev). */
288706f2543Smrgint dmxCommonKbdOn(DevicePtr pDev)
289706f2543Smrg{
290706f2543Smrg    GETPRIVFROMPDEV;
291706f2543Smrg    if (priv->be) dmxCommonSaveState(priv);
292706f2543Smrg    priv->eventMask |= DMX_KEYBOARD_EVENT_MASK;
293706f2543Smrg    XSelectInput(priv->display, priv->window, priv->eventMask);
294706f2543Smrg    if (priv->be)
295706f2543Smrg        XSetInputFocus(priv->display, priv->window, RevertToPointerRoot,
296706f2543Smrg                       CurrentTime);
297706f2543Smrg    return -1;
298706f2543Smrg}
299706f2543Smrg
300706f2543Smrg/** Turn \a pDev off. */
301706f2543Smrgvoid dmxCommonKbdOff(DevicePtr pDev)
302706f2543Smrg{
303706f2543Smrg    GETPRIVFROMPDEV;
304706f2543Smrg    priv->eventMask &= ~DMX_KEYBOARD_EVENT_MASK;
305706f2543Smrg    XSelectInput(priv->display, priv->window, priv->eventMask);
306706f2543Smrg    dmxCommonRestoreState(priv);
307706f2543Smrg}
308706f2543Smrg
309706f2543Smrg/** Turn \a pDev on (i.e., take input from \a pDev). */
310706f2543Smrgint dmxCommonOthOn(DevicePtr pDev)
311706f2543Smrg{
312706f2543Smrg    GETPRIVFROMPDEV;
313706f2543Smrg    GETDMXINPUTFROMPRIV;
314706f2543Smrg    XEventClass event_list[DMX_MAX_XINPUT_EVENT_TYPES];
315706f2543Smrg    int         event_type[DMX_MAX_XINPUT_EVENT_TYPES];
316706f2543Smrg    int         count = 0;
317706f2543Smrg
318706f2543Smrg#define ADD(type)                                                            \
319706f2543Smrg    if (count < DMX_MAX_XINPUT_EVENT_TYPES) {                                \
320706f2543Smrg        type(priv->xi, event_type[count], event_list[count]);                \
321706f2543Smrg        if (event_type[count]) {                                             \
322706f2543Smrg            dmxMapInsert(dmxLocal, event_type[count], XI_##type);            \
323706f2543Smrg            ++count;                                                         \
324706f2543Smrg        }                                                                    \
325706f2543Smrg    } else {                                                                 \
326706f2543Smrg        dmxLog(dmxWarning, "More than %d event types for %s\n",              \
327706f2543Smrg               DMX_MAX_XINPUT_EVENT_TYPES, dmxInput->name);                  \
328706f2543Smrg    }
329706f2543Smrg
330706f2543Smrg    if (!(priv->xi = XOpenDevice(priv->display, dmxLocal->deviceId))) {
331706f2543Smrg        dmxLog(dmxWarning, "Cannot open %s device (id=%d) on %s\n",
332706f2543Smrg               dmxLocal->deviceName ? dmxLocal->deviceName : "(unknown)",
333706f2543Smrg               dmxLocal->deviceId, dmxInput->name);
334706f2543Smrg        return -1;
335706f2543Smrg    }
336706f2543Smrg    ADD(DeviceKeyPress);
337706f2543Smrg    ADD(DeviceKeyRelease);
338706f2543Smrg    ADD(DeviceButtonPress);
339706f2543Smrg    ADD(DeviceButtonRelease);
340706f2543Smrg    ADD(DeviceMotionNotify);
341706f2543Smrg    ADD(DeviceFocusIn);
342706f2543Smrg    ADD(DeviceFocusOut);
343706f2543Smrg    ADD(ProximityIn);
344706f2543Smrg    ADD(ProximityOut);
345706f2543Smrg    ADD(DeviceStateNotify);
346706f2543Smrg    ADD(DeviceMappingNotify);
347706f2543Smrg    ADD(ChangeDeviceNotify);
348706f2543Smrg    XSelectExtensionEvent(priv->display, priv->window, event_list, count);
349706f2543Smrg
350706f2543Smrg    return -1;
351706f2543Smrg}
352706f2543Smrg
353706f2543Smrg/** Turn \a pDev off. */
354706f2543Smrgvoid dmxCommonOthOff(DevicePtr pDev)
355706f2543Smrg{
356706f2543Smrg    GETPRIVFROMPDEV;
357706f2543Smrg
358706f2543Smrg    if (priv->xi) XCloseDevice(priv->display, priv->xi);
359706f2543Smrg    priv->xi = NULL;
360706f2543Smrg}
361706f2543Smrg
362706f2543Smrg/** Fill the \a info structure with information needed to initialize \a
363706f2543Smrg * pDev. */
364706f2543Smrgvoid dmxCommonOthGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
365706f2543Smrg{
366706f2543Smrg    GETPRIVFROMPDEV;
367706f2543Smrg    GETDMXINPUTFROMPRIV;
368706f2543Smrg    XExtensionVersion    *ext;
369706f2543Smrg    XDeviceInfo          *devices;
370706f2543Smrg    Display              *display = priv->display;
371706f2543Smrg    int                  num;
372706f2543Smrg    int                  i, j, k;
373706f2543Smrg    XextErrorHandler     handler;
374706f2543Smrg
375706f2543Smrg    if (!display && !(display = XOpenDisplay(dmxInput->name)))
376706f2543Smrg        return;
377706f2543Smrg
378706f2543Smrg    /* Print out information about the XInput Extension. */
379706f2543Smrg    handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler);
380706f2543Smrg    ext     = XGetExtensionVersion(display, INAME);
381706f2543Smrg    XSetExtensionErrorHandler(handler);
382706f2543Smrg
383706f2543Smrg    if (ext && ext != (XExtensionVersion *)NoSuchExtension) {
384706f2543Smrg        XFree(ext);
385706f2543Smrg        devices = XListInputDevices(display, &num);
386706f2543Smrg        for (i = 0; i < num; i++) {
387706f2543Smrg            if (devices[i].id == (XID)dmxLocal->deviceId) {
388706f2543Smrg                XAnyClassPtr     any;
389706f2543Smrg                XKeyInfoPtr      ki;
390706f2543Smrg                XButtonInfoPtr   bi;
391706f2543Smrg                XValuatorInfoPtr vi;
392706f2543Smrg                for (j = 0, any = devices[i].inputclassinfo;
393706f2543Smrg                     j < devices[i].num_classes;
394706f2543Smrg                     any = (XAnyClassPtr)((char *)any + any->length), j++) {
395706f2543Smrg                    switch (any->class) {
396706f2543Smrg                    case KeyClass:
397706f2543Smrg                        ki = (XKeyInfoPtr)any;
398706f2543Smrg                        info->keyboard           = 1;
399706f2543Smrg                        info->keyClass           = 1;
400706f2543Smrg                        info->keySyms.minKeyCode = ki->min_keycode;
401706f2543Smrg                        info->keySyms.maxKeyCode = ki->max_keycode;
402706f2543Smrg                        info->kbdFeedbackClass   = 1;
403706f2543Smrg                        break;
404706f2543Smrg                    case ButtonClass:
405706f2543Smrg                        bi = (XButtonInfoPtr)any;
406706f2543Smrg                        info->buttonClass        = 1;
407706f2543Smrg                        info->numButtons         = bi->num_buttons;
408706f2543Smrg                        info->ptrFeedbackClass   = 1;
409706f2543Smrg                        break;
410706f2543Smrg                    case ValuatorClass:
411706f2543Smrg                                /* This assume all axes are either
412706f2543Smrg                                 * Absolute or Relative. */
413706f2543Smrg                        vi = (XValuatorInfoPtr)any;
414706f2543Smrg                        info->valuatorClass      = 1;
415706f2543Smrg                        if (vi->mode == Absolute)
416706f2543Smrg                            info->numAbsAxes     = vi->num_axes;
417706f2543Smrg                        else
418706f2543Smrg                            info->numRelAxes     = vi->num_axes;
419706f2543Smrg                        for (k = 0; k < vi->num_axes; k++) {
420706f2543Smrg                            info->res[k]         = vi->axes[k].resolution;
421706f2543Smrg                            info->minres[k]      = vi->axes[k].resolution;
422706f2543Smrg                            info->maxres[k]      = vi->axes[k].resolution;
423706f2543Smrg                            info->minval[k]      = vi->axes[k].min_value;
424706f2543Smrg                            info->maxval[k]      = vi->axes[k].max_value;
425706f2543Smrg                        }
426706f2543Smrg                        break;
427706f2543Smrg                    case FeedbackClass:
428706f2543Smrg                                /* Only keyboard and pointer feedback
429706f2543Smrg                                 * are handled at this time. */
430706f2543Smrg                        break;
431706f2543Smrg                    case ProximityClass:
432706f2543Smrg                        info->proximityClass     = 1;
433706f2543Smrg                        break;
434706f2543Smrg                    case FocusClass:
435706f2543Smrg                        info->focusClass         = 1;
436706f2543Smrg                        break;
437706f2543Smrg                    case OtherClass:
438706f2543Smrg                        break;
439706f2543Smrg                    }
440706f2543Smrg                }
441706f2543Smrg            }
442706f2543Smrg        }
443706f2543Smrg        XFreeDeviceList(devices);
444706f2543Smrg    }
445706f2543Smrg    if (display != priv->display) XCloseDisplay(display);
446706f2543Smrg}
447706f2543Smrg
448706f2543Smrg/** Obtain the mouse button mapping. */
449706f2543Smrgvoid dmxCommonMouGetMap(DevicePtr pDev, unsigned char *map, int *nButtons)
450706f2543Smrg{
451706f2543Smrg    GETPRIVFROMPDEV;
452706f2543Smrg    int i;
453706f2543Smrg
454706f2543Smrg    *nButtons = XGetPointerMapping(priv->display, map, DMX_MAX_BUTTONS);
455706f2543Smrg    for (i = 0; i <= *nButtons; i++) map[i] = i;
456706f2543Smrg}
457706f2543Smrg
458706f2543Smrgstatic void *dmxCommonXSelect(DMXScreenInfo *dmxScreen, void *closure)
459706f2543Smrg{
460706f2543Smrg    myPrivate *priv = closure;
461706f2543Smrg    XSelectInput(dmxScreen->beDisplay, dmxScreen->scrnWin, priv->eventMask);
462706f2543Smrg    return NULL;
463706f2543Smrg}
464706f2543Smrg
465706f2543Smrgstatic void *dmxCommonAddEnabledDevice(DMXScreenInfo *dmxScreen, void *closure)
466706f2543Smrg{
467706f2543Smrg    AddEnabledDevice(XConnectionNumber(dmxScreen->beDisplay));
468706f2543Smrg    return NULL;
469706f2543Smrg}
470706f2543Smrg
471706f2543Smrgstatic void *dmxCommonRemoveEnabledDevice(DMXScreenInfo *dmxScreen,
472706f2543Smrg                                          void *closure)
473706f2543Smrg{
474706f2543Smrg    RemoveEnabledDevice(XConnectionNumber(dmxScreen->beDisplay));
475706f2543Smrg    return NULL;
476706f2543Smrg}
477706f2543Smrg
478706f2543Smrg/** Turn \a pDev on (i.e., take input from \a pDev). */
479706f2543Smrgint dmxCommonMouOn(DevicePtr pDev)
480706f2543Smrg{
481706f2543Smrg    GETPRIVFROMPDEV;
482706f2543Smrg    GETDMXINPUTFROMPRIV;
483706f2543Smrg
484706f2543Smrg    priv->eventMask |= DMX_POINTER_EVENT_MASK;
485706f2543Smrg    if (dmxShadowFB) {
486706f2543Smrg        XWarpPointer(priv->display, priv->window, priv->window,
487706f2543Smrg                     0, 0, 0, 0,
488706f2543Smrg                     priv->initPointerX,
489706f2543Smrg                     priv->initPointerY);
490706f2543Smrg        dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE);
491706f2543Smrg    }
492706f2543Smrg    if (!priv->be) {
493706f2543Smrg        XSelectInput(priv->display, priv->window, priv->eventMask);
494706f2543Smrg        AddEnabledDevice(XConnectionNumber(priv->display));
495706f2543Smrg    } else {
496706f2543Smrg        dmxPropertyIterate(priv->be, dmxCommonXSelect, priv);
497706f2543Smrg        dmxPropertyIterate(priv->be, dmxCommonAddEnabledDevice, dmxInput);
498706f2543Smrg    }
499706f2543Smrg
500706f2543Smrg    return -1;
501706f2543Smrg}
502706f2543Smrg
503706f2543Smrg/** Turn \a pDev off. */
504706f2543Smrgvoid dmxCommonMouOff(DevicePtr pDev)
505706f2543Smrg{
506706f2543Smrg    GETPRIVFROMPDEV;
507706f2543Smrg    GETDMXINPUTFROMPRIV;
508706f2543Smrg
509706f2543Smrg    priv->eventMask &= ~DMX_POINTER_EVENT_MASK;
510706f2543Smrg    if (!priv->be) {
511706f2543Smrg        RemoveEnabledDevice(XConnectionNumber(priv->display));
512706f2543Smrg        XSelectInput(priv->display, priv->window, priv->eventMask);
513706f2543Smrg    } else {
514706f2543Smrg        dmxPropertyIterate(priv->be, dmxCommonRemoveEnabledDevice, dmxInput);
515706f2543Smrg        dmxPropertyIterate(priv->be, dmxCommonXSelect, priv);
516706f2543Smrg    }
517706f2543Smrg}
518706f2543Smrg
519706f2543Smrg/** Given the global coordinates \a x and \a y, determine the screen
520706f2543Smrg * with the lowest number on which those coordinates lie.  If they are
521706f2543Smrg * not on any screen, return -1.  The number returned is an index into
522706f2543Smrg * \a dmxScreenInfo and is between -1 and \a dmxNumScreens - 1,
523706f2543Smrg * inclusive. */
524706f2543Smrgint dmxFindPointerScreen(int x, int y)
525706f2543Smrg{
526706f2543Smrg    int i;
527706f2543Smrg
528706f2543Smrg    for (i = 0; i < dmxNumScreens; i++) {
529706f2543Smrg	ScreenPtr pScreen = screenInfo.screens[i];
530706f2543Smrg	if (x >= pScreen->x && x < pScreen->x + pScreen->width &&
531706f2543Smrg	    y >= pScreen->y && y < pScreen->y + pScreen->height)
532706f2543Smrg	    return i;
533706f2543Smrg    }
534706f2543Smrg    return -1;
535706f2543Smrg}
536706f2543Smrg
537706f2543Smrg/** Returns a pointer to the private area for the device that comes just
538706f2543Smrg * prior to \a pDevice in the current \a dmxInput device list.  This is
539706f2543Smrg * used as the private area for the current device in some situations
540706f2543Smrg * (e.g., when a keyboard and mouse form a pair that should share the
541706f2543Smrg * same private area).  If the requested private area cannot be located,
542706f2543Smrg * then NULL is returned. */
543706f2543Smrgpointer dmxCommonCopyPrivate(DeviceIntPtr pDevice)
544706f2543Smrg{
545706f2543Smrg    GETDMXLOCALFROMPDEVICE;
546706f2543Smrg    DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
547706f2543Smrg    int          i;
548706f2543Smrg
549706f2543Smrg    for (i = 0; i < dmxInput->numDevs; i++)
550706f2543Smrg        if (dmxInput->devs[i] == dmxLocal && i)
551706f2543Smrg            return dmxInput->devs[i-1]->private;
552706f2543Smrg    return NULL;
553706f2543Smrg}
554706f2543Smrg
555706f2543Smrg/** This routine saves and resets some important state for the backend
556706f2543Smrg * and console device drivers:
557706f2543Smrg * - the modifier map is saved and set to 0 (so DMX controls the LEDs)
558706f2543Smrg * - the key click, bell, led, and repeat masks are saved and set to the
559706f2543Smrg * values that DMX claims to be using
560706f2543Smrg *
561706f2543Smrg * This routine and #dmxCommonRestoreState are used when the pointer
562706f2543Smrg * enters and leaves the console window, or when the backend window is
563706f2543Smrg * active or not active (for a full-screen window, this only happens at
564706f2543Smrg * server startup and server shutdown).
565706f2543Smrg */
566706f2543Smrgvoid dmxCommonSaveState(pointer private)
567706f2543Smrg{
568706f2543Smrg    GETPRIVFROMPRIVATE;
569706f2543Smrg    XKeyboardState   ks;
570706f2543Smrg    unsigned long    i;
571706f2543Smrg    XModifierKeymap  *modmap;
572706f2543Smrg
573706f2543Smrg    if (dmxInput->console) priv = dmxInput->devs[0]->private;
574706f2543Smrg    if (!priv->display || priv->stateSaved) return;
575706f2543Smrg    DMXDBG0("dmxCommonSaveState\n");
576706f2543Smrg    if (dmxUseXKB && (priv->xkb = XkbAllocKeyboard())) {
577706f2543Smrg        if (XkbGetIndicatorMap(priv->display, XkbAllIndicatorsMask, priv->xkb)
578706f2543Smrg            || XkbGetNames(priv->display, XkbAllNamesMask, priv->xkb)) {
579706f2543Smrg            dmxLogInput(dmxInput, "Could not get XKB information\n");
580706f2543Smrg            XkbFreeKeyboard(priv->xkb, 0, True);
581706f2543Smrg            priv->xkb = NULL;
582706f2543Smrg        } else {
583706f2543Smrg            if (priv->xkb->indicators) {
584706f2543Smrg                priv->savedIndicators = *priv->xkb->indicators;
585706f2543Smrg                for (i = 0; i < XkbNumIndicators; i++)
586706f2543Smrg                    if (priv->xkb->indicators->phys_indicators & (1 << i)) {
587706f2543Smrg                        priv->xkb->indicators->maps[i].flags
588706f2543Smrg                            = XkbIM_NoAutomatic;
589706f2543Smrg                    }
590706f2543Smrg                XkbSetIndicatorMap(priv->display, ~0, priv->xkb);
591706f2543Smrg            }
592706f2543Smrg        }
593706f2543Smrg    }
594706f2543Smrg
595706f2543Smrg    XGetKeyboardControl(priv->display, &ks);
596706f2543Smrg    priv->savedKctrl.click              = ks.key_click_percent;
597706f2543Smrg    priv->savedKctrl.bell               = ks.bell_percent;
598706f2543Smrg    priv->savedKctrl.bell_pitch         = ks.bell_pitch;
599706f2543Smrg    priv->savedKctrl.bell_duration      = ks.bell_duration;
600706f2543Smrg    priv->savedKctrl.leds               = ks.led_mask;
601706f2543Smrg    priv->savedKctrl.autoRepeat         = ks.global_auto_repeat;
602706f2543Smrg    for (i = 0; i < 32; i++)
603706f2543Smrg        priv->savedKctrl.autoRepeats[i] = ks.auto_repeats[i];
604706f2543Smrg
605706f2543Smrg    dmxCommonKbdSetCtrl(priv->display, &priv->savedKctrl,
606706f2543Smrg                        &priv->dmxLocal->kctrl);
607706f2543Smrg
608706f2543Smrg    priv->savedModMap                   = XGetModifierMapping(priv->display);
609706f2543Smrg
610706f2543Smrg    modmap                              = XNewModifiermap(0);
611706f2543Smrg    XSetModifierMapping(priv->display, modmap);
612706f2543Smrg    if (dmxInput->scrnIdx != -1)
613706f2543Smrg        dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE);
614706f2543Smrg    XFreeModifiermap(modmap);
615706f2543Smrg
616706f2543Smrg    priv->stateSaved = 1;
617706f2543Smrg}
618706f2543Smrg
619706f2543Smrg/** This routine restores all the information saved by #dmxCommonSaveState. */
620706f2543Smrgvoid dmxCommonRestoreState(pointer private)
621706f2543Smrg{
622706f2543Smrg    GETPRIVFROMPRIVATE;
623706f2543Smrg    int retcode = -1;
624706f2543Smrg    CARD32 start;
625706f2543Smrg
626706f2543Smrg    if (dmxInput->console)
627706f2543Smrg        priv = dmxInput->devs[0]->private;
628706f2543Smrg    if (!priv->stateSaved)
629706f2543Smrg        return;
630706f2543Smrg    priv->stateSaved = 0;
631706f2543Smrg
632706f2543Smrg    DMXDBG0("dmxCommonRestoreState\n");
633706f2543Smrg    if (priv->xkb) {
634706f2543Smrg        *priv->xkb->indicators = priv->savedIndicators;
635706f2543Smrg        XkbSetIndicatorMap(priv->display, ~0, priv->xkb);
636706f2543Smrg        XkbFreeKeyboard(priv->xkb, 0, True);
637706f2543Smrg        priv->xkb = 0;
638706f2543Smrg    }
639706f2543Smrg
640706f2543Smrg    for (start = GetTimeInMillis(); GetTimeInMillis() - start < 5000;) {
641706f2543Smrg        CARD32 tmp;
642706f2543Smrg
643706f2543Smrg        retcode = XSetModifierMapping(priv->display, priv->savedModMap);
644706f2543Smrg        if (retcode == MappingSuccess)
645706f2543Smrg            break;
646706f2543Smrg        if (retcode == MappingBusy)
647706f2543Smrg            dmxLogInput(dmxInput, "Keyboard busy, waiting\n");
648706f2543Smrg        else
649706f2543Smrg            dmxLogInput(dmxInput, "Keyboard error, waiting\n");
650706f2543Smrg
651706f2543Smrg                                /* Don't generate X11 protocol for a bit */
652706f2543Smrg        for (tmp = GetTimeInMillis(); GetTimeInMillis() - tmp < 250;) {
653706f2543Smrg            usleep(250);            /* This ends up sleeping only until
654706f2543Smrg                                     * the next key press generates an
655706f2543Smrg                                     * interruption.  We make the delay
656706f2543Smrg                                     * relatively short in case the user
657706f2543Smrg                                     * pressed they keys quickly. */
658706f2543Smrg        }
659706f2543Smrg
660706f2543Smrg    }
661706f2543Smrg    if (retcode != MappingSuccess)
662706f2543Smrg        dmxLog(dmxWarning, "Unable to restore keyboard modifier state!\n");
663706f2543Smrg
664706f2543Smrg    XFreeModifiermap(priv->savedModMap);
665706f2543Smrg    priv->savedModMap = NULL;
666706f2543Smrg
667706f2543Smrg    dmxCommonKbdSetCtrl(priv->display, NULL, &priv->savedKctrl);
668706f2543Smrg    priv->kctrlset = 0;         /* Invalidate copy */
669706f2543Smrg}
670