Commit | Line | Data |
---|---|---|
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. */ | |
70 | typedef struct _myPrivate { | |
71 | DMX_COMMON_PRIVATE; | |
72 | } myPrivate; | |
73 | ||
74 | static void | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | 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 | |
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 | |
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 | |
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 * | |
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 * | |
484 | dmxCommonAddEnabledDevice(DMXScreenInfo * dmxScreen, void *closure) | |
485 | { | |
486 | AddEnabledDevice(XConnectionNumber(dmxScreen->beDisplay)); | |
487 | return NULL; | |
488 | } | |
489 | ||
490 | static void * | |
491 | dmxCommonRemoveEnabledDevice(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). */ | |
498 | int | |
499 | dmxCommonMouOn(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. */ | |
518 | void | |
519 | dmxCommonMouOff(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. */ | |
540 | int | |
541 | dmxFindPointerScreen(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. */ | |
561 | pointer | |
562 | dmxCommonCopyPrivate(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 | */ | |
585 | void | |
586 | dmxCommonSaveState(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. */ | |
643 | void | |
644 | dmxCommonRestoreState(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 | } |