xref: /OK3568_Linux_fs/external/xserver/hw/dmx/input/dmxevents.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright 2002-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  *   Rickard E. (Rik) Faith <faith@redhat.com>
31  *
32  */
33 
34 /** \file
35  * Provide support and helper functions for enqueing events received by
36  * the low-level input drivers. */
37 
38 #ifdef HAVE_DMX_CONFIG_H
39 #include <dmx-config.h>
40 #endif
41 
42 #define DMX_EVENTS_DEBUG 0
43 
44 #include "dmxinputinit.h"
45 #include "dmxevents.h"
46 #include "dmxcb.h"
47 #include "dmxcommon.h"
48 #include "dmxcursor.h"
49 #include "dmxmotion.h"
50 #include "dmxmap.h"
51 
52 #include <X11/keysym.h>
53 #include "opaque.h"
54 #include "inputstr.h"
55 #include "inpututils.h"
56 #include "mipointer.h"
57 #include "mi.h"
58 #include "exglobals.h"
59 
60 #include "xkbsrv.h"
61 #include "XIstubs.h"
62 
63 static int dmxGlobalX, dmxGlobalY;      /* Global cursor position */
64 static int dmxGlobalInvalid;    /* Flag indicating dmxCoreMotion
65                                  * should move the mouse anyway. */
66 
67 #if DMX_EVENTS_DEBUG
68 #define DMXDBG0(f)               dmxLog(dmxDebug,f)
69 #define DMXDBG1(f,a)             dmxLog(dmxDebug,f,a)
70 #define DMXDBG2(f,a,b)           dmxLog(dmxDebug,f,a,b)
71 #define DMXDBG3(f,a,b,c)         dmxLog(dmxDebug,f,a,b,c)
72 #define DMXDBG4(f,a,b,c,d)       dmxLog(dmxDebug,f,a,b,c,d)
73 #define DMXDBG5(f,a,b,c,d,e)     dmxLog(dmxDebug,f,a,b,c,d,e)
74 #define DMXDBG6(f,a,b,c,d,e,g)   dmxLog(dmxDebug,f,a,b,c,d,e,g)
75 #define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h)
76 #else
77 #define DMXDBG0(f)
78 #define DMXDBG1(f,a)
79 #define DMXDBG2(f,a,b)
80 #define DMXDBG3(f,a,b,c)
81 #define DMXDBG4(f,a,b,c,d)
82 #define DMXDBG5(f,a,b,c,d,e)
83 #define DMXDBG6(f,a,b,c,d,e,g)
84 #define DMXDBG7(f,a,b,c,d,e,g,h)
85 #endif
86 
87 static int
dmxApplyFunctions(DMXInputInfo * dmxInput,DMXFunctionType f)88 dmxApplyFunctions(DMXInputInfo * dmxInput, DMXFunctionType f)
89 {
90     int i;
91     int rc = 0;
92 
93     for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding)
94         if (dmxInput->devs[i]->functions)
95             rc += dmxInput->devs[i]->functions(dmxInput->devs[i]->private, f);
96     return rc;
97 }
98 
99 static int
dmxCheckFunctionKeys(DMXLocalInputInfoPtr dmxLocal,int type,KeySym keySym)100 dmxCheckFunctionKeys(DMXLocalInputInfoPtr dmxLocal, int type, KeySym keySym)
101 {
102     DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
103 
104 #if 1                           /* hack to detect ctrl-alt-q, etc */
105     static int ctrl = 0, alt = 0;
106 
107     /* keep track of ctrl/alt key status */
108     if (type == KeyPress && keySym == 0xffe3) {
109         ctrl = 1;
110     }
111     else if (type == KeyRelease && keySym == 0xffe3) {
112         ctrl = 0;
113     }
114     else if (type == KeyPress && keySym == 0xffe9) {
115         alt = 1;
116     }
117     else if (type == KeyRelease && keySym == 0xffe9) {
118         alt = 0;
119     }
120     if (!ctrl || !alt)
121         return 0;
122 #else
123     unsigned short state = 0;
124 
125     if (dmxLocal->sendsCore)
126         state = dmxLocalCoreKeyboard->pDevice->key->state;
127     else if (dmxLocal->pDevice->key)
128         state = dmxLocal->pDevice->key->state;
129 
130     DMXDBG3("dmxCheckFunctionKeys: keySym=0x%04x %s state=0x%04x\n",
131             keySym, type == KeyPress ? "press" : "release", state);
132 
133     if ((state & (ControlMask | Mod1Mask)) != (ControlMask | Mod1Mask))
134         return 0;
135 #endif
136 
137     switch (keySym) {
138     case XK_g:
139         if (type == KeyPress)
140             dmxApplyFunctions(dmxInput, DMX_FUNCTION_GRAB);
141         return 1;
142     case XK_f:
143         if (type == KeyPress)
144             dmxApplyFunctions(dmxInput, DMX_FUNCTION_FINE);
145         return 1;
146     case XK_q:
147         if (type == KeyPress && dmxLocal->sendsCore)
148             if (dmxApplyFunctions(dmxInput, DMX_FUNCTION_TERMINATE)) {
149                 dmxLog(dmxInfo, "User request for termination\n");
150                 dispatchException |= DE_TERMINATE;
151             }
152         return 1;
153     }
154 
155     return 0;
156 }
157 
158 DMXScreenInfo *
dmxFindFirstScreen(int x,int y)159 dmxFindFirstScreen(int x, int y)
160 {
161     int i;
162 
163     for (i = 0; i < dmxNumScreens; i++) {
164         DMXScreenInfo *dmxScreen = &dmxScreens[i];
165 
166         if (dmxOnScreen(x, y, dmxScreen))
167             return dmxScreen;
168     }
169     return NULL;
170 }
171 
172 /**
173  * Enqueue a motion event.
174  */
175 static void
enqueueMotion(DevicePtr pDev,int x,int y)176 enqueueMotion(DevicePtr pDev, int x, int y)
177 {
178     GETDMXLOCALFROMPDEV;
179     DeviceIntPtr p = dmxLocal->pDevice;
180     int valuators[3];
181     int detail = 0;             /* XXX should this be mask of pressed buttons? */
182     ValuatorMask mask;
183 
184     valuators[0] = x;
185     valuators[1] = y;
186 
187     valuator_mask_set_range(&mask, 0, 2, valuators);
188     QueuePointerEvents(p, MotionNotify, detail,
189                        POINTER_ABSOLUTE | POINTER_SCREEN, &mask);
190     return;
191 }
192 
193 void
dmxCoreMotion(DevicePtr pDev,int x,int y,int delta,DMXBlockType block)194 dmxCoreMotion(DevicePtr pDev, int x, int y, int delta, DMXBlockType block)
195 {
196     DMXScreenInfo *dmxScreen;
197     DMXInputInfo *dmxInput;
198     ScreenPtr pScreen;
199     int localX;
200     int localY;
201     int i;
202 
203     if (!dmxGlobalInvalid && dmxGlobalX == x && dmxGlobalY == y)
204         return;
205 
206     DMXDBG5("dmxCoreMotion(%d,%d,%d) dmxGlobalX=%d dmxGlobalY=%d\n",
207             x, y, delta, dmxGlobalX, dmxGlobalY);
208 
209     dmxGlobalInvalid = 0;
210     dmxGlobalX = x;
211     dmxGlobalY = y;
212 
213     if (dmxGlobalX < 0)
214         dmxGlobalX = 0;
215     if (dmxGlobalY < 0)
216         dmxGlobalY = 0;
217     if (dmxGlobalX >= dmxGlobalWidth)
218         dmxGlobalX = dmxGlobalWidth + delta - 1;
219     if (dmxGlobalY >= dmxGlobalHeight)
220         dmxGlobalY = dmxGlobalHeight + delta - 1;
221 
222     if ((dmxScreen = dmxFindFirstScreen(dmxGlobalX, dmxGlobalY))) {
223         localX = dmxGlobalX - dmxScreen->rootXOrigin;
224         localY = dmxGlobalY - dmxScreen->rootYOrigin;
225         if ((pScreen = miPointerGetScreen(inputInfo.pointer))
226             && pScreen->myNum == dmxScreen->index) {
227             /* Screen is old screen */
228             if (block)
229                 input_lock();
230             if (pDev)
231                 enqueueMotion(pDev, localX, localY);
232             if (block)
233                 input_unlock();
234         }
235         else {
236             /* Screen is new */
237             DMXDBG4("   New screen: old=%d new=%d localX=%d localY=%d\n",
238                     pScreen->myNum, dmxScreen->index, localX, localY);
239             if (block)
240                 input_lock();
241             mieqProcessInputEvents();
242             miPointerSetScreen(inputInfo.pointer, dmxScreen->index,
243                                localX, localY);
244             if (pDev)
245                 enqueueMotion(pDev, localX, localY);
246             if (block)
247                 input_unlock();
248         }
249 #if 00
250         miPointerGetPosition(inputInfo.pointer, &localX, &localY);
251 
252         if ((pScreen = miPointerGetScreen(inputInfo.pointer))) {
253             dmxGlobalX = localX + dmxScreens[pScreen->myNum].rootXOrigin;
254             dmxGlobalY = localY + dmxScreens[pScreen->myNum].rootYOrigin;
255             ErrorF("Global is now %d, %d  %d, %d\n", dmxGlobalX, dmxGlobalY,
256                    localX, localY);
257             DMXDBG6("   Moved to dmxGlobalX=%d dmxGlobalY=%d"
258                     " on screen index=%d/%d localX=%d localY=%d\n",
259                     dmxGlobalX, dmxGlobalY,
260                     dmxScreen ? dmxScreen->index : -1, pScreen->myNum,
261                     localX, localY);
262         }
263 #endif
264     }
265     /* Send updates down to all core input
266      * drivers */
267     for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) {
268         int j;
269 
270         for (j = 0; j < dmxInput->numDevs; j += dmxInput->devs[j]->binding)
271             if (!dmxInput->detached
272                 && dmxInput->devs[j]->sendsCore
273                 && dmxInput->devs[j]->update_position)
274                 dmxInput->devs[j]->update_position(dmxInput->devs[j]->private,
275                                                    dmxGlobalX, dmxGlobalY);
276     }
277     if (!dmxScreen)
278         ProcessInputEvents();
279 }
280 
281 #define DMX_MAX_AXES 32         /* Max axes reported by this routine */
282 static void
dmxExtMotion(DMXLocalInputInfoPtr dmxLocal,int * v,int firstAxis,int axesCount,DMXMotionType type,DMXBlockType block)283 dmxExtMotion(DMXLocalInputInfoPtr dmxLocal,
284              int *v, int firstAxis, int axesCount,
285              DMXMotionType type, DMXBlockType block)
286 {
287     DeviceIntPtr pDevice = dmxLocal->pDevice;
288     xEvent xE[2 * DMX_MAX_AXES / 6];
289     deviceKeyButtonPointer *xev = (deviceKeyButtonPointer *) xE;
290     deviceValuator *xv = (deviceValuator *) xev + 1;
291     int thisX = 0;
292     int thisY = 0;
293     int count;
294     ValuatorMask mask;
295 
296     memset(xE, 0, sizeof(xE));
297 
298     if (axesCount > DMX_MAX_AXES)
299         axesCount = DMX_MAX_AXES;
300 
301     if ((valuator_get_mode(pDevice, 0) == Relative) && axesCount == 2) {
302         /* The dmx console is a relative mode
303          * device that sometimes reports
304          * absolute motion.  It only has two
305          * axes. */
306         if (type == DMX_RELATIVE) {
307             thisX = -v[0];
308             thisY = -v[1];
309             dmxLocal->lastX += thisX;
310             dmxLocal->lastY += thisY;
311             if (dmxLocal->update_position)
312                 dmxLocal->update_position(dmxLocal->private,
313                                           dmxLocal->lastX, dmxLocal->lastY);
314         }
315         else {                  /* Convert to relative */
316             if (dmxLocal->lastX || dmxLocal->lastY) {
317                 thisX = v[0] - dmxLocal->lastX;
318                 thisY = v[1] - dmxLocal->lastY;
319             }
320             dmxLocal->lastX = v[0];
321             dmxLocal->lastY = v[1];
322         }
323         v[0] = thisX;
324         v[1] = thisY;
325     }
326 
327     if (axesCount <= 6) {
328         /* Optimize for the common case when
329          * only 1 or 2 axes change. */
330         xev->time = GetTimeInMillis();
331         xev->type = DeviceMotionNotify;
332         xev->detail = 0;
333         xev->deviceid = pDevice->id | MORE_EVENTS;
334 
335         xv->type = DeviceValuator;
336         xv->deviceid = pDevice->id;
337         xv->num_valuators = axesCount;
338         xv->first_valuator = firstAxis;
339         switch (xv->num_valuators) {
340         case 6:
341             xv->valuator5 = v[5];
342         case 5:
343             xv->valuator4 = v[4];
344         case 4:
345             xv->valuator3 = v[3];
346         case 3:
347             xv->valuator2 = v[2];
348         case 2:
349             xv->valuator1 = v[1];
350         case 1:
351             xv->valuator0 = v[0];
352         }
353         count = 2;
354     }
355     else {
356         int i;
357 
358         for (i = 0, count = 0; i < axesCount; i += 6) {
359             xev->time = GetTimeInMillis();
360             xev->type = DeviceMotionNotify;
361             xev->detail = 0;
362             xev->deviceid = pDevice->id | MORE_EVENTS;
363             xev += 2;
364 
365             xv->type = DeviceValuator;
366             xv->deviceid = pDevice->id;
367             xv->num_valuators = (i + 6 >= axesCount ? axesCount - i : 6);
368             xv->first_valuator = firstAxis + i;
369             switch (xv->num_valuators) {
370             case 6:
371                 xv->valuator5 = v[i + 5];
372             case 5:
373                 xv->valuator4 = v[i + 4];
374             case 4:
375                 xv->valuator3 = v[i + 3];
376             case 3:
377                 xv->valuator2 = v[i + 2];
378             case 2:
379                 xv->valuator1 = v[i + 1];
380             case 1:
381                 xv->valuator0 = v[i + 0];
382             }
383             xv += 2;
384             count += 2;
385         }
386     }
387 
388     if (block)
389         input_lock();
390     valuator_mask_set_range(&mask, firstAxis, axesCount, v);
391     QueuePointerEvents(pDevice, MotionNotify, 0, POINTER_ABSOLUTE, &mask);
392 
393     if (block)
394         input_unlock();
395 }
396 
397 static int
dmxTranslateAndEnqueueExtEvent(DMXLocalInputInfoPtr dmxLocal,XEvent * e,DMXBlockType block)398 dmxTranslateAndEnqueueExtEvent(DMXLocalInputInfoPtr dmxLocal,
399                                XEvent * e, DMXBlockType block)
400 {
401     int type;
402     int event = -1;
403     XDeviceKeyEvent *ke = (XDeviceKeyEvent *) e;
404     XDeviceMotionEvent *me = (XDeviceMotionEvent *) e;
405     DeviceIntPtr pDevice = dmxLocal->pDevice;
406     int valuators[MAX_VALUATORS];
407     ValuatorMask mask;
408 
409     if (!e)
410         return -1;              /* No extended event passed, cannot handle */
411 
412     if ((XID) dmxLocal->deviceId != ke->deviceid) {
413         /* Search for the correct dmxLocal,
414          * since backend and console events are
415          * picked up for the first device on
416          * that X server. */
417         int i;
418         DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
419 
420         for (i = 0; i < dmxInput->numDevs; i++) {
421             dmxLocal = dmxInput->devs[i];
422             if ((XID) dmxLocal->deviceId == ke->deviceid)
423                 break;
424         }
425     }
426 
427     if ((XID) dmxLocal->deviceId != ke->deviceid
428         || (type = dmxMapLookup(dmxLocal, e->type)) < 0)
429         return -1;              /* No mapping, so this event is unhandled */
430 
431     switch (type) {
432     case XI_DeviceValuator:
433         event = DeviceValuator;
434         break;
435     case XI_DeviceKeyPress:
436         event = KeyPress;
437         break;
438     case XI_DeviceKeyRelease:
439         event = KeyRelease;
440         break;
441     case XI_DeviceButtonPress:
442         event = ButtonPress;
443         break;
444     case XI_DeviceButtonRelease:
445         event = ButtonRelease;
446         break;
447     case XI_DeviceMotionNotify:
448         event = MotionNotify;
449         break;
450     case XI_DeviceFocusIn:
451         event = DeviceFocusIn;
452         break;
453     case XI_DeviceFocusOut:
454         event = DeviceFocusOut;
455         break;
456     case XI_ProximityIn:
457         event = ProximityIn;
458         break;
459     case XI_ProximityOut:
460         event = ProximityOut;
461         break;
462     case XI_DeviceStateNotify:
463         event = DeviceStateNotify;
464         break;
465     case XI_DeviceMappingNotify:
466         event = DeviceMappingNotify;
467         break;
468     case XI_ChangeDeviceNotify:
469         event = ChangeDeviceNotify;
470         break;
471     case XI_DeviceKeystateNotify:
472         event = DeviceStateNotify;
473         break;
474     case XI_DeviceButtonstateNotify:
475         event = DeviceStateNotify;
476         break;
477     }
478 
479 #define EXTRACT_VALUATORS(ke, valuators) \
480         valuators[0] = ke->axis_data[0]; \
481         valuators[1] = ke->axis_data[1]; \
482         valuators[2] = ke->axis_data[2]; \
483         valuators[3] = ke->axis_data[3]; \
484         valuators[4] = ke->axis_data[4]; \
485         valuators[5] = ke->axis_data[5]; \
486 
487     switch (type) {
488     case XI_DeviceKeyPress:
489     case XI_DeviceKeyRelease:
490         if (block)
491             input_lock();
492         QueueKeyboardEvents(pDevice, event, ke->keycode);
493         if (block)
494             input_unlock();
495         break;
496     case XI_DeviceButtonPress:
497     case XI_DeviceButtonRelease:
498         EXTRACT_VALUATORS(ke, valuators);
499         valuator_mask_set_range(&mask, ke->first_axis, ke->axes_count,
500                                 valuators);
501         if (block)
502             input_lock();
503         QueuePointerEvents(pDevice, event, ke->keycode,
504                            POINTER_ABSOLUTE, &mask);
505         if (block)
506             input_unlock();
507         break;
508     case XI_ProximityIn:
509     case XI_ProximityOut:
510         EXTRACT_VALUATORS(ke, valuators);
511         valuator_mask_set_range(&mask, ke->first_axis, ke->axes_count,
512                                 valuators);
513         if (block)
514             input_lock();
515         QueueProximityEvents(pDevice, event, &mask);
516         if (block)
517             input_unlock();
518         break;
519 
520         break;
521 
522     case XI_DeviceMotionNotify:
523         dmxExtMotion(dmxLocal, me->axis_data, me->first_axis, me->axes_count,
524                      DMX_ABSOLUTE, block);
525         break;
526     case XI_DeviceFocusIn:
527     case XI_DeviceFocusOut:
528     case XI_DeviceStateNotify:
529     case XI_DeviceMappingNotify:
530     case XI_ChangeDeviceNotify:
531     case XI_DeviceKeystateNotify:
532     case XI_DeviceButtonstateNotify:
533         /* These are ignored, since DMX will
534          * generate its own events of these
535          * types, as necessary.
536 
537          * Perhaps ChangeDeviceNotify should
538          * generate an error, because it is
539          * unexpected? */
540         break;
541     case XI_DeviceValuator:
542     default:
543         dmxLog(dmxWarning,
544                "XInput extension event (remote=%d -> zero-based=%d)"
545                " not supported yet\n", e->type, type);
546         return -1;
547     }
548     return 0;
549 }
550 
551 static int
dmxGetButtonMapping(DMXLocalInputInfoPtr dmxLocal,int button)552 dmxGetButtonMapping(DMXLocalInputInfoPtr dmxLocal, int button)
553 {
554     ButtonClassPtr b = dmxLocal->pDevice->button;
555 
556     if (button > b->numButtons) {       /* This shouldn't happen. */
557         dmxLog(dmxWarning, "Button %d pressed, but only %d buttons?!?\n",
558                button, b->numButtons);
559         return button;
560     }
561     return b->map[button];
562 }
563 
564 /** Return DMX's notion of the pointer position in the global coordinate
565  * space. */
566 void
dmxGetGlobalPosition(int * x,int * y)567 dmxGetGlobalPosition(int *x, int *y)
568 {
569     *x = dmxGlobalX;
570     *y = dmxGlobalY;
571 }
572 
573 /** Invalidate the global position for #dmxCoreMotion. */
574 void
dmxInvalidateGlobalPosition(void)575 dmxInvalidateGlobalPosition(void)
576 {
577     dmxGlobalInvalid = 1;
578 }
579 
580 /** Enqueue a motion event for \a pDev.  The \a v vector has length \a
581  * axesCount, and contains values for each of the axes, starting at \a
582  * firstAxes.
583  *
584  * The \a type of the motion may be \a DMX_RELATIVE, \a DMX_ABSOLUTE, or
585  * \a DMX_ABSOLUTE_CONFINED (in the latter case, the pointer will not be
586  * allowed to move outside the global boundaires).
587  *
588  * If \a block is set to \a DMX_BLOCK, then the input thread will be
589  * blocked around calls to \a enqueueMotion(). */
590 void
dmxMotion(DevicePtr pDev,int * v,int firstAxes,int axesCount,DMXMotionType type,DMXBlockType block)591 dmxMotion(DevicePtr pDev, int *v, int firstAxes, int axesCount,
592           DMXMotionType type, DMXBlockType block)
593 {
594     GETDMXLOCALFROMPDEV;
595 
596     if (!dmxLocal->sendsCore) {
597         dmxExtMotion(dmxLocal, v, firstAxes, axesCount, type, block);
598         return;
599     }
600     if (axesCount == 2) {
601         switch (type) {
602         case DMX_RELATIVE:
603             dmxCoreMotion(pDev, dmxGlobalX - v[0], dmxGlobalY - v[1], 0, block);
604             break;
605         case DMX_ABSOLUTE:
606             dmxCoreMotion(pDev, v[0], v[1], 0, block);
607             break;
608         case DMX_ABSOLUTE_CONFINED:
609             dmxCoreMotion(pDev, v[0], v[1], -1, block);
610             break;
611         }
612     }
613 }
614 
615 static KeySym
dmxKeyCodeToKeySym(DMXLocalInputInfoPtr dmxLocal,KeyCode keyCode)616 dmxKeyCodeToKeySym(DMXLocalInputInfoPtr dmxLocal, KeyCode keyCode)
617 {
618     KeySym keysym = NoSymbol;
619     int effectiveGroup;
620     XkbSrvInfoPtr xkbi;
621 
622     if (!dmxLocal || !dmxLocal->pDevice || !dmxLocal->pDevice->key)
623         goto out;
624 
625     xkbi = dmxLocal->pDevice->key->xkbInfo;
626     effectiveGroup = XkbGetEffectiveGroup(xkbi, &xkbi->state, keyCode);
627 
628     if (effectiveGroup == -1)
629         goto out;
630 
631     keysym = XkbKeySym(xkbi->desc, keyCode, effectiveGroup);
632     DMXDBG2("dmxKeyCodeToKeySym: Translated keyCode=%d to keySym=0x%04x\n",
633             keyCode, keysym);
634 
635  out:
636     return keysym;
637 }
638 
639 static KeyCode
dmxKeySymToKeyCode(DMXLocalInputInfoPtr dmxLocal,KeySym keySym,int tryFirst)640 dmxKeySymToKeyCode(DMXLocalInputInfoPtr dmxLocal, KeySym keySym, int tryFirst)
641 {
642     /* FIXME: this is quite ineffective, converting to a core map first and
643      * then extracting the info from there. It'd be better to run the actual
644      * xkb map */
645     XkbSrvInfoPtr xkbi = dmxLocal->pDevice->key->xkbInfo;
646     KeySymsPtr pKeySyms = XkbGetCoreMap(dmxLocal->pDevice);
647     int i;
648 
649     /* Optimize for similar maps */
650     if (XkbKeycodeInRange(xkbi->desc, tryFirst)
651         && pKeySyms->map[(tryFirst - xkbi->desc->min_key_code)
652                          * pKeySyms->mapWidth] == keySym)
653         return tryFirst;
654 
655     for (i = pKeySyms->minKeyCode; i <= pKeySyms->maxKeyCode; i++) {
656         if (pKeySyms->map[(i - pKeySyms->minKeyCode)
657                           * pKeySyms->mapWidth] == keySym) {
658             DMXDBG3("dmxKeySymToKeyCode: Translated keySym=0x%04x to"
659                     " keyCode=%d (reverses to core keySym=0x%04x)\n",
660                     keySym, i, dmxKeyCodeToKeySym(dmxLocalCoreKeyboard, i));
661             return i;
662         }
663     }
664     return 0;
665 }
666 
667 static int
dmxFixup(DevicePtr pDev,int detail,KeySym keySym)668 dmxFixup(DevicePtr pDev, int detail, KeySym keySym)
669 {
670     GETDMXLOCALFROMPDEV;
671     int keyCode;
672 
673     if (!dmxLocal->pDevice->key) {
674         dmxLog(dmxWarning, "dmxFixup: not a keyboard device (%s)\n",
675                dmxLocal->pDevice->name);
676         return NoSymbol;
677     }
678     if (!keySym)
679         keySym = dmxKeyCodeToKeySym(dmxLocal, detail);
680     if (keySym == NoSymbol)
681         return detail;
682     keyCode = dmxKeySymToKeyCode(dmxLocalCoreKeyboard, keySym, detail);
683 
684     return keyCode ? keyCode : detail;
685 }
686 
687 /** Enqueue an event from the \a pDev device with the
688  * specified \a type and \a detail.  If the event is a KeyPress or
689  * KeyRelease event, then the \a keySym is also specified.
690  *
691  * FIXME: make the code do what the comment says, or remove this comment.
692  * If \a block is set to \a DMX_BLOCK, then the input thread will be
693  * blocked around calls to dmxeqEnqueue(). */
694 
695 void
dmxEnqueue(DevicePtr pDev,int type,int detail,KeySym keySym,XEvent * e,DMXBlockType block)696 dmxEnqueue(DevicePtr pDev, int type, int detail, KeySym keySym,
697            XEvent * e, DMXBlockType block)
698 {
699     GETDMXINPUTFROMPDEV;
700     DeviceIntPtr p = dmxLocal->pDevice;
701     int valuators[3];
702     ValuatorMask mask;
703 
704     DMXDBG2("dmxEnqueue: Enqueuing type=%d detail=0x%0x\n", type, detail);
705 
706     switch (type) {
707     case KeyPress:
708     case KeyRelease:
709         if (!keySym)
710             keySym = dmxKeyCodeToKeySym(dmxLocal, detail);
711         if (dmxCheckFunctionKeys(dmxLocal, type, keySym))
712             return;
713         if (dmxLocal->sendsCore && dmxLocal != dmxLocalCoreKeyboard)
714             detail = dmxFixup(pDev, detail, keySym);
715 
716         /*ErrorF("KEY %d  sym %d\n", detail, (int) keySym); */
717         QueueKeyboardEvents(p, type, detail);
718         return;
719 
720     case ButtonPress:
721     case ButtonRelease:
722         detail = dmxGetButtonMapping(dmxLocal, detail);
723         valuator_mask_zero(&mask);
724         QueuePointerEvents(p, type, detail, 0, &mask);
725         return;
726 
727     case MotionNotify:
728         valuators[0] = e->xmotion.x;
729         valuators[1] = e->xmotion.y;
730         valuators[2] = e->xmotion.state;        /* FIXME: WTF?? */
731         valuator_mask_set_range(&mask, 0, 3, valuators);
732         QueuePointerEvents(p, type, detail,
733                            POINTER_ABSOLUTE | POINTER_SCREEN, &mask);
734         return;
735 
736     case EnterNotify:
737     case LeaveNotify:
738     case KeymapNotify:
739     case MappingNotify:        /* This is sent because we change the
740                                  * modifier map on the backend/console
741                                  * input device so that we have complete
742                                  * control of the input device LEDs. */
743         return;
744     default:
745         if (type == ProximityIn || type == ProximityOut) {
746             if (dmxLocal->sendsCore)
747                 return;         /* Not a core event */
748             break;
749         }
750         if (type >= LASTEvent) {
751             if (dmxTranslateAndEnqueueExtEvent(dmxLocal, e, block))
752                 dmxLogInput(dmxInput, "Unhandled extension event: %d\n", type);
753         }
754         else {
755             dmxLogInput(dmxInput, "Unhandled event: %d (%s)\n",
756                         type, dmxEventName(type));
757         }
758         return;
759     }
760 
761 }
762 
763 /** A pointer to this routine is passed to low-level input drivers so
764  * that all special keychecking is unified to this file.  This function
765  * returns 0 if no special keys have been pressed.  If the user has
766  * requested termination of the DMX server, -1 is returned.  If the user
767  * has requested a switch to a VT, then the (1-based) number of that VT
768  * is returned. */
769 int
dmxCheckSpecialKeys(DevicePtr pDev,KeySym keySym)770 dmxCheckSpecialKeys(DevicePtr pDev, KeySym keySym)
771 {
772     GETDMXINPUTFROMPDEV;
773     int vt = 0;
774     unsigned short state = 0;
775 
776     if (dmxLocal->sendsCore)
777         state =
778             XkbStateFieldFromRec(&dmxLocalCoreKeyboard->pDevice->key->xkbInfo->
779                                  state);
780     else if (dmxLocal->pDevice->key)
781         state = XkbStateFieldFromRec(&dmxLocal->pDevice->key->xkbInfo->state);
782 
783     if (!dmxLocal->sendsCore)
784         return 0;               /* Only for core devices */
785 
786     DMXDBG2("dmxCheckSpecialKeys: keySym=0x%04x state=0x%04x\n", keySym, state);
787 
788     if ((state & (ControlMask | Mod1Mask)) != (ControlMask | Mod1Mask))
789         return 0;
790 
791     switch (keySym) {
792     case XK_F1:
793     case XK_F2:
794     case XK_F3:
795     case XK_F4:
796     case XK_F5:
797     case XK_F6:
798     case XK_F7:
799     case XK_F8:
800     case XK_F9:
801     case XK_F10:
802         vt = keySym - XK_F1 + 1;
803         break;
804 
805     case XK_F11:
806     case XK_F12:
807         vt = keySym - XK_F11 + 11;
808         break;
809 
810     case XK_q:                 /* To avoid confusion  */
811     case XK_BackSpace:
812     case XK_Delete:
813     case XK_KP_Delete:
814         dmxLog(dmxInfo, "User request for termination\n");
815         dispatchException |= DE_TERMINATE;
816         return -1;              /* Terminate */
817     }
818 
819     if (vt) {
820         dmxLog(dmxInfo, "Request to switch to VT %d\n", vt);
821         dmxInput->vt_switch_pending = vt;
822         return vt;
823     }
824 
825     return 0;                   /* Do nothing */
826 }
827