1 /*
2  * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina.
3  *
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation on the rights to use, copy, modify, merge,
10  * publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial
16  * portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 /*
29  * Authors:
30  *   David H. Dawes <dawes@xfree86.org>
31  *   Kevin E. Martin <kem@redhat.com>
32  *   Rickard E. (Rik) Faith <faith@redhat.com>
33  */
34 
35 /** \file
36  *
37  * This file implements common routines used by the backend and console
38  * input devices.
39  */
40 
41 #ifdef HAVE_DMX_CONFIG_H
42 #include <dmx-config.h>
43 #endif
44 
45 #define DMX_STATE_DEBUG 0
46 
47 #include "dmxinputinit.h"
48 #include "dmxcommon.h"
49 #include "dmxconsole.h"
50 #include "dmxprop.h"
51 #include "dmxsync.h"
52 #include "dmxmap.h"
53 
54 #include "inputstr.h"
55 #include "input.h"
56 #include <X11/keysym.h>
57 #include "mipointer.h"
58 #include "scrnintstr.h"
59 
60 #include <unistd.h>             /* For usleep() */
61 
62 #if DMX_STATE_DEBUG
63 #define DMXDBG0(f)               dmxLog(dmxDebug,f)
64 #else
65 #define DMXDBG0(f)
66 #endif
67 
68 /** Each device has a private area that is visible only from inside the
69  * driver code. */
70 typedef struct _myPrivate {
71     DMX_COMMON_PRIVATE;
72 } myPrivate;
73 
74 static void
dmxCommonKbdSetAR(Display * display,unsigned char * old,unsigned char * new)75 dmxCommonKbdSetAR(Display * display, unsigned char *old, unsigned char *new)
76 {
77     XKeyboardControl kc;
78     XKeyboardState ks;
79     unsigned long mask = KBKey | KBAutoRepeatMode;
80     int i, j;
81     int minKeycode, maxKeycode;
82 
83     if (!old) {
84         XGetKeyboardControl(display, &ks);
85         old = (unsigned char *) ks.auto_repeats;
86     }
87 
88     XDisplayKeycodes(display, &minKeycode, &maxKeycode);
89     for (i = 1; i < 32; i++) {
90         if (!old || old[i] != new[i]) {
91             for (j = 0; j < 8; j++) {
92                 if ((new[i] & (1 << j)) != (old[i] & (1 << j))) {
93                     kc.key = i * 8 + j;
94                     kc.auto_repeat_mode = ((new[i] & (1 << j))
95                                            ? AutoRepeatModeOn
96                                            : AutoRepeatModeOff);
97                     if (kc.key >= minKeycode && kc.key <= maxKeycode)
98                         XChangeKeyboardControl(display, mask, &kc);
99                 }
100             }
101         }
102     }
103 }
104 
105 static void
dmxCommonKbdSetLeds(Display * display,unsigned long new)106 dmxCommonKbdSetLeds(Display * display, unsigned long new)
107 {
108     int i;
109     XKeyboardControl kc;
110 
111     for (i = 0; i < 32; i++) {
112         kc.led = i + 1;
113         kc.led_mode = (new & (1 << i)) ? LedModeOn : LedModeOff;
114         XChangeKeyboardControl(display, KBLed | KBLedMode, &kc);
115     }
116 }
117 
118 static void
dmxCommonKbdSetCtrl(Display * display,KeybdCtrl * old,KeybdCtrl * new)119 dmxCommonKbdSetCtrl(Display * display, KeybdCtrl * old, KeybdCtrl * new)
120 {
121     XKeyboardControl kc;
122     unsigned long mask = KBKeyClickPercent | KBAutoRepeatMode;
123 
124     if (!old || old->click != new->click || old->autoRepeat != new->autoRepeat) {
125 
126         kc.key_click_percent = new->click;
127         kc.auto_repeat_mode = new->autoRepeat;
128 
129         XChangeKeyboardControl(display, mask, &kc);
130     }
131 
132     dmxCommonKbdSetLeds(display, new->leds);
133     dmxCommonKbdSetAR(display, old ? old->autoRepeats : NULL, new->autoRepeats);
134 }
135 
136 static void
dmxCommonMouSetCtrl(Display * display,PtrCtrl * old,PtrCtrl * new)137 dmxCommonMouSetCtrl(Display * display, PtrCtrl * old, PtrCtrl * new)
138 {
139     Bool do_accel, do_threshold;
140 
141     if (!old
142         || old->num != new->num
143         || old->den != new->den || old->threshold != new->threshold) {
144         do_accel = (new->num > 0 && new->den > 0);
145         do_threshold = (new->threshold > 0);
146         if (do_accel || do_threshold) {
147             XChangePointerControl(display, do_accel, do_threshold,
148                                   new->num, new->den, new->threshold);
149         }
150     }
151 }
152 
153 /** Update the keyboard control. */
154 void
dmxCommonKbdCtrl(DevicePtr pDev,KeybdCtrl * ctrl)155 dmxCommonKbdCtrl(DevicePtr pDev, KeybdCtrl * ctrl)
156 {
157     GETPRIVFROMPDEV;
158 
159     if (!priv->stateSaved && priv->be)
160         dmxCommonSaveState(priv);
161     if (!priv->display || !priv->stateSaved)
162         return;
163     dmxCommonKbdSetCtrl(priv->display,
164                         priv->kctrlset ? &priv->kctrl : NULL, ctrl);
165     priv->kctrl = *ctrl;
166     priv->kctrlset = 1;
167 }
168 
169 /** Update the mouse control. */
170 void
dmxCommonMouCtrl(DevicePtr pDev,PtrCtrl * ctrl)171 dmxCommonMouCtrl(DevicePtr pDev, PtrCtrl * ctrl)
172 {
173     GETPRIVFROMPDEV;
174 
175     /* Don't set the acceleration for the
176      * console, because that should be
177      * controlled by the X server that the
178      * console is running on.  Otherwise,
179      * the acceleration for the console
180      * window would be unexpected for the
181      * scale of the window. */
182     if (priv->be) {
183         dmxCommonMouSetCtrl(priv->display,
184                             priv->mctrlset ? &priv->mctrl : NULL, ctrl);
185         priv->mctrl = *ctrl;
186         priv->mctrlset = 1;
187     }
188 }
189 
190 /** Sound they keyboard bell. */
191 void
dmxCommonKbdBell(DevicePtr pDev,int percent,int volume,int pitch,int duration)192 dmxCommonKbdBell(DevicePtr pDev, int percent,
193                  int volume, int pitch, int duration)
194 {
195     GETPRIVFROMPDEV;
196     XKeyboardControl kc;
197     XKeyboardState ks;
198     unsigned long mask = KBBellPercent | KBBellPitch | KBBellDuration;
199 
200     if (!priv->be)
201         XGetKeyboardControl(priv->display, &ks);
202     kc.bell_percent = volume;
203     kc.bell_pitch = pitch;
204     kc.bell_duration = duration;
205     XChangeKeyboardControl(priv->display, mask, &kc);
206     XBell(priv->display, percent);
207     if (!priv->be) {
208         kc.bell_percent = ks.bell_percent;
209         kc.bell_pitch = ks.bell_pitch;
210         kc.bell_duration = ks.bell_duration;
211         XChangeKeyboardControl(priv->display, mask, &kc);
212     }
213 }
214 
215 /** Get the keyboard mapping. */
216 void
dmxCommonKbdGetMap(DevicePtr pDev,KeySymsPtr pKeySyms,CARD8 * pModMap)217 dmxCommonKbdGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap)
218 {
219     GETPRIVFROMPDEV;
220     int min_keycode;
221     int max_keycode;
222     int map_width;
223     KeySym *keyboard_mapping;
224     XModifierKeymap *modifier_mapping;
225     int i, j;
226 
227     /* Compute pKeySyms.  Cast
228      * XGetKeyboardMapping because of
229      * compiler warning on 64-bit machines.
230      * We assume pointers to 32-bit and
231      * 64-bit ints are the same. */
232     XDisplayKeycodes(priv->display, &min_keycode, &max_keycode);
233     keyboard_mapping = (KeySym *) XGetKeyboardMapping(priv->display,
234                                                       min_keycode,
235                                                       max_keycode
236                                                       - min_keycode + 1,
237                                                       &map_width);
238     pKeySyms->minKeyCode = min_keycode;
239     pKeySyms->maxKeyCode = max_keycode;
240     pKeySyms->mapWidth = map_width;
241     pKeySyms->map = keyboard_mapping;
242 
243     /* Compute pModMap  */
244     modifier_mapping = XGetModifierMapping(priv->display);
245     for (i = 0; i < MAP_LENGTH; i++)
246         pModMap[i] = 0;
247     for (j = 0; j < 8; j++) {
248         int max_keypermod = modifier_mapping->max_keypermod;
249 
250         for (i = 0; i < max_keypermod; i++) {
251             CARD8 keycode =
252                 modifier_mapping->modifiermap[j * max_keypermod + i];
253             if (keycode)
254                 pModMap[keycode] |= 1 << j;
255         }
256     }
257     XFreeModifiermap(modifier_mapping);
258 }
259 
260 /** Fill in the XKEYBOARD parts of the \a info structure for the
261  * specified \a pDev. */
262 void
dmxCommonKbdGetInfo(DevicePtr pDev,DMXLocalInitInfoPtr info)263 dmxCommonKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
264 {
265     GETPRIVFROMPDEV;
266     GETDMXINPUTFROMPRIV;
267     char *pt;
268 
269     dmxCommonSaveState(priv);
270     if (priv->xkb) {
271 #define NAME(x) \
272  priv->xkb->names->x ? XGetAtomName(priv->display,priv->xkb->names->x) : NULL
273         info->names.keycodes = NAME(keycodes);
274         info->names.types = NAME(types);
275         info->names.compat = NAME(compat);
276         info->names.symbols = NAME(symbols);
277         info->names.geometry = NAME(geometry);
278         info->freenames = 1;
279 #undef NAME
280         dmxLogInput(dmxInput,
281                     "XKEYBOARD: keycodes = %s\n", info->names.keycodes);
282         dmxLogInput(dmxInput,
283                     "XKEYBOARD: symbols  = %s\n", info->names.symbols);
284         dmxLogInput(dmxInput,
285                     "XKEYBOARD: geometry = %s\n", info->names.geometry);
286         if ((pt = strchr(info->names.keycodes, '+')))
287             *pt = '\0';
288     }
289     dmxCommonRestoreState(priv);
290 }
291 
292 /** Turn \a pDev on (i.e., take input from \a pDev). */
293 int
dmxCommonKbdOn(DevicePtr pDev)294 dmxCommonKbdOn(DevicePtr pDev)
295 {
296     GETPRIVFROMPDEV;
297     if (priv->be)
298         dmxCommonSaveState(priv);
299     priv->eventMask |= DMX_KEYBOARD_EVENT_MASK;
300     XSelectInput(priv->display, priv->window, priv->eventMask);
301     if (priv->be)
302         XSetInputFocus(priv->display, priv->window, RevertToPointerRoot,
303                        CurrentTime);
304     return -1;
305 }
306 
307 /** Turn \a pDev off. */
308 void
dmxCommonKbdOff(DevicePtr pDev)309 dmxCommonKbdOff(DevicePtr pDev)
310 {
311     GETPRIVFROMPDEV;
312     priv->eventMask &= ~DMX_KEYBOARD_EVENT_MASK;
313     XSelectInput(priv->display, priv->window, priv->eventMask);
314     dmxCommonRestoreState(priv);
315 }
316 
317 /** Turn \a pDev on (i.e., take input from \a pDev). */
318 int
dmxCommonOthOn(DevicePtr pDev)319 dmxCommonOthOn(DevicePtr pDev)
320 {
321     GETPRIVFROMPDEV;
322     GETDMXINPUTFROMPRIV;
323     XEventClass event_list[DMX_MAX_XINPUT_EVENT_TYPES];
324     int event_type[DMX_MAX_XINPUT_EVENT_TYPES];
325     int count = 0;
326 
327 #define ADD(type)                                                            \
328     if (count < DMX_MAX_XINPUT_EVENT_TYPES) {                                \
329         type(priv->xi, event_type[count], event_list[count]);                \
330         if (event_type[count]) {                                             \
331             dmxMapInsert(dmxLocal, event_type[count], XI_##type);            \
332             ++count;                                                         \
333         }                                                                    \
334     } else {                                                                 \
335         dmxLog(dmxWarning, "More than %d event types for %s\n",              \
336                DMX_MAX_XINPUT_EVENT_TYPES, dmxInput->name);                  \
337     }
338 
339     if (!(priv->xi = XOpenDevice(priv->display, dmxLocal->deviceId))) {
340         dmxLog(dmxWarning, "Cannot open %s device (id=%d) on %s\n",
341                dmxLocal->deviceName ? dmxLocal->deviceName : "(unknown)",
342                (int) dmxLocal->deviceId, dmxInput->name);
343         return -1;
344     }
345     ADD(DeviceKeyPress);
346     ADD(DeviceKeyRelease);
347     ADD(DeviceButtonPress);
348     ADD(DeviceButtonRelease);
349     ADD(DeviceMotionNotify);
350     ADD(DeviceFocusIn);
351     ADD(DeviceFocusOut);
352     ADD(ProximityIn);
353     ADD(ProximityOut);
354     ADD(DeviceStateNotify);
355     ADD(DeviceMappingNotify);
356     ADD(ChangeDeviceNotify);
357     XSelectExtensionEvent(priv->display, priv->window, event_list, count);
358 
359     return -1;
360 }
361 
362 /** Turn \a pDev off. */
363 void
dmxCommonOthOff(DevicePtr pDev)364 dmxCommonOthOff(DevicePtr pDev)
365 {
366     GETPRIVFROMPDEV;
367 
368     if (priv->xi)
369         XCloseDevice(priv->display, priv->xi);
370     priv->xi = NULL;
371 }
372 
373 /** Fill the \a info structure with information needed to initialize \a
374  * pDev. */
375 void
dmxCommonOthGetInfo(DevicePtr pDev,DMXLocalInitInfoPtr info)376 dmxCommonOthGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
377 {
378     GETPRIVFROMPDEV;
379     GETDMXINPUTFROMPRIV;
380     XExtensionVersion *ext;
381     XDeviceInfo *devices;
382     Display *display = priv->display;
383     int num;
384     int i, j, k;
385     XextErrorHandler handler;
386 
387     if (!display && !(display = XOpenDisplay(dmxInput->name)))
388         return;
389 
390     /* Print out information about the XInput Extension. */
391     handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler);
392     ext = XGetExtensionVersion(display, INAME);
393     XSetExtensionErrorHandler(handler);
394 
395     if (ext && ext != (XExtensionVersion *) NoSuchExtension) {
396         XFree(ext);
397         devices = XListInputDevices(display, &num);
398         for (i = 0; i < num; i++) {
399             if (devices[i].id == (XID) dmxLocal->deviceId) {
400                 XAnyClassPtr any;
401                 XKeyInfoPtr ki;
402                 XButtonInfoPtr bi;
403                 XValuatorInfoPtr vi;
404 
405                 for (j = 0, any = devices[i].inputclassinfo;
406                      j < devices[i].num_classes;
407                      any = (XAnyClassPtr) ((char *) any + any->length), j++) {
408                     switch (any->class) {
409                     case KeyClass:
410                         ki = (XKeyInfoPtr) any;
411                         info->keyboard = 1;
412                         info->keyClass = 1;
413                         info->keySyms.minKeyCode = ki->min_keycode;
414                         info->keySyms.maxKeyCode = ki->max_keycode;
415                         info->kbdFeedbackClass = 1;
416                         break;
417                     case ButtonClass:
418                         bi = (XButtonInfoPtr) any;
419                         info->buttonClass = 1;
420                         info->numButtons = bi->num_buttons;
421                         info->ptrFeedbackClass = 1;
422                         break;
423                     case ValuatorClass:
424                         /* This assume all axes are either
425                          * Absolute or Relative. */
426                         vi = (XValuatorInfoPtr) any;
427                         info->valuatorClass = 1;
428                         if (vi->mode == Absolute)
429                             info->numAbsAxes = vi->num_axes;
430                         else
431                             info->numRelAxes = vi->num_axes;
432                         for (k = 0; k < vi->num_axes; k++) {
433                             info->res[k] = vi->axes[k].resolution;
434                             info->minres[k] = vi->axes[k].resolution;
435                             info->maxres[k] = vi->axes[k].resolution;
436                             info->minval[k] = vi->axes[k].min_value;
437                             info->maxval[k] = vi->axes[k].max_value;
438                         }
439                         break;
440                     case FeedbackClass:
441                         /* Only keyboard and pointer feedback
442                          * are handled at this time. */
443                         break;
444                     case ProximityClass:
445                         info->proximityClass = 1;
446                         break;
447                     case FocusClass:
448                         info->focusClass = 1;
449                         break;
450                     case OtherClass:
451                         break;
452                     }
453                 }
454             }
455         }
456         XFreeDeviceList(devices);
457     }
458     if (display != priv->display)
459         XCloseDisplay(display);
460 }
461 
462 /** Obtain the mouse button mapping. */
463 void
dmxCommonMouGetMap(DevicePtr pDev,unsigned char * map,int * nButtons)464 dmxCommonMouGetMap(DevicePtr pDev, unsigned char *map, int *nButtons)
465 {
466     GETPRIVFROMPDEV;
467     int i;
468 
469     *nButtons = XGetPointerMapping(priv->display, map, DMX_MAX_BUTTONS);
470     for (i = 0; i <= *nButtons; i++)
471         map[i] = i;
472 }
473 
474 static void *
dmxCommonXSelect(DMXScreenInfo * dmxScreen,void * closure)475 dmxCommonXSelect(DMXScreenInfo * dmxScreen, void *closure)
476 {
477     myPrivate *priv = closure;
478 
479     XSelectInput(dmxScreen->beDisplay, dmxScreen->scrnWin, priv->eventMask);
480     return NULL;
481 }
482 
483 static void
dmxCommonFdNotify(int fd,int ready,void * data)484 dmxCommonFdNotify(int fd, int ready, void *data)
485 {
486     /* This should process input on this fd, but instead all
487      * of that is delayed until the block and wakeup handlers are called
488      */
489     ;
490 }
491 
492 static void *
dmxCommonAddEnabledDevice(DMXScreenInfo * dmxScreen,void * closure)493 dmxCommonAddEnabledDevice(DMXScreenInfo * dmxScreen, void *closure)
494 {
495     SetNotifyFd(XConnectionNumber(dmxScreen->beDisplay), dmxCommonFdNotify, X_NOTIFY_READ, closure);
496     return NULL;
497 }
498 
499 static void *
dmxCommonRemoveEnabledDevice(DMXScreenInfo * dmxScreen,void * closure)500 dmxCommonRemoveEnabledDevice(DMXScreenInfo * dmxScreen, void *closure)
501 {
502     RemoveNotifyFd(XConnectionNumber(dmxScreen->beDisplay));
503     return NULL;
504 }
505 
506 /** Turn \a pDev on (i.e., take input from \a pDev). */
507 int
dmxCommonMouOn(DevicePtr pDev)508 dmxCommonMouOn(DevicePtr pDev)
509 {
510     GETPRIVFROMPDEV;
511     GETDMXINPUTFROMPRIV;
512 
513     priv->eventMask |= DMX_POINTER_EVENT_MASK;
514     if (!priv->be) {
515         XSelectInput(priv->display, priv->window, priv->eventMask);
516         SetNotifyFd(XConnectionNumber(priv->display), dmxCommonFdNotify,X_NOTIFY_READ, pDev);
517     }
518     else {
519         dmxPropertyIterate(priv->be, dmxCommonXSelect, priv);
520         dmxPropertyIterate(priv->be, dmxCommonAddEnabledDevice, dmxInput);
521     }
522 
523     return -1;
524 }
525 
526 /** Turn \a pDev off. */
527 void
dmxCommonMouOff(DevicePtr pDev)528 dmxCommonMouOff(DevicePtr pDev)
529 {
530     GETPRIVFROMPDEV;
531     GETDMXINPUTFROMPRIV;
532 
533     priv->eventMask &= ~DMX_POINTER_EVENT_MASK;
534     if (!priv->be) {
535         RemoveNotifyFd(XConnectionNumber(priv->display));
536         XSelectInput(priv->display, priv->window, priv->eventMask);
537     }
538     else {
539         dmxPropertyIterate(priv->be, dmxCommonRemoveEnabledDevice, dmxInput);
540         dmxPropertyIterate(priv->be, dmxCommonXSelect, priv);
541     }
542 }
543 
544 /** Given the global coordinates \a x and \a y, determine the screen
545  * with the lowest number on which those coordinates lie.  If they are
546  * not on any screen, return -1.  The number returned is an index into
547  * \a dmxScreenInfo and is between -1 and \a dmxNumScreens - 1,
548  * inclusive. */
549 int
dmxFindPointerScreen(int x,int y)550 dmxFindPointerScreen(int x, int y)
551 {
552     int i;
553 
554     for (i = 0; i < dmxNumScreens; i++) {
555         ScreenPtr pScreen = screenInfo.screens[i];
556 
557         if (x >= pScreen->x && x < pScreen->x + pScreen->width &&
558             y >= pScreen->y && y < pScreen->y + pScreen->height)
559             return i;
560     }
561     return -1;
562 }
563 
564 /** Returns a pointer to the private area for the device that comes just
565  * prior to \a pDevice in the current \a dmxInput device list.  This is
566  * used as the private area for the current device in some situations
567  * (e.g., when a keyboard and mouse form a pair that should share the
568  * same private area).  If the requested private area cannot be located,
569  * then NULL is returned. */
570 void *
dmxCommonCopyPrivate(DeviceIntPtr pDevice)571 dmxCommonCopyPrivate(DeviceIntPtr pDevice)
572 {
573     GETDMXLOCALFROMPDEVICE;
574     DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
575     int i;
576 
577     for (i = 0; i < dmxInput->numDevs; i++)
578         if (dmxInput->devs[i] == dmxLocal && i)
579             return dmxInput->devs[i - 1]->private;
580     return NULL;
581 }
582 
583 /** This routine saves and resets some important state for the backend
584  * and console device drivers:
585  * - the modifier map is saved and set to 0 (so DMX controls the LEDs)
586  * - the key click, bell, led, and repeat masks are saved and set to the
587  * values that DMX claims to be using
588  *
589  * This routine and #dmxCommonRestoreState are used when the pointer
590  * enters and leaves the console window, or when the backend window is
591  * active or not active (for a full-screen window, this only happens at
592  * server startup and server shutdown).
593  */
594 void
dmxCommonSaveState(void * private)595 dmxCommonSaveState(void *private)
596 {
597     GETPRIVFROMPRIVATE;
598     XKeyboardState ks;
599     unsigned long i;
600     XModifierKeymap *modmap;
601 
602     if (dmxInput->console)
603         priv = dmxInput->devs[0]->private;
604     if (!priv->display || priv->stateSaved)
605         return;
606     DMXDBG0("dmxCommonSaveState\n");
607     if (dmxUseXKB && (priv->xkb = XkbAllocKeyboard())) {
608         if (XkbGetIndicatorMap(priv->display, XkbAllIndicatorsMask, priv->xkb)
609             || XkbGetNames(priv->display, XkbAllNamesMask, priv->xkb)) {
610             dmxLogInput(dmxInput, "Could not get XKB information\n");
611             XkbFreeKeyboard(priv->xkb, 0, True);
612             priv->xkb = NULL;
613         }
614         else {
615             if (priv->xkb->indicators) {
616                 priv->savedIndicators = *priv->xkb->indicators;
617                 for (i = 0; i < XkbNumIndicators; i++)
618                     if (priv->xkb->indicators->phys_indicators & (1 << i)) {
619                         priv->xkb->indicators->maps[i].flags
620                             = XkbIM_NoAutomatic;
621                     }
622                 XkbSetIndicatorMap(priv->display, ~0, priv->xkb);
623             }
624         }
625     }
626 
627     XGetKeyboardControl(priv->display, &ks);
628     priv->savedKctrl.click = ks.key_click_percent;
629     priv->savedKctrl.bell = ks.bell_percent;
630     priv->savedKctrl.bell_pitch = ks.bell_pitch;
631     priv->savedKctrl.bell_duration = ks.bell_duration;
632     priv->savedKctrl.leds = ks.led_mask;
633     priv->savedKctrl.autoRepeat = ks.global_auto_repeat;
634     for (i = 0; i < 32; i++)
635         priv->savedKctrl.autoRepeats[i] = ks.auto_repeats[i];
636 
637     dmxCommonKbdSetCtrl(priv->display, &priv->savedKctrl,
638                         &priv->dmxLocal->kctrl);
639 
640     priv->savedModMap = XGetModifierMapping(priv->display);
641 
642     modmap = XNewModifiermap(0);
643     XSetModifierMapping(priv->display, modmap);
644     if (dmxInput->scrnIdx != -1)
645         dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE);
646     XFreeModifiermap(modmap);
647 
648     priv->stateSaved = 1;
649 }
650 
651 /** This routine restores all the information saved by #dmxCommonSaveState. */
652 void
dmxCommonRestoreState(void * private)653 dmxCommonRestoreState(void *private)
654 {
655     GETPRIVFROMPRIVATE;
656     int retcode = -1;
657     CARD32 start;
658 
659     if (dmxInput->console)
660         priv = dmxInput->devs[0]->private;
661     if (!priv->stateSaved)
662         return;
663     priv->stateSaved = 0;
664 
665     DMXDBG0("dmxCommonRestoreState\n");
666     if (priv->xkb) {
667         *priv->xkb->indicators = priv->savedIndicators;
668         XkbSetIndicatorMap(priv->display, ~0, priv->xkb);
669         XkbFreeKeyboard(priv->xkb, 0, True);
670         priv->xkb = 0;
671     }
672 
673     for (start = GetTimeInMillis(); GetTimeInMillis() - start < 5000;) {
674         CARD32 tmp;
675 
676         retcode = XSetModifierMapping(priv->display, priv->savedModMap);
677         if (retcode == MappingSuccess)
678             break;
679         if (retcode == MappingBusy)
680             dmxLogInput(dmxInput, "Keyboard busy, waiting\n");
681         else
682             dmxLogInput(dmxInput, "Keyboard error, waiting\n");
683 
684         /* Don't generate X11 protocol for a bit */
685         for (tmp = GetTimeInMillis(); GetTimeInMillis() - tmp < 250;) {
686             usleep(250);        /* This ends up sleeping only until
687                                  * the next key press generates an
688                                  * interruption.  We make the delay
689                                  * relatively short in case the user
690                                  * pressed they keys quickly. */
691         }
692 
693     }
694     if (retcode != MappingSuccess)
695         dmxLog(dmxWarning, "Unable to restore keyboard modifier state!\n");
696 
697     XFreeModifiermap(priv->savedModMap);
698     priv->savedModMap = NULL;
699 
700     dmxCommonKbdSetCtrl(priv->display, NULL, &priv->savedKctrl);
701     priv->kctrlset = 0;         /* Invalidate copy */
702 }
703