Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / dmx / input / dmxcommon.c
CommitLineData
a09e091a
JB
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. */
70typedef struct _myPrivate {
71 DMX_COMMON_PRIVATE;
72} myPrivate;
73
74static void
75dmxCommonKbdSetAR(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
105static void
106dmxCommonKbdSetLeds(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
118static void
119dmxCommonKbdSetCtrl(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
136static void
137dmxCommonMouSetCtrl(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. */
154void
155dmxCommonKbdCtrl(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. */
170void
171dmxCommonMouCtrl(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. */
191void
192dmxCommonKbdBell(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. */
216void
217dmxCommonKbdGetMap(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. */
262void
263dmxCommonKbdGetInfo(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). */
293int
294dmxCommonKbdOn(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. */
308void
309dmxCommonKbdOff(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). */
318int
319dmxCommonOthOn(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 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. */
363void
364dmxCommonOthOff(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. */
375void
376dmxCommonOthGetInfo(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. */
463void
464dmxCommonMouGetMap(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
474static void *
475dmxCommonXSelect(DMXScreenInfo * dmxScreen, void *closure)
476{
477 myPrivate *priv = closure;
478
479 XSelectInput(dmxScreen->beDisplay, dmxScreen->scrnWin, priv->eventMask);
480 return NULL;
481}
482
483static void *
484dmxCommonAddEnabledDevice(DMXScreenInfo * dmxScreen, void *closure)
485{
486 AddEnabledDevice(XConnectionNumber(dmxScreen->beDisplay));
487 return NULL;
488}
489
490static void *
491dmxCommonRemoveEnabledDevice(DMXScreenInfo * dmxScreen, void *closure)
492{
493 RemoveEnabledDevice(XConnectionNumber(dmxScreen->beDisplay));
494 return NULL;
495}
496
497/** Turn \a pDev on (i.e., take input from \a pDev). */
498int
499dmxCommonMouOn(DevicePtr pDev)
500{
501 GETPRIVFROMPDEV;
502 GETDMXINPUTFROMPRIV;
503
504 priv->eventMask |= DMX_POINTER_EVENT_MASK;
505 if (!priv->be) {
506 XSelectInput(priv->display, priv->window, priv->eventMask);
507 AddEnabledDevice(XConnectionNumber(priv->display));
508 }
509 else {
510 dmxPropertyIterate(priv->be, dmxCommonXSelect, priv);
511 dmxPropertyIterate(priv->be, dmxCommonAddEnabledDevice, dmxInput);
512 }
513
514 return -1;
515}
516
517/** Turn \a pDev off. */
518void
519dmxCommonMouOff(DevicePtr pDev)
520{
521 GETPRIVFROMPDEV;
522 GETDMXINPUTFROMPRIV;
523
524 priv->eventMask &= ~DMX_POINTER_EVENT_MASK;
525 if (!priv->be) {
526 RemoveEnabledDevice(XConnectionNumber(priv->display));
527 XSelectInput(priv->display, priv->window, priv->eventMask);
528 }
529 else {
530 dmxPropertyIterate(priv->be, dmxCommonRemoveEnabledDevice, dmxInput);
531 dmxPropertyIterate(priv->be, dmxCommonXSelect, priv);
532 }
533}
534
535/** Given the global coordinates \a x and \a y, determine the screen
536 * with the lowest number on which those coordinates lie. If they are
537 * not on any screen, return -1. The number returned is an index into
538 * \a dmxScreenInfo and is between -1 and \a dmxNumScreens - 1,
539 * inclusive. */
540int
541dmxFindPointerScreen(int x, int y)
542{
543 int i;
544
545 for (i = 0; i < dmxNumScreens; i++) {
546 ScreenPtr pScreen = screenInfo.screens[i];
547
548 if (x >= pScreen->x && x < pScreen->x + pScreen->width &&
549 y >= pScreen->y && y < pScreen->y + pScreen->height)
550 return i;
551 }
552 return -1;
553}
554
555/** Returns a pointer to the private area for the device that comes just
556 * prior to \a pDevice in the current \a dmxInput device list. This is
557 * used as the private area for the current device in some situations
558 * (e.g., when a keyboard and mouse form a pair that should share the
559 * same private area). If the requested private area cannot be located,
560 * then NULL is returned. */
561pointer
562dmxCommonCopyPrivate(DeviceIntPtr pDevice)
563{
564 GETDMXLOCALFROMPDEVICE;
565 DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
566 int i;
567
568 for (i = 0; i < dmxInput->numDevs; i++)
569 if (dmxInput->devs[i] == dmxLocal && i)
570 return dmxInput->devs[i - 1]->private;
571 return NULL;
572}
573
574/** This routine saves and resets some important state for the backend
575 * and console device drivers:
576 * - the modifier map is saved and set to 0 (so DMX controls the LEDs)
577 * - the key click, bell, led, and repeat masks are saved and set to the
578 * values that DMX claims to be using
579 *
580 * This routine and #dmxCommonRestoreState are used when the pointer
581 * enters and leaves the console window, or when the backend window is
582 * active or not active (for a full-screen window, this only happens at
583 * server startup and server shutdown).
584 */
585void
586dmxCommonSaveState(pointer private)
587{
588 GETPRIVFROMPRIVATE;
589 XKeyboardState ks;
590 unsigned long i;
591 XModifierKeymap *modmap;
592
593 if (dmxInput->console)
594 priv = dmxInput->devs[0]->private;
595 if (!priv->display || priv->stateSaved)
596 return;
597 DMXDBG0("dmxCommonSaveState\n");
598 if (dmxUseXKB && (priv->xkb = XkbAllocKeyboard())) {
599 if (XkbGetIndicatorMap(priv->display, XkbAllIndicatorsMask, priv->xkb)
600 || XkbGetNames(priv->display, XkbAllNamesMask, priv->xkb)) {
601 dmxLogInput(dmxInput, "Could not get XKB information\n");
602 XkbFreeKeyboard(priv->xkb, 0, True);
603 priv->xkb = NULL;
604 }
605 else {
606 if (priv->xkb->indicators) {
607 priv->savedIndicators = *priv->xkb->indicators;
608 for (i = 0; i < XkbNumIndicators; i++)
609 if (priv->xkb->indicators->phys_indicators & (1 << i)) {
610 priv->xkb->indicators->maps[i].flags
611 = XkbIM_NoAutomatic;
612 }
613 XkbSetIndicatorMap(priv->display, ~0, priv->xkb);
614 }
615 }
616 }
617
618 XGetKeyboardControl(priv->display, &ks);
619 priv->savedKctrl.click = ks.key_click_percent;
620 priv->savedKctrl.bell = ks.bell_percent;
621 priv->savedKctrl.bell_pitch = ks.bell_pitch;
622 priv->savedKctrl.bell_duration = ks.bell_duration;
623 priv->savedKctrl.leds = ks.led_mask;
624 priv->savedKctrl.autoRepeat = ks.global_auto_repeat;
625 for (i = 0; i < 32; i++)
626 priv->savedKctrl.autoRepeats[i] = ks.auto_repeats[i];
627
628 dmxCommonKbdSetCtrl(priv->display, &priv->savedKctrl,
629 &priv->dmxLocal->kctrl);
630
631 priv->savedModMap = XGetModifierMapping(priv->display);
632
633 modmap = XNewModifiermap(0);
634 XSetModifierMapping(priv->display, modmap);
635 if (dmxInput->scrnIdx != -1)
636 dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE);
637 XFreeModifiermap(modmap);
638
639 priv->stateSaved = 1;
640}
641
642/** This routine restores all the information saved by #dmxCommonSaveState. */
643void
644dmxCommonRestoreState(pointer private)
645{
646 GETPRIVFROMPRIVATE;
647 int retcode = -1;
648 CARD32 start;
649
650 if (dmxInput->console)
651 priv = dmxInput->devs[0]->private;
652 if (!priv->stateSaved)
653 return;
654 priv->stateSaved = 0;
655
656 DMXDBG0("dmxCommonRestoreState\n");
657 if (priv->xkb) {
658 *priv->xkb->indicators = priv->savedIndicators;
659 XkbSetIndicatorMap(priv->display, ~0, priv->xkb);
660 XkbFreeKeyboard(priv->xkb, 0, True);
661 priv->xkb = 0;
662 }
663
664 for (start = GetTimeInMillis(); GetTimeInMillis() - start < 5000;) {
665 CARD32 tmp;
666
667 retcode = XSetModifierMapping(priv->display, priv->savedModMap);
668 if (retcode == MappingSuccess)
669 break;
670 if (retcode == MappingBusy)
671 dmxLogInput(dmxInput, "Keyboard busy, waiting\n");
672 else
673 dmxLogInput(dmxInput, "Keyboard error, waiting\n");
674
675 /* Don't generate X11 protocol for a bit */
676 for (tmp = GetTimeInMillis(); GetTimeInMillis() - tmp < 250;) {
677 usleep(250); /* This ends up sleeping only until
678 * the next key press generates an
679 * interruption. We make the delay
680 * relatively short in case the user
681 * pressed they keys quickly. */
682 }
683
684 }
685 if (retcode != MappingSuccess)
686 dmxLog(dmxWarning, "Unable to restore keyboard modifier state!\n");
687
688 XFreeModifiermap(priv->savedModMap);
689 priv->savedModMap = NULL;
690
691 dmxCommonKbdSetCtrl(priv->display, NULL, &priv->savedKctrl);
692 priv->kctrlset = 0; /* Invalidate copy */
693}