Home | History | Annotate | Line # | Download | only in input
      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 (at) xfree86.org>
     31  *   Kevin E. Martin <kem (at) redhat.com>
     32  *   Rickard E. (Rik) Faith <faith (at) 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,
     75                               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 {
    107     int              i;
    108     XKeyboardControl kc;
    109 
    110     for (i = 0; i < 32; i++) {
    111         kc.led      = i + 1;
    112         kc.led_mode = (new & (1 << i)) ? LedModeOn : LedModeOff;
    113         XChangeKeyboardControl(display, KBLed | KBLedMode, &kc);
    114     }
    115 }
    116 
    117 static void dmxCommonKbdSetCtrl(Display *display,
    118                                 KeybdCtrl *old, KeybdCtrl *new)
    119 {
    120     XKeyboardControl kc;
    121     unsigned long    mask = KBKeyClickPercent | KBAutoRepeatMode;
    122 
    123     if (!old
    124         || old->click         != new->click
    125         || old->autoRepeat    != new->autoRepeat) {
    126 
    127         kc.key_click_percent = new->click;
    128         kc.auto_repeat_mode  = new->autoRepeat;
    129 
    130         XChangeKeyboardControl(display, mask, &kc);
    131     }
    132 
    133     dmxCommonKbdSetLeds(display, new->leds);
    134     dmxCommonKbdSetAR(display, old ? old->autoRepeats : NULL,
    135                       new->autoRepeats);
    136 }
    137 
    138 static void dmxCommonMouSetCtrl(Display *display, PtrCtrl *old, PtrCtrl *new)
    139 {
    140     Bool do_accel, do_threshold;
    141 
    142     if (!old
    143         || old->num != new->num
    144         || old->den != new->den
    145         || old->threshold != new->threshold) {
    146         do_accel     = (new->num > 0 && new->den > 0);
    147         do_threshold = (new->threshold > 0);
    148         if (do_accel || do_threshold) {
    149             XChangePointerControl(display, do_accel, do_threshold,
    150                                   new->num, new->den, new->threshold);
    151         }
    152     }
    153 }
    154 
    155 /** Update the keyboard control. */
    156 void dmxCommonKbdCtrl(DevicePtr pDev, KeybdCtrl *ctrl)
    157 {
    158     GETPRIVFROMPDEV;
    159 
    160     if (!priv->stateSaved && priv->be) dmxCommonSaveState(priv);
    161     if (!priv->display || !priv->stateSaved) return;
    162     dmxCommonKbdSetCtrl(priv->display,
    163                         priv->kctrlset ? &priv->kctrl : NULL,
    164                         ctrl);
    165     priv->kctrl    = *ctrl;
    166     priv->kctrlset = 1;
    167 }
    168 
    169 /** Update the mouse control. */
    170 void dmxCommonMouCtrl(DevicePtr pDev, PtrCtrl *ctrl)
    171 {
    172     GETPRIVFROMPDEV;
    173 
    174                                 /* Don't set the acceleration for the
    175                                  * console, because that should be
    176                                  * controlled by the X server that the
    177                                  * console is running on.  Otherwise,
    178                                  * the acceleration for the console
    179                                  * window would be unexpected for the
    180                                  * scale of the window. */
    181     if (priv->be) {
    182         dmxCommonMouSetCtrl(priv->display,
    183                             priv->mctrlset ? &priv->mctrl : NULL,
    184                             ctrl);
    185         priv->mctrl    = *ctrl;
    186         priv->mctrlset = 1;
    187     }
    188 }
    189 
    190 /** Sound they keyboard bell. */
    191 void dmxCommonKbdBell(DevicePtr pDev, int percent,
    192                       int volume, int pitch, int duration)
    193 {
    194     GETPRIVFROMPDEV;
    195     XKeyboardControl kc;
    196     XKeyboardState   ks;
    197     unsigned long    mask = KBBellPercent | KBBellPitch | KBBellDuration;
    198 
    199     if (!priv->be) XGetKeyboardControl(priv->display, &ks);
    200     kc.bell_percent  = volume;
    201     kc.bell_pitch    = pitch;
    202     kc.bell_duration = duration;
    203     XChangeKeyboardControl(priv->display, mask, &kc);
    204     XBell(priv->display, percent);
    205     if (!priv->be) {
    206         kc.bell_percent  = ks.bell_percent;
    207         kc.bell_pitch    = ks.bell_pitch;
    208         kc.bell_duration = ks.bell_duration;
    209         XChangeKeyboardControl(priv->display, mask, &kc);
    210     }
    211 }
    212 
    213 /** Get the keyboard mapping. */
    214 void dmxCommonKbdGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap)
    215 {
    216     GETPRIVFROMPDEV;
    217     int             min_keycode;
    218     int             max_keycode;
    219     int             map_width;
    220     KeySym          *keyboard_mapping;
    221     XModifierKeymap *modifier_mapping;
    222     int             i, j;
    223 
    224                                 /* Compute pKeySyms.  Cast
    225                                  * XGetKeyboardMapping because of
    226                                  * compiler warning on 64-bit machines.
    227                                  * We assume pointers to 32-bit and
    228                                  * 64-bit ints are the same. */
    229     XDisplayKeycodes(priv->display, &min_keycode, &max_keycode);
    230     keyboard_mapping     = (KeySym *)XGetKeyboardMapping(priv->display,
    231                                                          min_keycode,
    232                                                          max_keycode
    233                                                          - min_keycode + 1,
    234                                                          &map_width);
    235     pKeySyms->minKeyCode = min_keycode;
    236     pKeySyms->maxKeyCode = max_keycode;
    237     pKeySyms->mapWidth   = map_width;
    238     pKeySyms->map        = keyboard_mapping;
    239 
    240 
    241                                 /* Compute pModMap  */
    242     modifier_mapping     = XGetModifierMapping(priv->display);
    243     for (i = 0; i < MAP_LENGTH; i++)
    244         pModMap[i] = 0;
    245     for (j = 0; j < 8; j++) {
    246         int max_keypermod = modifier_mapping->max_keypermod;
    247 
    248         for (i = 0; i < max_keypermod; i++) {
    249             CARD8 keycode = modifier_mapping->modifiermap[j*max_keypermod + i];
    250             if (keycode)
    251                 pModMap[keycode] |= 1 << j;
    252         }
    253     }
    254     XFreeModifiermap(modifier_mapping);
    255 }
    256 
    257 /** Fill in the XKEYBOARD parts of the \a info structure for the
    258  * specified \a pDev. */
    259 void dmxCommonKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
    260 {
    261     GETPRIVFROMPDEV;
    262     GETDMXINPUTFROMPRIV;
    263     char *pt;
    264 
    265     dmxCommonSaveState(priv);
    266     if (priv->xkb) {
    267 #define NAME(x) \
    268  priv->xkb->names->x ? XGetAtomName(priv->display,priv->xkb->names->x) : NULL
    269         info->names.keycodes = NAME(keycodes);
    270         info->names.types    = NAME(types);
    271         info->names.compat   = NAME(compat);
    272         info->names.symbols  = NAME(symbols);
    273         info->names.geometry = NAME(geometry);
    274         info->freenames      = 1;
    275 #undef NAME
    276         dmxLogInput(dmxInput,
    277                     "XKEYBOARD: keycodes = %s\n", info->names.keycodes);
    278         dmxLogInput(dmxInput,
    279                     "XKEYBOARD: symbols  = %s\n", info->names.symbols);
    280         dmxLogInput(dmxInput,
    281                     "XKEYBOARD: geometry = %s\n", info->names.geometry);
    282         if ((pt = strchr(info->names.keycodes, '+'))) *pt = '\0';
    283     }
    284     dmxCommonRestoreState(priv);
    285 }
    286 
    287 /** Turn \a pDev on (i.e., take input from \a pDev). */
    288 int dmxCommonKbdOn(DevicePtr pDev)
    289 {
    290     GETPRIVFROMPDEV;
    291     if (priv->be) dmxCommonSaveState(priv);
    292     priv->eventMask |= DMX_KEYBOARD_EVENT_MASK;
    293     XSelectInput(priv->display, priv->window, priv->eventMask);
    294     if (priv->be)
    295         XSetInputFocus(priv->display, priv->window, RevertToPointerRoot,
    296                        CurrentTime);
    297     return -1;
    298 }
    299 
    300 /** Turn \a pDev off. */
    301 void dmxCommonKbdOff(DevicePtr pDev)
    302 {
    303     GETPRIVFROMPDEV;
    304     priv->eventMask &= ~DMX_KEYBOARD_EVENT_MASK;
    305     XSelectInput(priv->display, priv->window, priv->eventMask);
    306     dmxCommonRestoreState(priv);
    307 }
    308 
    309 /** Turn \a pDev on (i.e., take input from \a pDev). */
    310 int dmxCommonOthOn(DevicePtr pDev)
    311 {
    312     GETPRIVFROMPDEV;
    313     GETDMXINPUTFROMPRIV;
    314     XEventClass event_list[DMX_MAX_XINPUT_EVENT_TYPES];
    315     int         event_type[DMX_MAX_XINPUT_EVENT_TYPES];
    316     int         count = 0;
    317 
    318 #define ADD(type)                                                            \
    319     if (count < DMX_MAX_XINPUT_EVENT_TYPES) {                                \
    320         type(priv->xi, event_type[count], event_list[count]);                \
    321         if (event_type[count]) {                                             \
    322             dmxMapInsert(dmxLocal, event_type[count], XI_##type);            \
    323             ++count;                                                         \
    324         }                                                                    \
    325     } else {                                                                 \
    326         dmxLog(dmxWarning, "More than %d event types for %s\n",              \
    327                DMX_MAX_XINPUT_EVENT_TYPES, dmxInput->name);                  \
    328     }
    329 
    330     if (!(priv->xi = XOpenDevice(priv->display, dmxLocal->deviceId))) {
    331         dmxLog(dmxWarning, "Cannot open %s device (id=%d) on %s\n",
    332                dmxLocal->deviceName ? dmxLocal->deviceName : "(unknown)",
    333                dmxLocal->deviceId, dmxInput->name);
    334         return -1;
    335     }
    336     ADD(DeviceKeyPress);
    337     ADD(DeviceKeyRelease);
    338     ADD(DeviceButtonPress);
    339     ADD(DeviceButtonRelease);
    340     ADD(DeviceMotionNotify);
    341     ADD(DeviceFocusIn);
    342     ADD(DeviceFocusOut);
    343     ADD(ProximityIn);
    344     ADD(ProximityOut);
    345     ADD(DeviceStateNotify);
    346     ADD(DeviceMappingNotify);
    347     ADD(ChangeDeviceNotify);
    348     XSelectExtensionEvent(priv->display, priv->window, event_list, count);
    349 
    350     return -1;
    351 }
    352 
    353 /** Turn \a pDev off. */
    354 void dmxCommonOthOff(DevicePtr pDev)
    355 {
    356     GETPRIVFROMPDEV;
    357 
    358     if (priv->xi) XCloseDevice(priv->display, priv->xi);
    359     priv->xi = NULL;
    360 }
    361 
    362 /** Fill the \a info structure with information needed to initialize \a
    363  * pDev. */
    364 void dmxCommonOthGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
    365 {
    366     GETPRIVFROMPDEV;
    367     GETDMXINPUTFROMPRIV;
    368     XExtensionVersion    *ext;
    369     XDeviceInfo          *devices;
    370     Display              *display = priv->display;
    371     int                  num;
    372     int                  i, j, k;
    373     XextErrorHandler     handler;
    374 
    375     if (!display && !(display = XOpenDisplay(dmxInput->name)))
    376         return;
    377 
    378     /* Print out information about the XInput Extension. */
    379     handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler);
    380     ext     = XGetExtensionVersion(display, INAME);
    381     XSetExtensionErrorHandler(handler);
    382 
    383     if (ext && ext != (XExtensionVersion *)NoSuchExtension) {
    384         XFree(ext);
    385         devices = XListInputDevices(display, &num);
    386         for (i = 0; i < num; i++) {
    387             if (devices[i].id == (XID)dmxLocal->deviceId) {
    388                 XAnyClassPtr     any;
    389                 XKeyInfoPtr      ki;
    390                 XButtonInfoPtr   bi;
    391                 XValuatorInfoPtr vi;
    392                 for (j = 0, any = devices[i].inputclassinfo;
    393                      j < devices[i].num_classes;
    394                      any = (XAnyClassPtr)((char *)any + any->length), j++) {
    395                     switch (any->class) {
    396                     case KeyClass:
    397                         ki = (XKeyInfoPtr)any;
    398                         info->keyboard           = 1;
    399                         info->keyClass           = 1;
    400                         info->keySyms.minKeyCode = ki->min_keycode;
    401                         info->keySyms.maxKeyCode = ki->max_keycode;
    402                         info->kbdFeedbackClass   = 1;
    403                         break;
    404                     case ButtonClass:
    405                         bi = (XButtonInfoPtr)any;
    406                         info->buttonClass        = 1;
    407                         info->numButtons         = bi->num_buttons;
    408                         info->ptrFeedbackClass   = 1;
    409                         break;
    410                     case ValuatorClass:
    411                                 /* This assume all axes are either
    412                                  * Absolute or Relative. */
    413                         vi = (XValuatorInfoPtr)any;
    414                         info->valuatorClass      = 1;
    415                         if (vi->mode == Absolute)
    416                             info->numAbsAxes     = vi->num_axes;
    417                         else
    418                             info->numRelAxes     = vi->num_axes;
    419                         for (k = 0; k < vi->num_axes; k++) {
    420                             info->res[k]         = vi->axes[k].resolution;
    421                             info->minres[k]      = vi->axes[k].resolution;
    422                             info->maxres[k]      = vi->axes[k].resolution;
    423                             info->minval[k]      = vi->axes[k].min_value;
    424                             info->maxval[k]      = vi->axes[k].max_value;
    425                         }
    426                         break;
    427                     case FeedbackClass:
    428                                 /* Only keyboard and pointer feedback
    429                                  * are handled at this time. */
    430                         break;
    431                     case ProximityClass:
    432                         info->proximityClass     = 1;
    433                         break;
    434                     case FocusClass:
    435                         info->focusClass         = 1;
    436                         break;
    437                     case OtherClass:
    438                         break;
    439                     }
    440                 }
    441             }
    442         }
    443         XFreeDeviceList(devices);
    444     }
    445     if (display != priv->display) XCloseDisplay(display);
    446 }
    447 
    448 /** Obtain the mouse button mapping. */
    449 void dmxCommonMouGetMap(DevicePtr pDev, unsigned char *map, int *nButtons)
    450 {
    451     GETPRIVFROMPDEV;
    452     int i;
    453 
    454     *nButtons = XGetPointerMapping(priv->display, map, DMX_MAX_BUTTONS);
    455     for (i = 0; i <= *nButtons; i++) map[i] = i;
    456 }
    457 
    458 static void *dmxCommonXSelect(DMXScreenInfo *dmxScreen, void *closure)
    459 {
    460     myPrivate *priv = closure;
    461     XSelectInput(dmxScreen->beDisplay, dmxScreen->scrnWin, priv->eventMask);
    462     return NULL;
    463 }
    464 
    465 static void *dmxCommonAddEnabledDevice(DMXScreenInfo *dmxScreen, void *closure)
    466 {
    467     AddEnabledDevice(XConnectionNumber(dmxScreen->beDisplay));
    468     return NULL;
    469 }
    470 
    471 static void *dmxCommonRemoveEnabledDevice(DMXScreenInfo *dmxScreen,
    472                                           void *closure)
    473 {
    474     RemoveEnabledDevice(XConnectionNumber(dmxScreen->beDisplay));
    475     return NULL;
    476 }
    477 
    478 /** Turn \a pDev on (i.e., take input from \a pDev). */
    479 int dmxCommonMouOn(DevicePtr pDev)
    480 {
    481     GETPRIVFROMPDEV;
    482     GETDMXINPUTFROMPRIV;
    483 
    484     priv->eventMask |= DMX_POINTER_EVENT_MASK;
    485     if (dmxShadowFB) {
    486         XWarpPointer(priv->display, priv->window, priv->window,
    487                      0, 0, 0, 0,
    488                      priv->initPointerX,
    489                      priv->initPointerY);
    490         dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE);
    491     }
    492     if (!priv->be) {
    493         XSelectInput(priv->display, priv->window, priv->eventMask);
    494         AddEnabledDevice(XConnectionNumber(priv->display));
    495     } else {
    496         dmxPropertyIterate(priv->be, dmxCommonXSelect, priv);
    497         dmxPropertyIterate(priv->be, dmxCommonAddEnabledDevice, dmxInput);
    498     }
    499 
    500     return -1;
    501 }
    502 
    503 /** Turn \a pDev off. */
    504 void dmxCommonMouOff(DevicePtr pDev)
    505 {
    506     GETPRIVFROMPDEV;
    507     GETDMXINPUTFROMPRIV;
    508 
    509     priv->eventMask &= ~DMX_POINTER_EVENT_MASK;
    510     if (!priv->be) {
    511         RemoveEnabledDevice(XConnectionNumber(priv->display));
    512         XSelectInput(priv->display, priv->window, priv->eventMask);
    513     } else {
    514         dmxPropertyIterate(priv->be, dmxCommonRemoveEnabledDevice, dmxInput);
    515         dmxPropertyIterate(priv->be, dmxCommonXSelect, priv);
    516     }
    517 }
    518 
    519 /** Given the global coordinates \a x and \a y, determine the screen
    520  * with the lowest number on which those coordinates lie.  If they are
    521  * not on any screen, return -1.  The number returned is an index into
    522  * \a dmxScreenInfo and is between -1 and \a dmxNumScreens - 1,
    523  * inclusive. */
    524 int dmxFindPointerScreen(int x, int y)
    525 {
    526     int i;
    527 
    528     for (i = 0; i < dmxNumScreens; i++) {
    529 	ScreenPtr pScreen = screenInfo.screens[i];
    530 	if (x >= pScreen->x && x < pScreen->x + pScreen->width &&
    531 	    y >= pScreen->y && y < pScreen->y + pScreen->height)
    532 	    return i;
    533     }
    534     return -1;
    535 }
    536 
    537 /** Returns a pointer to the private area for the device that comes just
    538  * prior to \a pDevice in the current \a dmxInput device list.  This is
    539  * used as the private area for the current device in some situations
    540  * (e.g., when a keyboard and mouse form a pair that should share the
    541  * same private area).  If the requested private area cannot be located,
    542  * then NULL is returned. */
    543 pointer dmxCommonCopyPrivate(DeviceIntPtr pDevice)
    544 {
    545     GETDMXLOCALFROMPDEVICE;
    546     DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
    547     int          i;
    548 
    549     for (i = 0; i < dmxInput->numDevs; i++)
    550         if (dmxInput->devs[i] == dmxLocal && i)
    551             return dmxInput->devs[i-1]->private;
    552     return NULL;
    553 }
    554 
    555 /** This routine saves and resets some important state for the backend
    556  * and console device drivers:
    557  * - the modifier map is saved and set to 0 (so DMX controls the LEDs)
    558  * - the key click, bell, led, and repeat masks are saved and set to the
    559  * values that DMX claims to be using
    560  *
    561  * This routine and #dmxCommonRestoreState are used when the pointer
    562  * enters and leaves the console window, or when the backend window is
    563  * active or not active (for a full-screen window, this only happens at
    564  * server startup and server shutdown).
    565  */
    566 void dmxCommonSaveState(pointer private)
    567 {
    568     GETPRIVFROMPRIVATE;
    569     XKeyboardState   ks;
    570     unsigned long    i;
    571     XModifierKeymap  *modmap;
    572 
    573     if (dmxInput->console) priv = dmxInput->devs[0]->private;
    574     if (!priv->display || priv->stateSaved) return;
    575     DMXDBG0("dmxCommonSaveState\n");
    576     if (dmxUseXKB && (priv->xkb = XkbAllocKeyboard())) {
    577         if (XkbGetIndicatorMap(priv->display, XkbAllIndicatorsMask, priv->xkb)
    578             || XkbGetNames(priv->display, XkbAllNamesMask, priv->xkb)) {
    579             dmxLogInput(dmxInput, "Could not get XKB information\n");
    580             XkbFreeKeyboard(priv->xkb, 0, True);
    581             priv->xkb = NULL;
    582         } else {
    583             if (priv->xkb->indicators) {
    584                 priv->savedIndicators = *priv->xkb->indicators;
    585                 for (i = 0; i < XkbNumIndicators; i++)
    586                     if (priv->xkb->indicators->phys_indicators & (1 << i)) {
    587                         priv->xkb->indicators->maps[i].flags
    588                             = XkbIM_NoAutomatic;
    589                     }
    590                 XkbSetIndicatorMap(priv->display, ~0, priv->xkb);
    591             }
    592         }
    593     }
    594 
    595     XGetKeyboardControl(priv->display, &ks);
    596     priv->savedKctrl.click              = ks.key_click_percent;
    597     priv->savedKctrl.bell               = ks.bell_percent;
    598     priv->savedKctrl.bell_pitch         = ks.bell_pitch;
    599     priv->savedKctrl.bell_duration      = ks.bell_duration;
    600     priv->savedKctrl.leds               = ks.led_mask;
    601     priv->savedKctrl.autoRepeat         = ks.global_auto_repeat;
    602     for (i = 0; i < 32; i++)
    603         priv->savedKctrl.autoRepeats[i] = ks.auto_repeats[i];
    604 
    605     dmxCommonKbdSetCtrl(priv->display, &priv->savedKctrl,
    606                         &priv->dmxLocal->kctrl);
    607 
    608     priv->savedModMap                   = XGetModifierMapping(priv->display);
    609 
    610     modmap                              = XNewModifiermap(0);
    611     XSetModifierMapping(priv->display, modmap);
    612     if (dmxInput->scrnIdx != -1)
    613         dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE);
    614     XFreeModifiermap(modmap);
    615 
    616     priv->stateSaved = 1;
    617 }
    618 
    619 /** This routine restores all the information saved by #dmxCommonSaveState. */
    620 void dmxCommonRestoreState(pointer private)
    621 {
    622     GETPRIVFROMPRIVATE;
    623     int retcode = -1;
    624     CARD32 start;
    625 
    626     if (dmxInput->console)
    627         priv = dmxInput->devs[0]->private;
    628     if (!priv->stateSaved)
    629         return;
    630     priv->stateSaved = 0;
    631 
    632     DMXDBG0("dmxCommonRestoreState\n");
    633     if (priv->xkb) {
    634         *priv->xkb->indicators = priv->savedIndicators;
    635         XkbSetIndicatorMap(priv->display, ~0, priv->xkb);
    636         XkbFreeKeyboard(priv->xkb, 0, True);
    637         priv->xkb = 0;
    638     }
    639 
    640     for (start = GetTimeInMillis(); GetTimeInMillis() - start < 5000;) {
    641         CARD32 tmp;
    642 
    643         retcode = XSetModifierMapping(priv->display, priv->savedModMap);
    644         if (retcode == MappingSuccess)
    645             break;
    646         if (retcode == MappingBusy)
    647             dmxLogInput(dmxInput, "Keyboard busy, waiting\n");
    648         else
    649             dmxLogInput(dmxInput, "Keyboard error, waiting\n");
    650 
    651                                 /* Don't generate X11 protocol for a bit */
    652         for (tmp = GetTimeInMillis(); GetTimeInMillis() - tmp < 250;) {
    653             usleep(250);            /* This ends up sleeping only until
    654                                      * the next key press generates an
    655                                      * interruption.  We make the delay
    656                                      * relatively short in case the user
    657                                      * pressed they keys quickly. */
    658         }
    659 
    660     }
    661     if (retcode != MappingSuccess)
    662         dmxLog(dmxWarning, "Unable to restore keyboard modifier state!\n");
    663 
    664     XFreeModifiermap(priv->savedModMap);
    665     priv->savedModMap = NULL;
    666 
    667     dmxCommonKbdSetCtrl(priv->display, NULL, &priv->savedKctrl);
    668     priv->kctrlset = 0;         /* Invalidate copy */
    669 }
    670