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
{
74 static void dmxCommonKbdSetAR(Display
*display
,
75 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
);
105 static void dmxCommonKbdSetLeds(Display
*display
, unsigned long new)
110 for (i
= 0; i
< 32; i
++) {
112 kc
.led_mode
= (new & (1 << i
)) ? LedModeOn
: LedModeOff
;
113 XChangeKeyboardControl(display
, KBLed
| KBLedMode
, &kc
);
117 static void dmxCommonKbdSetCtrl(Display
*display
,
118 KeybdCtrl
*old
, KeybdCtrl
*new)
121 unsigned long mask
= KBKeyClickPercent
| KBAutoRepeatMode
;
124 || old
->click
!= new->click
125 || old
->autoRepeat
!= new->autoRepeat
) {
127 kc
.key_click_percent
= new->click
;
128 kc
.auto_repeat_mode
= new->autoRepeat
;
130 XChangeKeyboardControl(display
, mask
, &kc
);
133 dmxCommonKbdSetLeds(display
, new->leds
);
134 dmxCommonKbdSetAR(display
, old
? old
->autoRepeats
: NULL
,
138 static void dmxCommonMouSetCtrl(Display
*display
, PtrCtrl
*old
, PtrCtrl
*new)
140 Bool do_accel
, do_threshold
;
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
);
155 /** Update the keyboard control. */
156 void dmxCommonKbdCtrl(DevicePtr pDev
, KeybdCtrl
*ctrl
)
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
,
169 /** Update the mouse control. */
170 void dmxCommonMouCtrl(DevicePtr pDev
, PtrCtrl
*ctrl
)
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. */
182 dmxCommonMouSetCtrl(priv
->display
,
183 priv
->mctrlset
? &priv
->mctrl
: NULL
,
190 /** Sound they keyboard bell. */
191 void dmxCommonKbdBell(DevicePtr pDev
, int percent
,
192 int volume
, int pitch
, int duration
)
197 unsigned long mask
= KBBellPercent
| KBBellPitch
| KBBellDuration
;
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
);
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
);
213 /** Get the keyboard mapping. */
214 void dmxCommonKbdGetMap(DevicePtr pDev
, KeySymsPtr pKeySyms
, CARD8
*pModMap
)
220 KeySym
*keyboard_mapping
;
221 XModifierKeymap
*modifier_mapping
;
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
,
235 pKeySyms
->minKeyCode
= min_keycode
;
236 pKeySyms
->maxKeyCode
= max_keycode
;
237 pKeySyms
->mapWidth
= map_width
;
238 pKeySyms
->map
= keyboard_mapping
;
241 /* Compute pModMap */
242 modifier_mapping
= XGetModifierMapping(priv
->display
);
243 for (i
= 0; i
< MAP_LENGTH
; i
++)
245 for (j
= 0; j
< 8; j
++) {
246 int max_keypermod
= modifier_mapping
->max_keypermod
;
248 for (i
= 0; i
< max_keypermod
; i
++) {
249 CARD8 keycode
= modifier_mapping
->modifiermap
[j
*max_keypermod
+ i
];
251 pModMap
[keycode
] |= 1 << j
;
254 XFreeModifiermap(modifier_mapping
);
257 /** Fill in the XKEYBOARD parts of the \a info structure for the
258 * specified \a pDev. */
259 void dmxCommonKbdGetInfo(DevicePtr pDev
, DMXLocalInitInfoPtr info
)
266 dmxCommonSaveState(priv
);
268 info
->names
.keymap
= NULL
;
270 priv->xkb->names->x ? XGetAtomName(priv->display,priv->xkb->names->x) : NULL
271 info
->names
.keycodes
= NAME(keycodes
);
272 info
->names
.types
= NAME(types
);
273 info
->names
.compat
= NAME(compat
);
274 info
->names
.symbols
= NAME(symbols
);
275 info
->names
.geometry
= NAME(geometry
);
278 dmxLogInput(dmxInput
,
279 "XKEYBOARD: keycodes = %s\n", info
->names
.keycodes
);
280 dmxLogInput(dmxInput
,
281 "XKEYBOARD: symbols = %s\n", info
->names
.symbols
);
282 dmxLogInput(dmxInput
,
283 "XKEYBOARD: geometry = %s\n", info
->names
.geometry
);
284 if ((pt
= strchr(info
->names
.keycodes
, '+'))) *pt
= '\0';
286 dmxCommonRestoreState(priv
);
290 /** Turn \a pDev on (i.e., take input from \a pDev). */
291 int dmxCommonKbdOn(DevicePtr pDev
)
294 if (priv
->be
) dmxCommonSaveState(priv
);
295 priv
->eventMask
|= DMX_KEYBOARD_EVENT_MASK
;
296 XSelectInput(priv
->display
, priv
->window
, priv
->eventMask
);
298 XSetInputFocus(priv
->display
, priv
->window
, RevertToPointerRoot
,
303 /** Turn \a pDev off. */
304 void dmxCommonKbdOff(DevicePtr pDev
)
307 priv
->eventMask
&= ~DMX_KEYBOARD_EVENT_MASK
;
308 XSelectInput(priv
->display
, priv
->window
, priv
->eventMask
);
309 dmxCommonRestoreState(priv
);
312 /** Turn \a pDev on (i.e., take input from \a pDev). */
313 int dmxCommonOthOn(DevicePtr pDev
)
317 XEventClass event_list
[DMX_MAX_XINPUT_EVENT_TYPES
];
318 int event_type
[DMX_MAX_XINPUT_EVENT_TYPES
];
322 if (count < DMX_MAX_XINPUT_EVENT_TYPES) { \
323 type(priv->xi, event_type[count], event_list[count]); \
324 if (event_type[count]) { \
325 dmxMapInsert(dmxLocal, event_type[count], XI_##type); \
329 dmxLog(dmxWarning, "More than %d event types for %s\n", \
330 DMX_MAX_XINPUT_EVENT_TYPES, dmxInput->name); \
333 if (!(priv
->xi
= XOpenDevice(priv
->display
, dmxLocal
->deviceId
))) {
334 dmxLog(dmxWarning
, "Cannot open %s device (id=%d) on %s\n",
335 dmxLocal
->deviceName
? dmxLocal
->deviceName
: "(unknown)",
336 dmxLocal
->deviceId
, dmxInput
->name
);
340 ADD(DeviceKeyRelease
);
341 ADD(DeviceButtonPress
);
342 ADD(DeviceButtonRelease
);
343 ADD(DeviceMotionNotify
);
348 ADD(DeviceStateNotify
);
349 ADD(DeviceMappingNotify
);
350 ADD(ChangeDeviceNotify
);
351 XSelectExtensionEvent(priv
->display
, priv
->window
, event_list
, count
);
356 /** Turn \a pDev off. */
357 void dmxCommonOthOff(DevicePtr pDev
)
361 if (priv
->xi
) XCloseDevice(priv
->display
, priv
->xi
);
365 /** Fill the \a info structure with information needed to initialize \a
367 void dmxCommonOthGetInfo(DevicePtr pDev
, DMXLocalInitInfoPtr info
)
371 XExtensionVersion
*ext
;
372 XDeviceInfo
*devices
;
373 Display
*display
= priv
->display
;
376 int (*handler
)(Display
*, char *, char *);
378 if (!display
&& !(display
= XOpenDisplay(dmxInput
->name
)))
381 /* Print out information about the XInput Extension. */
382 handler
= XSetExtensionErrorHandler(dmxInputExtensionErrorHandler
);
383 ext
= XGetExtensionVersion(display
, INAME
);
384 XSetExtensionErrorHandler(handler
);
386 if (ext
&& ext
!= (XExtensionVersion
*)NoSuchExtension
) {
388 devices
= XListInputDevices(display
, &num
);
389 for (i
= 0; i
< num
; i
++) {
390 if (devices
[i
].id
== (XID
)dmxLocal
->deviceId
) {
395 for (j
= 0, any
= devices
[i
].inputclassinfo
;
396 j
< devices
[i
].num_classes
;
397 any
= (XAnyClassPtr
)((char *)any
+ any
->length
), j
++) {
398 switch (any
->class) {
400 ki
= (XKeyInfoPtr
)any
;
403 info
->keySyms
.minKeyCode
= ki
->min_keycode
;
404 info
->keySyms
.maxKeyCode
= ki
->max_keycode
;
405 info
->kbdFeedbackClass
= 1;
408 bi
= (XButtonInfoPtr
)any
;
409 info
->buttonClass
= 1;
410 info
->numButtons
= bi
->num_buttons
;
411 info
->ptrFeedbackClass
= 1;
414 /* This assume all axes are either
415 * Absolute or Relative. */
416 vi
= (XValuatorInfoPtr
)any
;
417 info
->valuatorClass
= 1;
418 if (vi
->mode
== Absolute
)
419 info
->numAbsAxes
= vi
->num_axes
;
421 info
->numRelAxes
= vi
->num_axes
;
422 for (k
= 0; k
< vi
->num_axes
; k
++) {
423 info
->res
[k
] = vi
->axes
[k
].resolution
;
424 info
->minres
[k
] = vi
->axes
[k
].resolution
;
425 info
->maxres
[k
] = vi
->axes
[k
].resolution
;
426 info
->minval
[k
] = vi
->axes
[k
].min_value
;
427 info
->maxval
[k
] = vi
->axes
[k
].max_value
;
431 /* Only keyboard and pointer feedback
432 * are handled at this time. */
435 info
->proximityClass
= 1;
438 info
->focusClass
= 1;
446 XFreeDeviceList(devices
);
448 if (display
!= priv
->display
) XCloseDisplay(display
);
451 /** Obtain the mouse button mapping. */
452 void dmxCommonMouGetMap(DevicePtr pDev
, unsigned char *map
, int *nButtons
)
457 *nButtons
= XGetPointerMapping(priv
->display
, map
, DMX_MAX_BUTTONS
);
458 for (i
= 0; i
<= *nButtons
; i
++) map
[i
] = i
;
461 static void *dmxCommonXSelect(DMXScreenInfo
*dmxScreen
, void *closure
)
463 myPrivate
*priv
= closure
;
464 XSelectInput(dmxScreen
->beDisplay
, dmxScreen
->scrnWin
, priv
->eventMask
);
468 static void *dmxCommonAddEnabledDevice(DMXScreenInfo
*dmxScreen
, void *closure
)
470 AddEnabledDevice(XConnectionNumber(dmxScreen
->beDisplay
));
474 static void *dmxCommonRemoveEnabledDevice(DMXScreenInfo
*dmxScreen
,
477 RemoveEnabledDevice(XConnectionNumber(dmxScreen
->beDisplay
));
481 /** Turn \a pDev on (i.e., take input from \a pDev). */
482 int dmxCommonMouOn(DevicePtr pDev
)
487 priv
->eventMask
|= DMX_POINTER_EVENT_MASK
;
489 XWarpPointer(priv
->display
, priv
->window
, priv
->window
,
493 dmxSync(&dmxScreens
[dmxInput
->scrnIdx
], TRUE
);
496 XSelectInput(priv
->display
, priv
->window
, priv
->eventMask
);
497 AddEnabledDevice(XConnectionNumber(priv
->display
));
499 dmxPropertyIterate(priv
->be
, dmxCommonXSelect
, priv
);
500 dmxPropertyIterate(priv
->be
, dmxCommonAddEnabledDevice
, dmxInput
);
506 /** Turn \a pDev off. */
507 void dmxCommonMouOff(DevicePtr pDev
)
512 priv
->eventMask
&= ~DMX_POINTER_EVENT_MASK
;
514 RemoveEnabledDevice(XConnectionNumber(priv
->display
));
515 XSelectInput(priv
->display
, priv
->window
, priv
->eventMask
);
517 dmxPropertyIterate(priv
->be
, dmxCommonRemoveEnabledDevice
, dmxInput
);
518 dmxPropertyIterate(priv
->be
, dmxCommonXSelect
, priv
);
522 /** Given the global coordinates \a x and \a y, determine the screen
523 * with the lowest number on which those coordinates lie. If they are
524 * not on any screen, return -1. The number returned is an index into
525 * #dmxScreenInfo and is between -1 and #dmxNumScreens - 1,
527 int dmxFindPointerScreen(int x
, int y
)
531 for (i
= 0; i
< dmxNumScreens
; i
++) {
532 if (x
>= dixScreenOrigins
[i
].x
533 && x
< dixScreenOrigins
[i
].x
+ screenInfo
.screens
[i
]->width
534 && y
>= dixScreenOrigins
[i
].y
535 && y
< dixScreenOrigins
[i
].y
+ screenInfo
.screens
[i
]->height
)
541 /** Returns a pointer to the private area for the device that comes just
542 * prior to \a pDevice in the current \a dmxInput device list. This is
543 * used as the private area for the current device in some situations
544 * (e.g., when a keyboard and mouse form a pair that should share the
545 * same private area). If the requested private area cannot be located,
546 * then NULL is returned. */
547 pointer
dmxCommonCopyPrivate(DeviceIntPtr pDevice
)
549 GETDMXLOCALFROMPDEVICE
;
550 DMXInputInfo
*dmxInput
= &dmxInputs
[dmxLocal
->inputIdx
];
553 for (i
= 0; i
< dmxInput
->numDevs
; i
++)
554 if (dmxInput
->devs
[i
] == dmxLocal
&& i
)
555 return dmxInput
->devs
[i
-1]->private;
559 /** This routine saves and resets some important state for the backend
560 * and console device drivers:
561 * - the modifier map is saved and set to 0 (so DMX controls the LEDs)
562 * - the key click, bell, led, and repeat masks are saved and set to the
563 * values that DMX claims to be using
565 * This routine and #dmxCommonRestoreState are used when the pointer
566 * enters and leaves the console window, or when the backend window is
567 * active or not active (for a full-screen window, this only happens at
568 * server startup and server shutdown).
570 void dmxCommonSaveState(pointer
private)
575 XModifierKeymap
*modmap
;
577 if (dmxInput
->console
) priv
= dmxInput
->devs
[0]->private;
578 if (!priv
->display
|| priv
->stateSaved
) return;
579 DMXDBG0("dmxCommonSaveState\n");
581 if (dmxUseXKB
&& (priv
->xkb
= XkbAllocKeyboard())) {
582 if (XkbGetIndicatorMap(priv
->display
, XkbAllIndicatorsMask
, priv
->xkb
)
583 || XkbGetNames(priv
->display
, XkbAllNamesMask
, priv
->xkb
)) {
584 dmxLogInput(dmxInput
, "Could not get XKB information\n");
585 XkbFreeKeyboard(priv
->xkb
, 0, True
);
588 if (priv
->xkb
->indicators
) {
589 priv
->savedIndicators
= *priv
->xkb
->indicators
;
590 for (i
= 0; i
< XkbNumIndicators
; i
++)
591 if (priv
->xkb
->indicators
->phys_indicators
& (1 << i
)) {
592 priv
->xkb
->indicators
->maps
[i
].flags
595 XkbSetIndicatorMap(priv
->display
, ~0, priv
->xkb
);
601 XGetKeyboardControl(priv
->display
, &ks
);
602 priv
->savedKctrl
.click
= ks
.key_click_percent
;
603 priv
->savedKctrl
.bell
= ks
.bell_percent
;
604 priv
->savedKctrl
.bell_pitch
= ks
.bell_pitch
;
605 priv
->savedKctrl
.bell_duration
= ks
.bell_duration
;
606 priv
->savedKctrl
.leds
= ks
.led_mask
;
607 priv
->savedKctrl
.autoRepeat
= ks
.global_auto_repeat
;
608 for (i
= 0; i
< 32; i
++)
609 priv
->savedKctrl
.autoRepeats
[i
] = ks
.auto_repeats
[i
];
611 dmxCommonKbdSetCtrl(priv
->display
, &priv
->savedKctrl
,
612 &priv
->dmxLocal
->kctrl
);
614 priv
->savedModMap
= XGetModifierMapping(priv
->display
);
616 modmap
= XNewModifiermap(0);
617 XSetModifierMapping(priv
->display
, modmap
);
618 if (dmxInput
->scrnIdx
!= -1)
619 dmxSync(&dmxScreens
[dmxInput
->scrnIdx
], TRUE
);
620 XFreeModifiermap(modmap
);
622 priv
->stateSaved
= 1;
625 /** This routine restores all the information saved by #dmxCommonSaveState. */
626 void dmxCommonRestoreState(pointer
private)
632 if (dmxInput
->console
)
633 priv
= dmxInput
->devs
[0]->private;
634 if (!priv
->stateSaved
)
636 priv
->stateSaved
= 0;
638 DMXDBG0("dmxCommonRestoreState\n");
641 *priv
->xkb
->indicators
= priv
->savedIndicators
;
642 XkbSetIndicatorMap(priv
->display
, ~0, priv
->xkb
);
643 XkbFreeKeyboard(priv
->xkb
, 0, True
);
648 for (start
= GetTimeInMillis(); GetTimeInMillis() - start
< 5000;) {
651 retcode
= XSetModifierMapping(priv
->display
, priv
->savedModMap
);
652 if (retcode
== MappingSuccess
)
654 if (retcode
== MappingBusy
)
655 dmxLogInput(dmxInput
, "Keyboard busy, waiting\n");
657 dmxLogInput(dmxInput
, "Keyboard error, waiting\n");
659 /* Don't generate X11 protocol for a bit */
660 for (tmp
= GetTimeInMillis(); GetTimeInMillis() - tmp
< 250;) {
661 usleep(250); /* This ends up sleeping only until
662 * the next key press generates an
663 * interruption. We make the delay
664 * relatively short in case the user
665 * pressed they keys quickly. */
669 if (retcode
!= MappingSuccess
)
670 dmxLog(dmxWarning
, "Unable to restore keyboard modifier state!\n");
672 XFreeModifiermap(priv
->savedModMap
);
673 priv
->savedModMap
= NULL
;
675 dmxCommonKbdSetCtrl(priv
->display
, NULL
, &priv
->savedKctrl
);
676 priv
->kctrlset
= 0; /* Invalidate copy */