2 * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina.
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:
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.
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
30 * David H. Dawes <dawes@xfree86.org>
31 * Kevin E. Martin <kem@redhat.com>
32 * Rickard E. (Rik) Faith <faith@redhat.com>
37 * This file implements common routines used by the backend and console
41 #ifdef HAVE_DMX_CONFIG_H
42 #include <dmx-config.h>
45 #define DMX_STATE_DEBUG 0
47 #include "dmxinputinit.h"
48 #include "dmxcommon.h"
49 #include "dmxconsole.h"
56 #include <X11/keysym.h>
57 #include "mipointer.h"
58 #include "scrnintstr.h"
60 #include <unistd.h> /* For usleep() */
63 #define DMXDBG0(f) dmxLog(dmxDebug,f)
68 /** Each device has a private area that is visible only from inside the
70 typedef struct _myPrivate
{
75 dmxCommonKbdSetAR(Display
* display
, unsigned char *old
, unsigned char *new)
79 unsigned long mask
= KBKey
| KBAutoRepeatMode
;
81 int minKeycode
, maxKeycode
;
84 XGetKeyboardControl(display
, &ks
);
85 old
= (unsigned char *) ks
.auto_repeats
;
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
))) {
94 kc
.auto_repeat_mode
= ((new[i
] & (1 << j
))
97 if (kc
.key
>= minKeycode
&& kc
.key
<= maxKeycode
)
98 XChangeKeyboardControl(display
, mask
, &kc
);
106 dmxCommonKbdSetLeds(Display
* display
, unsigned long new)
111 for (i
= 0; i
< 32; i
++) {
113 kc
.led_mode
= (new & (1 << i
)) ? LedModeOn
: LedModeOff
;
114 XChangeKeyboardControl(display
, KBLed
| KBLedMode
, &kc
);
119 dmxCommonKbdSetCtrl(Display
* display
, KeybdCtrl
* old
, KeybdCtrl
* new)
122 unsigned long mask
= KBKeyClickPercent
| KBAutoRepeatMode
;
124 if (!old
|| old
->click
!= new->click
|| old
->autoRepeat
!= new->autoRepeat
) {
126 kc
.key_click_percent
= new->click
;
127 kc
.auto_repeat_mode
= new->autoRepeat
;
129 XChangeKeyboardControl(display
, mask
, &kc
);
132 dmxCommonKbdSetLeds(display
, new->leds
);
133 dmxCommonKbdSetAR(display
, old
? old
->autoRepeats
: NULL
, new->autoRepeats
);
137 dmxCommonMouSetCtrl(Display
* display
, PtrCtrl
* old
, PtrCtrl
* new)
139 Bool do_accel
, do_threshold
;
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
);
153 /** Update the keyboard control. */
155 dmxCommonKbdCtrl(DevicePtr pDev
, KeybdCtrl
* ctrl
)
159 if (!priv
->stateSaved
&& priv
->be
)
160 dmxCommonSaveState(priv
);
161 if (!priv
->display
|| !priv
->stateSaved
)
163 dmxCommonKbdSetCtrl(priv
->display
,
164 priv
->kctrlset
? &priv
->kctrl
: NULL
, ctrl
);
169 /** Update the mouse control. */
171 dmxCommonMouCtrl(DevicePtr pDev
, PtrCtrl
* ctrl
)
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. */
183 dmxCommonMouSetCtrl(priv
->display
,
184 priv
->mctrlset
? &priv
->mctrl
: NULL
, ctrl
);
190 /** Sound they keyboard bell. */
192 dmxCommonKbdBell(DevicePtr pDev
, int percent
,
193 int volume
, int pitch
, int duration
)
198 unsigned long mask
= KBBellPercent
| KBBellPitch
| KBBellDuration
;
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
);
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
);
215 /** Get the keyboard mapping. */
217 dmxCommonKbdGetMap(DevicePtr pDev
, KeySymsPtr pKeySyms
, CARD8
*pModMap
)
223 KeySym
*keyboard_mapping
;
224 XModifierKeymap
*modifier_mapping
;
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
,
238 pKeySyms
->minKeyCode
= min_keycode
;
239 pKeySyms
->maxKeyCode
= max_keycode
;
240 pKeySyms
->mapWidth
= map_width
;
241 pKeySyms
->map
= keyboard_mapping
;
243 /* Compute pModMap */
244 modifier_mapping
= XGetModifierMapping(priv
->display
);
245 for (i
= 0; i
< MAP_LENGTH
; i
++)
247 for (j
= 0; j
< 8; j
++) {
248 int max_keypermod
= modifier_mapping
->max_keypermod
;
250 for (i
= 0; i
< max_keypermod
; i
++) {
252 modifier_mapping
->modifiermap
[j
* max_keypermod
+ i
];
254 pModMap
[keycode
] |= 1 << j
;
257 XFreeModifiermap(modifier_mapping
);
260 /** Fill in the XKEYBOARD parts of the \a info structure for the
261 * specified \a pDev. */
263 dmxCommonKbdGetInfo(DevicePtr pDev
, DMXLocalInitInfoPtr info
)
269 dmxCommonSaveState(priv
);
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
);
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
, '+')))
289 dmxCommonRestoreState(priv
);
292 /** Turn \a pDev on (i.e., take input from \a pDev). */
294 dmxCommonKbdOn(DevicePtr pDev
)
298 dmxCommonSaveState(priv
);
299 priv
->eventMask
|= DMX_KEYBOARD_EVENT_MASK
;
300 XSelectInput(priv
->display
, priv
->window
, priv
->eventMask
);
302 XSetInputFocus(priv
->display
, priv
->window
, RevertToPointerRoot
,
307 /** Turn \a pDev off. */
309 dmxCommonKbdOff(DevicePtr pDev
)
312 priv
->eventMask
&= ~DMX_KEYBOARD_EVENT_MASK
;
313 XSelectInput(priv
->display
, priv
->window
, priv
->eventMask
);
314 dmxCommonRestoreState(priv
);
317 /** Turn \a pDev on (i.e., take input from \a pDev). */
319 dmxCommonOthOn(DevicePtr pDev
)
323 XEventClass event_list
[DMX_MAX_XINPUT_EVENT_TYPES
];
324 int event_type
[DMX_MAX_XINPUT_EVENT_TYPES
];
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); \
335 dmxLog(dmxWarning, "More than %d event types for %s\n", \
336 DMX_MAX_XINPUT_EVENT_TYPES, dmxInput->name); \
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
);
346 ADD(DeviceKeyRelease
);
347 ADD(DeviceButtonPress
);
348 ADD(DeviceButtonRelease
);
349 ADD(DeviceMotionNotify
);
354 ADD(DeviceStateNotify
);
355 ADD(DeviceMappingNotify
);
356 ADD(ChangeDeviceNotify
);
357 XSelectExtensionEvent(priv
->display
, priv
->window
, event_list
, count
);
362 /** Turn \a pDev off. */
364 dmxCommonOthOff(DevicePtr pDev
)
369 XCloseDevice(priv
->display
, priv
->xi
);
373 /** Fill the \a info structure with information needed to initialize \a
376 dmxCommonOthGetInfo(DevicePtr pDev
, DMXLocalInitInfoPtr info
)
380 XExtensionVersion
*ext
;
381 XDeviceInfo
*devices
;
382 Display
*display
= priv
->display
;
385 XextErrorHandler handler
;
387 if (!display
&& !(display
= XOpenDisplay(dmxInput
->name
)))
390 /* Print out information about the XInput Extension. */
391 handler
= XSetExtensionErrorHandler(dmxInputExtensionErrorHandler
);
392 ext
= XGetExtensionVersion(display
, INAME
);
393 XSetExtensionErrorHandler(handler
);
395 if (ext
&& ext
!= (XExtensionVersion
*) NoSuchExtension
) {
397 devices
= XListInputDevices(display
, &num
);
398 for (i
= 0; i
< num
; i
++) {
399 if (devices
[i
].id
== (XID
) dmxLocal
->deviceId
) {
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) {
410 ki
= (XKeyInfoPtr
) any
;
413 info
->keySyms
.minKeyCode
= ki
->min_keycode
;
414 info
->keySyms
.maxKeyCode
= ki
->max_keycode
;
415 info
->kbdFeedbackClass
= 1;
418 bi
= (XButtonInfoPtr
) any
;
419 info
->buttonClass
= 1;
420 info
->numButtons
= bi
->num_buttons
;
421 info
->ptrFeedbackClass
= 1;
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
;
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
;
441 /* Only keyboard and pointer feedback
442 * are handled at this time. */
445 info
->proximityClass
= 1;
448 info
->focusClass
= 1;
456 XFreeDeviceList(devices
);
458 if (display
!= priv
->display
)
459 XCloseDisplay(display
);
462 /** Obtain the mouse button mapping. */
464 dmxCommonMouGetMap(DevicePtr pDev
, unsigned char *map
, int *nButtons
)
469 *nButtons
= XGetPointerMapping(priv
->display
, map
, DMX_MAX_BUTTONS
);
470 for (i
= 0; i
<= *nButtons
; i
++)
475 dmxCommonXSelect(DMXScreenInfo
* dmxScreen
, void *closure
)
477 myPrivate
*priv
= closure
;
479 XSelectInput(dmxScreen
->beDisplay
, dmxScreen
->scrnWin
, priv
->eventMask
);
484 dmxCommonAddEnabledDevice(DMXScreenInfo
* dmxScreen
, void *closure
)
486 AddEnabledDevice(XConnectionNumber(dmxScreen
->beDisplay
));
491 dmxCommonRemoveEnabledDevice(DMXScreenInfo
* dmxScreen
, void *closure
)
493 RemoveEnabledDevice(XConnectionNumber(dmxScreen
->beDisplay
));
497 /** Turn \a pDev on (i.e., take input from \a pDev). */
499 dmxCommonMouOn(DevicePtr pDev
)
504 priv
->eventMask
|= DMX_POINTER_EVENT_MASK
;
506 XSelectInput(priv
->display
, priv
->window
, priv
->eventMask
);
507 AddEnabledDevice(XConnectionNumber(priv
->display
));
510 dmxPropertyIterate(priv
->be
, dmxCommonXSelect
, priv
);
511 dmxPropertyIterate(priv
->be
, dmxCommonAddEnabledDevice
, dmxInput
);
517 /** Turn \a pDev off. */
519 dmxCommonMouOff(DevicePtr pDev
)
524 priv
->eventMask
&= ~DMX_POINTER_EVENT_MASK
;
526 RemoveEnabledDevice(XConnectionNumber(priv
->display
));
527 XSelectInput(priv
->display
, priv
->window
, priv
->eventMask
);
530 dmxPropertyIterate(priv
->be
, dmxCommonRemoveEnabledDevice
, dmxInput
);
531 dmxPropertyIterate(priv
->be
, dmxCommonXSelect
, priv
);
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,
541 dmxFindPointerScreen(int x
, int y
)
545 for (i
= 0; i
< dmxNumScreens
; i
++) {
546 ScreenPtr pScreen
= screenInfo
.screens
[i
];
548 if (x
>= pScreen
->x
&& x
< pScreen
->x
+ pScreen
->width
&&
549 y
>= pScreen
->y
&& y
< pScreen
->y
+ pScreen
->height
)
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. */
562 dmxCommonCopyPrivate(DeviceIntPtr pDevice
)
564 GETDMXLOCALFROMPDEVICE
;
565 DMXInputInfo
*dmxInput
= &dmxInputs
[dmxLocal
->inputIdx
];
568 for (i
= 0; i
< dmxInput
->numDevs
; i
++)
569 if (dmxInput
->devs
[i
] == dmxLocal
&& i
)
570 return dmxInput
->devs
[i
- 1]->private;
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
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).
586 dmxCommonSaveState(pointer
private)
591 XModifierKeymap
*modmap
;
593 if (dmxInput
->console
)
594 priv
= dmxInput
->devs
[0]->private;
595 if (!priv
->display
|| priv
->stateSaved
)
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
);
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
613 XkbSetIndicatorMap(priv
->display
, ~0, priv
->xkb
);
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
];
628 dmxCommonKbdSetCtrl(priv
->display
, &priv
->savedKctrl
,
629 &priv
->dmxLocal
->kctrl
);
631 priv
->savedModMap
= XGetModifierMapping(priv
->display
);
633 modmap
= XNewModifiermap(0);
634 XSetModifierMapping(priv
->display
, modmap
);
635 if (dmxInput
->scrnIdx
!= -1)
636 dmxSync(&dmxScreens
[dmxInput
->scrnIdx
], TRUE
);
637 XFreeModifiermap(modmap
);
639 priv
->stateSaved
= 1;
642 /** This routine restores all the information saved by #dmxCommonSaveState. */
644 dmxCommonRestoreState(pointer
private)
650 if (dmxInput
->console
)
651 priv
= dmxInput
->devs
[0]->private;
652 if (!priv
->stateSaved
)
654 priv
->stateSaved
= 0;
656 DMXDBG0("dmxCommonRestoreState\n");
658 *priv
->xkb
->indicators
= priv
->savedIndicators
;
659 XkbSetIndicatorMap(priv
->display
, ~0, priv
->xkb
);
660 XkbFreeKeyboard(priv
->xkb
, 0, True
);
664 for (start
= GetTimeInMillis(); GetTimeInMillis() - start
< 5000;) {
667 retcode
= XSetModifierMapping(priv
->display
, priv
->savedModMap
);
668 if (retcode
== MappingSuccess
)
670 if (retcode
== MappingBusy
)
671 dmxLogInput(dmxInput
, "Keyboard busy, waiting\n");
673 dmxLogInput(dmxInput
, "Keyboard error, waiting\n");
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. */
685 if (retcode
!= MappingSuccess
)
686 dmxLog(dmxWarning
, "Unable to restore keyboard modifier state!\n");
688 XFreeModifiermap(priv
->savedModMap
);
689 priv
->savedModMap
= NULL
;
691 dmxCommonKbdSetCtrl(priv
->display
, NULL
, &priv
->savedKctrl
);
692 priv
->kctrlset
= 0; /* Invalidate copy */