2 * Copyright 2002-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 * Rickard E. (Rik) Faith <faith@redhat.com>
35 * Provide support and helper functions for enqueing events received by
36 * the low-level input drivers. */
38 #ifdef HAVE_DMX_CONFIG_H
39 #include <dmx-config.h>
42 #define DMX_EVENTS_DEBUG 0
44 #include "dmxinputinit.h"
45 #include "dmxevents.h"
47 #include "dmxcommon.h"
48 #include "dmxcursor.h"
49 #include "dmxmotion.h"
53 #include <X11/keysym.h>
56 #include "inpututils.h"
57 #include "mipointer.h"
59 #include "exglobals.h"
64 static int dmxGlobalX
, dmxGlobalY
; /* Global cursor position */
65 static int dmxGlobalInvalid
; /* Flag indicating dmxCoreMotion
66 * should move the mouse anyway. */
69 #define DMXDBG0(f) dmxLog(dmxDebug,f)
70 #define DMXDBG1(f,a) dmxLog(dmxDebug,f,a)
71 #define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b)
72 #define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c)
73 #define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d)
74 #define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e)
75 #define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g)
76 #define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h)
80 #define DMXDBG2(f,a,b)
81 #define DMXDBG3(f,a,b,c)
82 #define DMXDBG4(f,a,b,c,d)
83 #define DMXDBG5(f,a,b,c,d,e)
84 #define DMXDBG6(f,a,b,c,d,e,g)
85 #define DMXDBG7(f,a,b,c,d,e,g,h)
89 dmxApplyFunctions(DMXInputInfo
* dmxInput
, DMXFunctionType f
)
94 for (i
= 0; i
< dmxInput
->numDevs
; i
+= dmxInput
->devs
[i
]->binding
)
95 if (dmxInput
->devs
[i
]->functions
)
96 rc
+= dmxInput
->devs
[i
]->functions(dmxInput
->devs
[i
]->private, f
);
101 dmxCheckFunctionKeys(DMXLocalInputInfoPtr dmxLocal
, int type
, KeySym keySym
)
103 DMXInputInfo
*dmxInput
= &dmxInputs
[dmxLocal
->inputIdx
];
105 #if 1 /* hack to detect ctrl-alt-q, etc */
106 static int ctrl
= 0, alt
= 0;
108 /* keep track of ctrl/alt key status */
109 if (type
== KeyPress
&& keySym
== 0xffe3) {
112 else if (type
== KeyRelease
&& keySym
== 0xffe3) {
115 else if (type
== KeyPress
&& keySym
== 0xffe9) {
118 else if (type
== KeyRelease
&& keySym
== 0xffe9) {
124 unsigned short state
= 0;
126 if (dmxLocal
->sendsCore
)
127 state
= dmxLocalCoreKeyboard
->pDevice
->key
->state
;
128 else if (dmxLocal
->pDevice
->key
)
129 state
= dmxLocal
->pDevice
->key
->state
;
131 DMXDBG3("dmxCheckFunctionKeys: keySym=0x%04x %s state=0x%04x\n",
132 keySym
, type
== KeyPress
? "press" : "release", state
);
134 if ((state
& (ControlMask
| Mod1Mask
)) != (ControlMask
| Mod1Mask
))
140 if (type
== KeyPress
)
141 dmxApplyFunctions(dmxInput
, DMX_FUNCTION_GRAB
);
144 if (type
== KeyPress
)
145 dmxApplyFunctions(dmxInput
, DMX_FUNCTION_FINE
);
148 if (type
== KeyPress
&& dmxLocal
->sendsCore
)
149 if (dmxApplyFunctions(dmxInput
, DMX_FUNCTION_TERMINATE
)) {
150 dmxLog(dmxInfo
, "User request for termination\n");
151 dispatchException
|= DE_TERMINATE
;
160 dmxFindFirstScreen(int x
, int y
)
164 for (i
= 0; i
< dmxNumScreens
; i
++) {
165 DMXScreenInfo
*dmxScreen
= &dmxScreens
[i
];
167 if (dmxOnScreen(x
, y
, dmxScreen
))
174 * Enqueue a motion event.
177 enqueueMotion(DevicePtr pDev
, int x
, int y
)
180 DeviceIntPtr p
= dmxLocal
->pDevice
;
182 int detail
= 0; /* XXX should this be mask of pressed buttons? */
188 valuator_mask_set_range(&mask
, 0, 2, valuators
);
189 QueuePointerEvents(p
, MotionNotify
, detail
,
190 POINTER_ABSOLUTE
| POINTER_SCREEN
, &mask
);
195 dmxCoreMotion(DevicePtr pDev
, int x
, int y
, int delta
, DMXBlockType block
)
197 DMXScreenInfo
*dmxScreen
;
198 DMXInputInfo
*dmxInput
;
204 if (!dmxGlobalInvalid
&& dmxGlobalX
== x
&& dmxGlobalY
== y
)
207 DMXDBG5("dmxCoreMotion(%d,%d,%d) dmxGlobalX=%d dmxGlobalY=%d\n",
208 x
, y
, delta
, dmxGlobalX
, dmxGlobalY
);
210 dmxGlobalInvalid
= 0;
218 if (dmxGlobalX
>= dmxGlobalWidth
)
219 dmxGlobalX
= dmxGlobalWidth
+ delta
- 1;
220 if (dmxGlobalY
>= dmxGlobalHeight
)
221 dmxGlobalY
= dmxGlobalHeight
+ delta
- 1;
223 if ((dmxScreen
= dmxFindFirstScreen(dmxGlobalX
, dmxGlobalY
))) {
224 localX
= dmxGlobalX
- dmxScreen
->rootXOrigin
;
225 localY
= dmxGlobalY
- dmxScreen
->rootYOrigin
;
226 if ((pScreen
= miPointerGetScreen(inputInfo
.pointer
))
227 && pScreen
->myNum
== dmxScreen
->index
) {
228 /* Screen is old screen */
232 enqueueMotion(pDev
, localX
, localY
);
238 DMXDBG4(" New screen: old=%d new=%d localX=%d localY=%d\n",
239 pScreen
->myNum
, dmxScreen
->index
, localX
, localY
);
242 mieqProcessInputEvents();
243 miPointerSetScreen(inputInfo
.pointer
, dmxScreen
->index
,
246 enqueueMotion(pDev
, localX
, localY
);
251 miPointerGetPosition(inputInfo
.pointer
, &localX
, &localY
);
253 if ((pScreen
= miPointerGetScreen(inputInfo
.pointer
))) {
254 dmxGlobalX
= localX
+ dmxScreens
[pScreen
->myNum
].rootXOrigin
;
255 dmxGlobalY
= localY
+ dmxScreens
[pScreen
->myNum
].rootYOrigin
;
256 ErrorF("Global is now %d, %d %d, %d\n", dmxGlobalX
, dmxGlobalY
,
258 DMXDBG6(" Moved to dmxGlobalX=%d dmxGlobalY=%d"
259 " on screen index=%d/%d localX=%d localY=%d\n",
260 dmxGlobalX
, dmxGlobalY
,
261 dmxScreen
? dmxScreen
->index
: -1, pScreen
->myNum
,
266 /* Send updates down to all core input
268 for (i
= 0, dmxInput
= &dmxInputs
[0]; i
< dmxNumInputs
; i
++, dmxInput
++) {
271 for (j
= 0; j
< dmxInput
->numDevs
; j
+= dmxInput
->devs
[j
]->binding
)
272 if (!dmxInput
->detached
273 && dmxInput
->devs
[j
]->sendsCore
274 && dmxInput
->devs
[j
]->update_position
)
275 dmxInput
->devs
[j
]->update_position(dmxInput
->devs
[j
]->private,
276 dmxGlobalX
, dmxGlobalY
);
279 ProcessInputEvents();
282 #define DMX_MAX_AXES 32 /* Max axes reported by this routine */
284 dmxExtMotion(DMXLocalInputInfoPtr dmxLocal
,
285 int *v
, int firstAxis
, int axesCount
,
286 DMXMotionType type
, DMXBlockType block
)
288 DeviceIntPtr pDevice
= dmxLocal
->pDevice
;
289 xEvent xE
[2 * DMX_MAX_AXES
/ 6];
290 deviceKeyButtonPointer
*xev
= (deviceKeyButtonPointer
*) xE
;
291 deviceValuator
*xv
= (deviceValuator
*) xev
+ 1;
297 memset(xE
, 0, sizeof(xE
));
299 if (axesCount
> DMX_MAX_AXES
)
300 axesCount
= DMX_MAX_AXES
;
302 if ((valuator_get_mode(pDevice
, 0) == Relative
) && axesCount
== 2) {
303 /* The dmx console is a relative mode
304 * device that sometimes reports
305 * absolute motion. It only has two
307 if (type
== DMX_RELATIVE
) {
310 dmxLocal
->lastX
+= thisX
;
311 dmxLocal
->lastY
+= thisY
;
312 if (dmxLocal
->update_position
)
313 dmxLocal
->update_position(dmxLocal
->private,
314 dmxLocal
->lastX
, dmxLocal
->lastY
);
316 else { /* Convert to relative */
317 if (dmxLocal
->lastX
|| dmxLocal
->lastY
) {
318 thisX
= v
[0] - dmxLocal
->lastX
;
319 thisY
= v
[1] - dmxLocal
->lastY
;
321 dmxLocal
->lastX
= v
[0];
322 dmxLocal
->lastY
= v
[1];
328 if (axesCount
<= 6) {
329 /* Optimize for the common case when
330 * only 1 or 2 axes change. */
331 xev
->time
= GetTimeInMillis();
332 xev
->type
= DeviceMotionNotify
;
334 xev
->deviceid
= pDevice
->id
| MORE_EVENTS
;
336 xv
->type
= DeviceValuator
;
337 xv
->deviceid
= pDevice
->id
;
338 xv
->num_valuators
= axesCount
;
339 xv
->first_valuator
= firstAxis
;
340 switch (xv
->num_valuators
) {
342 xv
->valuator5
= v
[5];
344 xv
->valuator4
= v
[4];
346 xv
->valuator3
= v
[3];
348 xv
->valuator2
= v
[2];
350 xv
->valuator1
= v
[1];
352 xv
->valuator0
= v
[0];
359 for (i
= 0, count
= 0; i
< axesCount
; i
+= 6) {
360 xev
->time
= GetTimeInMillis();
361 xev
->type
= DeviceMotionNotify
;
363 xev
->deviceid
= pDevice
->id
| MORE_EVENTS
;
366 xv
->type
= DeviceValuator
;
367 xv
->deviceid
= pDevice
->id
;
368 xv
->num_valuators
= (i
+ 6 >= axesCount
? axesCount
- i
: 6);
369 xv
->first_valuator
= firstAxis
+ i
;
370 switch (xv
->num_valuators
) {
372 xv
->valuator5
= v
[i
+ 5];
374 xv
->valuator4
= v
[i
+ 4];
376 xv
->valuator3
= v
[i
+ 3];
378 xv
->valuator2
= v
[i
+ 2];
380 xv
->valuator1
= v
[i
+ 1];
382 xv
->valuator0
= v
[i
+ 0];
391 valuator_mask_set_range(&mask
, firstAxis
, axesCount
, v
);
392 QueuePointerEvents(pDevice
, MotionNotify
, 0, POINTER_ABSOLUTE
, &mask
);
399 dmxTranslateAndEnqueueExtEvent(DMXLocalInputInfoPtr dmxLocal
,
400 XEvent
* e
, DMXBlockType block
)
404 XDeviceKeyEvent
*ke
= (XDeviceKeyEvent
*) e
;
405 XDeviceMotionEvent
*me
= (XDeviceMotionEvent
*) e
;
406 DeviceIntPtr pDevice
= dmxLocal
->pDevice
;
407 int valuators
[MAX_VALUATORS
];
411 return -1; /* No extended event passed, cannot handle */
413 if ((XID
) dmxLocal
->deviceId
!= ke
->deviceid
) {
414 /* Search for the correct dmxLocal,
415 * since backend and console events are
416 * picked up for the first device on
419 DMXInputInfo
*dmxInput
= &dmxInputs
[dmxLocal
->inputIdx
];
421 for (i
= 0; i
< dmxInput
->numDevs
; i
++) {
422 dmxLocal
= dmxInput
->devs
[i
];
423 if ((XID
) dmxLocal
->deviceId
== ke
->deviceid
)
428 if ((XID
) dmxLocal
->deviceId
!= ke
->deviceid
429 || (type
= dmxMapLookup(dmxLocal
, e
->type
)) < 0)
430 return -1; /* No mapping, so this event is unhandled */
433 case XI_DeviceValuator
:
434 event
= DeviceValuator
;
436 case XI_DeviceKeyPress
:
439 case XI_DeviceKeyRelease
:
442 case XI_DeviceButtonPress
:
445 case XI_DeviceButtonRelease
:
446 event
= ButtonRelease
;
448 case XI_DeviceMotionNotify
:
449 event
= MotionNotify
;
451 case XI_DeviceFocusIn
:
452 event
= DeviceFocusIn
;
454 case XI_DeviceFocusOut
:
455 event
= DeviceFocusOut
;
460 case XI_ProximityOut
:
461 event
= ProximityOut
;
463 case XI_DeviceStateNotify
:
464 event
= DeviceStateNotify
;
466 case XI_DeviceMappingNotify
:
467 event
= DeviceMappingNotify
;
469 case XI_ChangeDeviceNotify
:
470 event
= ChangeDeviceNotify
;
472 case XI_DeviceKeystateNotify
:
473 event
= DeviceStateNotify
;
475 case XI_DeviceButtonstateNotify
:
476 event
= DeviceStateNotify
;
480 #define EXTRACT_VALUATORS(ke, valuators) \
481 valuators[0] = ke->axis_data[0]; \
482 valuators[1] = ke->axis_data[1]; \
483 valuators[2] = ke->axis_data[2]; \
484 valuators[3] = ke->axis_data[3]; \
485 valuators[4] = ke->axis_data[4]; \
486 valuators[5] = ke->axis_data[5]; \
489 case XI_DeviceKeyPress
:
490 case XI_DeviceKeyRelease
:
491 EXTRACT_VALUATORS(ke
, valuators
);
492 valuator_mask_set_range(&mask
, ke
->first_axis
, ke
->axes_count
,
496 QueueKeyboardEvents(pDevice
, event
, ke
->keycode
, &mask
);
500 case XI_DeviceButtonPress
:
501 case XI_DeviceButtonRelease
:
502 EXTRACT_VALUATORS(ke
, valuators
);
503 valuator_mask_set_range(&mask
, ke
->first_axis
, ke
->axes_count
,
507 QueuePointerEvents(pDevice
, event
, ke
->keycode
,
508 POINTER_ABSOLUTE
, &mask
);
513 case XI_ProximityOut
:
514 EXTRACT_VALUATORS(ke
, valuators
);
515 valuator_mask_set_range(&mask
, ke
->first_axis
, ke
->axes_count
,
519 QueueProximityEvents(pDevice
, event
, &mask
);
526 case XI_DeviceMotionNotify
:
527 dmxExtMotion(dmxLocal
, me
->axis_data
, me
->first_axis
, me
->axes_count
,
528 DMX_ABSOLUTE
, block
);
530 case XI_DeviceFocusIn
:
531 case XI_DeviceFocusOut
:
532 case XI_DeviceStateNotify
:
533 case XI_DeviceMappingNotify
:
534 case XI_ChangeDeviceNotify
:
535 case XI_DeviceKeystateNotify
:
536 case XI_DeviceButtonstateNotify
:
537 /* These are ignored, since DMX will
538 * generate its own events of these
539 * types, as necessary.
541 * Perhaps ChangeDeviceNotify should
542 * generate an error, because it is
545 case XI_DeviceValuator
:
548 "XInput extension event (remote=%d -> zero-based=%d)"
549 " not supported yet\n", e
->type
, type
);
556 dmxGetButtonMapping(DMXLocalInputInfoPtr dmxLocal
, int button
)
558 ButtonClassPtr b
= dmxLocal
->pDevice
->button
;
560 if (button
> b
->numButtons
) { /* This shouldn't happen. */
561 dmxLog(dmxWarning
, "Button %d pressed, but only %d buttons?!?\n",
562 button
, b
->numButtons
);
565 return b
->map
[button
];
568 /** Return DMX's notion of the pointer position in the global coordinate
571 dmxGetGlobalPosition(int *x
, int *y
)
577 /** Invalidate the global position for #dmxCoreMotion. */
579 dmxInvalidateGlobalPosition(void)
581 dmxGlobalInvalid
= 1;
584 /** Enqueue a motion event for \a pDev. The \a v vector has length \a
585 * axesCount, and contains values for each of the axes, starting at \a
588 * The \a type of the motion may be \a DMX_RELATIVE, \a DMX_ABSOLUTE, or
589 * \a DMX_ABSOLUTE_CONFINED (in the latter case, the pointer will not be
590 * allowed to move outside the global boundaires).
592 * If \a block is set to \a DMX_BLOCK, then the SIGIO handler will be
593 * blocked around calls to \a enqueueMotion(). */
595 dmxMotion(DevicePtr pDev
, int *v
, int firstAxes
, int axesCount
,
596 DMXMotionType type
, DMXBlockType block
)
600 if (!dmxLocal
->sendsCore
) {
601 dmxExtMotion(dmxLocal
, v
, firstAxes
, axesCount
, type
, block
);
604 if (axesCount
== 2) {
607 dmxCoreMotion(pDev
, dmxGlobalX
- v
[0], dmxGlobalY
- v
[1], 0, block
);
610 dmxCoreMotion(pDev
, v
[0], v
[1], 0, block
);
612 case DMX_ABSOLUTE_CONFINED
:
613 dmxCoreMotion(pDev
, v
[0], v
[1], -1, block
);
620 dmxKeyCodeToKeySym(DMXLocalInputInfoPtr dmxLocal
, KeyCode keyCode
)
622 KeySym keysym
= NoSymbol
;
626 if (!dmxLocal
|| !dmxLocal
->pDevice
|| !dmxLocal
->pDevice
->key
)
629 xkbi
= dmxLocal
->pDevice
->key
->xkbInfo
;
630 effectiveGroup
= XkbGetEffectiveGroup(xkbi
, &xkbi
->state
, keyCode
);
632 if (effectiveGroup
== -1)
635 keysym
= XkbKeySym(xkbi
->desc
, keyCode
, effectiveGroup
);
636 DMXDBG2("dmxKeyCodeToKeySym: Translated keyCode=%d to keySym=0x%04x\n",
644 dmxKeySymToKeyCode(DMXLocalInputInfoPtr dmxLocal
, KeySym keySym
, int tryFirst
)
646 /* FIXME: this is quite ineffective, converting to a core map first and
647 * then extracting the info from there. It'd be better to run the actual
649 XkbSrvInfoPtr xkbi
= dmxLocal
->pDevice
->key
->xkbInfo
;
650 KeySymsPtr pKeySyms
= XkbGetCoreMap(dmxLocal
->pDevice
);
653 /* Optimize for similar maps */
654 if (XkbKeycodeInRange(xkbi
->desc
, tryFirst
)
655 && pKeySyms
->map
[(tryFirst
- xkbi
->desc
->min_key_code
)
656 * pKeySyms
->mapWidth
] == keySym
)
659 for (i
= pKeySyms
->minKeyCode
; i
<= pKeySyms
->maxKeyCode
; i
++) {
660 if (pKeySyms
->map
[(i
- pKeySyms
->minKeyCode
)
661 * pKeySyms
->mapWidth
] == keySym
) {
662 DMXDBG3("dmxKeySymToKeyCode: Translated keySym=0x%04x to"
663 " keyCode=%d (reverses to core keySym=0x%04x)\n",
664 keySym
, i
, dmxKeyCodeToKeySym(dmxLocalCoreKeyboard
, i
));
672 dmxFixup(DevicePtr pDev
, int detail
, KeySym keySym
)
677 if (!dmxLocal
->pDevice
->key
) {
678 dmxLog(dmxWarning
, "dmxFixup: not a keyboard device (%s)\n",
679 dmxLocal
->pDevice
->name
);
683 keySym
= dmxKeyCodeToKeySym(dmxLocal
, detail
);
684 if (keySym
== NoSymbol
)
686 keyCode
= dmxKeySymToKeyCode(dmxLocalCoreKeyboard
, keySym
, detail
);
688 return keyCode
? keyCode
: detail
;
691 /** Enqueue an event from the \a pDev device with the
692 * specified \a type and \a detail. If the event is a KeyPress or
693 * KeyRelease event, then the \a keySym is also specified.
695 * FIXME: make the code do what the comment says, or remove this comment.
696 * If \a block is set to \a DMX_BLOCK, then the SIGIO handler will be
697 * blocked around calls to dmxeqEnqueue(). */
700 dmxEnqueue(DevicePtr pDev
, int type
, int detail
, KeySym keySym
,
701 XEvent
* e
, DMXBlockType block
)
705 DeviceIntPtr p
= dmxLocal
->pDevice
;
709 DMXDBG2("dmxEnqueue: Enqueuing type=%d detail=0x%0x\n", type
, detail
);
715 keySym
= dmxKeyCodeToKeySym(dmxLocal
, detail
);
716 if (dmxCheckFunctionKeys(dmxLocal
, type
, keySym
))
718 if (dmxLocal
->sendsCore
&& dmxLocal
!= dmxLocalCoreKeyboard
)
719 xE
.u
.u
.detail
= dmxFixup(pDev
, detail
, keySym
);
721 /*ErrorF("KEY %d sym %d\n", detail, (int) keySym); */
722 QueueKeyboardEvents(p
, type
, detail
, NULL
);
727 detail
= dmxGetButtonMapping(dmxLocal
, detail
);
728 valuator_mask_zero(&mask
);
729 QueuePointerEvents(p
, type
, detail
, 0, &mask
);
733 valuators
[0] = e
->xmotion
.x
;
734 valuators
[1] = e
->xmotion
.y
;
735 valuators
[2] = e
->xmotion
.state
; /* FIXME: WTF?? */
736 valuator_mask_set_range(&mask
, 0, 3, valuators
);
737 QueuePointerEvents(p
, type
, detail
,
738 POINTER_ABSOLUTE
| POINTER_SCREEN
, &mask
);
744 case MappingNotify
: /* This is sent because we change the
745 * modifier map on the backend/console
746 * input device so that we have complete
747 * control of the input device LEDs. */
750 if (type
== ProximityIn
|| type
== ProximityOut
) {
751 if (dmxLocal
->sendsCore
)
752 return; /* Not a core event */
755 if (type
>= LASTEvent
) {
756 if (dmxTranslateAndEnqueueExtEvent(dmxLocal
, e
, block
))
757 dmxLogInput(dmxInput
, "Unhandled extension event: %d\n", type
);
760 dmxLogInput(dmxInput
, "Unhandled event: %d (%s)\n",
761 type
, dmxEventName(type
));
768 /** A pointer to this routine is passed to low-level input drivers so
769 * that all special keychecking is unified to this file. This function
770 * returns 0 if no special keys have been pressed. If the user has
771 * requested termination of the DMX server, -1 is returned. If the user
772 * has requested a switch to a VT, then the (1-based) number of that VT
775 dmxCheckSpecialKeys(DevicePtr pDev
, KeySym keySym
)
779 unsigned short state
= 0;
781 if (dmxLocal
->sendsCore
)
783 XkbStateFieldFromRec(&dmxLocalCoreKeyboard
->pDevice
->key
->xkbInfo
->
785 else if (dmxLocal
->pDevice
->key
)
786 state
= XkbStateFieldFromRec(&dmxLocal
->pDevice
->key
->xkbInfo
->state
);
788 if (!dmxLocal
->sendsCore
)
789 return 0; /* Only for core devices */
791 DMXDBG2("dmxCheckSpecialKeys: keySym=0x%04x state=0x%04x\n", keySym
, state
);
793 if ((state
& (ControlMask
| Mod1Mask
)) != (ControlMask
| Mod1Mask
))
807 vt
= keySym
- XK_F1
+ 1;
812 vt
= keySym
- XK_F11
+ 11;
815 case XK_q
: /* To avoid confusion */
819 dmxLog(dmxInfo
, "User request for termination\n");
820 dispatchException
|= DE_TERMINATE
;
821 return -1; /* Terminate */
825 dmxLog(dmxInfo
, "Request to switch to VT %d\n", vt
);
826 dmxInput
->vt_switch_pending
= vt
;
830 return 0; /* Do nothing */