Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / dmx / input / dmxevents.c
CommitLineData
a09e091a
JB
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 "dmxsigio.h"
51#include "dmxmap.h"
52
53#include <X11/keysym.h>
54#include "opaque.h"
55#include "inputstr.h"
56#include "inpututils.h"
57#include "mipointer.h"
58#include "mi.h"
59#include "exglobals.h"
60
61#include "xkbsrv.h"
62#include "XIstubs.h"
63
64static int dmxGlobalX, dmxGlobalY; /* Global cursor position */
65static int dmxGlobalInvalid; /* Flag indicating dmxCoreMotion
66 * should move the mouse anyway. */
67
68#if DMX_EVENTS_DEBUG
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)
77#else
78#define DMXDBG0(f)
79#define DMXDBG1(f,a)
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)
86#endif
87
88static int
89dmxApplyFunctions(DMXInputInfo * dmxInput, DMXFunctionType f)
90{
91 int i;
92 int rc = 0;
93
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);
97 return rc;
98}
99
100static int
101dmxCheckFunctionKeys(DMXLocalInputInfoPtr dmxLocal, int type, KeySym keySym)
102{
103 DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
104
105#if 1 /* hack to detect ctrl-alt-q, etc */
106 static int ctrl = 0, alt = 0;
107
108 /* keep track of ctrl/alt key status */
109 if (type == KeyPress && keySym == 0xffe3) {
110 ctrl = 1;
111 }
112 else if (type == KeyRelease && keySym == 0xffe3) {
113 ctrl = 0;
114 }
115 else if (type == KeyPress && keySym == 0xffe9) {
116 alt = 1;
117 }
118 else if (type == KeyRelease && keySym == 0xffe9) {
119 alt = 0;
120 }
121 if (!ctrl || !alt)
122 return 0;
123#else
124 unsigned short state = 0;
125
126 if (dmxLocal->sendsCore)
127 state = dmxLocalCoreKeyboard->pDevice->key->state;
128 else if (dmxLocal->pDevice->key)
129 state = dmxLocal->pDevice->key->state;
130
131 DMXDBG3("dmxCheckFunctionKeys: keySym=0x%04x %s state=0x%04x\n",
132 keySym, type == KeyPress ? "press" : "release", state);
133
134 if ((state & (ControlMask | Mod1Mask)) != (ControlMask | Mod1Mask))
135 return 0;
136#endif
137
138 switch (keySym) {
139 case XK_g:
140 if (type == KeyPress)
141 dmxApplyFunctions(dmxInput, DMX_FUNCTION_GRAB);
142 return 1;
143 case XK_f:
144 if (type == KeyPress)
145 dmxApplyFunctions(dmxInput, DMX_FUNCTION_FINE);
146 return 1;
147 case XK_q:
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;
152 }
153 return 1;
154 }
155
156 return 0;
157}
158
159DMXScreenInfo *
160dmxFindFirstScreen(int x, int y)
161{
162 int i;
163
164 for (i = 0; i < dmxNumScreens; i++) {
165 DMXScreenInfo *dmxScreen = &dmxScreens[i];
166
167 if (dmxOnScreen(x, y, dmxScreen))
168 return dmxScreen;
169 }
170 return NULL;
171}
172
173/**
174 * Enqueue a motion event.
175 */
176static void
177enqueueMotion(DevicePtr pDev, int x, int y)
178{
179 GETDMXLOCALFROMPDEV;
180 DeviceIntPtr p = dmxLocal->pDevice;
181 int valuators[3];
182 int detail = 0; /* XXX should this be mask of pressed buttons? */
183 ValuatorMask mask;
184
185 valuators[0] = x;
186 valuators[1] = y;
187
188 valuator_mask_set_range(&mask, 0, 2, valuators);
189 QueuePointerEvents(p, MotionNotify, detail,
190 POINTER_ABSOLUTE | POINTER_SCREEN, &mask);
191 return;
192}
193
194void
195dmxCoreMotion(DevicePtr pDev, int x, int y, int delta, DMXBlockType block)
196{
197 DMXScreenInfo *dmxScreen;
198 DMXInputInfo *dmxInput;
199 ScreenPtr pScreen;
200 int localX;
201 int localY;
202 int i;
203
204 if (!dmxGlobalInvalid && dmxGlobalX == x && dmxGlobalY == y)
205 return;
206
207 DMXDBG5("dmxCoreMotion(%d,%d,%d) dmxGlobalX=%d dmxGlobalY=%d\n",
208 x, y, delta, dmxGlobalX, dmxGlobalY);
209
210 dmxGlobalInvalid = 0;
211 dmxGlobalX = x;
212 dmxGlobalY = y;
213
214 if (dmxGlobalX < 0)
215 dmxGlobalX = 0;
216 if (dmxGlobalY < 0)
217 dmxGlobalY = 0;
218 if (dmxGlobalX >= dmxGlobalWidth)
219 dmxGlobalX = dmxGlobalWidth + delta - 1;
220 if (dmxGlobalY >= dmxGlobalHeight)
221 dmxGlobalY = dmxGlobalHeight + delta - 1;
222
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 */
229 if (block)
230 OsBlockSIGIO();
231 if (pDev)
232 enqueueMotion(pDev, localX, localY);
233 if (block)
234 OsReleaseSIGIO();
235 }
236 else {
237 /* Screen is new */
238 DMXDBG4(" New screen: old=%d new=%d localX=%d localY=%d\n",
239 pScreen->myNum, dmxScreen->index, localX, localY);
240 if (block)
241 OsBlockSIGIO();
242 mieqProcessInputEvents();
243 miPointerSetScreen(inputInfo.pointer, dmxScreen->index,
244 localX, localY);
245 if (pDev)
246 enqueueMotion(pDev, localX, localY);
247 if (block)
248 OsReleaseSIGIO();
249 }
250#if 00
251 miPointerGetPosition(inputInfo.pointer, &localX, &localY);
252
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,
257 localX, localY);
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,
262 localX, localY);
263 }
264#endif
265 }
266 /* Send updates down to all core input
267 * drivers */
268 for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) {
269 int j;
270
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);
277 }
278 if (!dmxScreen)
279 ProcessInputEvents();
280}
281
282#define DMX_MAX_AXES 32 /* Max axes reported by this routine */
283static void
284dmxExtMotion(DMXLocalInputInfoPtr dmxLocal,
285 int *v, int firstAxis, int axesCount,
286 DMXMotionType type, DMXBlockType block)
287{
288 DeviceIntPtr pDevice = dmxLocal->pDevice;
289 xEvent xE[2 * DMX_MAX_AXES / 6];
290 deviceKeyButtonPointer *xev = (deviceKeyButtonPointer *) xE;
291 deviceValuator *xv = (deviceValuator *) xev + 1;
292 int thisX = 0;
293 int thisY = 0;
294 int count;
295 ValuatorMask mask;
296
297 memset(xE, 0, sizeof(xE));
298
299 if (axesCount > DMX_MAX_AXES)
300 axesCount = DMX_MAX_AXES;
301
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
306 * axes. */
307 if (type == DMX_RELATIVE) {
308 thisX = -v[0];
309 thisY = -v[1];
310 dmxLocal->lastX += thisX;
311 dmxLocal->lastY += thisY;
312 if (dmxLocal->update_position)
313 dmxLocal->update_position(dmxLocal->private,
314 dmxLocal->lastX, dmxLocal->lastY);
315 }
316 else { /* Convert to relative */
317 if (dmxLocal->lastX || dmxLocal->lastY) {
318 thisX = v[0] - dmxLocal->lastX;
319 thisY = v[1] - dmxLocal->lastY;
320 }
321 dmxLocal->lastX = v[0];
322 dmxLocal->lastY = v[1];
323 }
324 v[0] = thisX;
325 v[1] = thisY;
326 }
327
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;
333 xev->detail = 0;
334 xev->deviceid = pDevice->id | MORE_EVENTS;
335
336 xv->type = DeviceValuator;
337 xv->deviceid = pDevice->id;
338 xv->num_valuators = axesCount;
339 xv->first_valuator = firstAxis;
340 switch (xv->num_valuators) {
341 case 6:
342 xv->valuator5 = v[5];
343 case 5:
344 xv->valuator4 = v[4];
345 case 4:
346 xv->valuator3 = v[3];
347 case 3:
348 xv->valuator2 = v[2];
349 case 2:
350 xv->valuator1 = v[1];
351 case 1:
352 xv->valuator0 = v[0];
353 }
354 count = 2;
355 }
356 else {
357 int i;
358
359 for (i = 0, count = 0; i < axesCount; i += 6) {
360 xev->time = GetTimeInMillis();
361 xev->type = DeviceMotionNotify;
362 xev->detail = 0;
363 xev->deviceid = pDevice->id | MORE_EVENTS;
364 xev += 2;
365
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) {
371 case 6:
372 xv->valuator5 = v[i + 5];
373 case 5:
374 xv->valuator4 = v[i + 4];
375 case 4:
376 xv->valuator3 = v[i + 3];
377 case 3:
378 xv->valuator2 = v[i + 2];
379 case 2:
380 xv->valuator1 = v[i + 1];
381 case 1:
382 xv->valuator0 = v[i + 0];
383 }
384 xv += 2;
385 count += 2;
386 }
387 }
388
389 if (block)
390 OsBlockSIGIO();
391 valuator_mask_set_range(&mask, firstAxis, axesCount, v);
392 QueuePointerEvents(pDevice, MotionNotify, 0, POINTER_ABSOLUTE, &mask);
393
394 if (block)
395 OsReleaseSIGIO();
396}
397
398static int
399dmxTranslateAndEnqueueExtEvent(DMXLocalInputInfoPtr dmxLocal,
400 XEvent * e, DMXBlockType block)
401{
402 int type;
403 int event = -1;
404 XDeviceKeyEvent *ke = (XDeviceKeyEvent *) e;
405 XDeviceMotionEvent *me = (XDeviceMotionEvent *) e;
406 DeviceIntPtr pDevice = dmxLocal->pDevice;
407 int valuators[MAX_VALUATORS];
408 ValuatorMask mask;
409
410 if (!e)
411 return -1; /* No extended event passed, cannot handle */
412
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
417 * that X server. */
418 int i;
419 DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
420
421 for (i = 0; i < dmxInput->numDevs; i++) {
422 dmxLocal = dmxInput->devs[i];
423 if ((XID) dmxLocal->deviceId == ke->deviceid)
424 break;
425 }
426 }
427
428 if ((XID) dmxLocal->deviceId != ke->deviceid
429 || (type = dmxMapLookup(dmxLocal, e->type)) < 0)
430 return -1; /* No mapping, so this event is unhandled */
431
432 switch (type) {
433 case XI_DeviceValuator:
434 event = DeviceValuator;
435 break;
436 case XI_DeviceKeyPress:
437 event = KeyPress;
438 break;
439 case XI_DeviceKeyRelease:
440 event = KeyRelease;
441 break;
442 case XI_DeviceButtonPress:
443 event = ButtonPress;
444 break;
445 case XI_DeviceButtonRelease:
446 event = ButtonRelease;
447 break;
448 case XI_DeviceMotionNotify:
449 event = MotionNotify;
450 break;
451 case XI_DeviceFocusIn:
452 event = DeviceFocusIn;
453 break;
454 case XI_DeviceFocusOut:
455 event = DeviceFocusOut;
456 break;
457 case XI_ProximityIn:
458 event = ProximityIn;
459 break;
460 case XI_ProximityOut:
461 event = ProximityOut;
462 break;
463 case XI_DeviceStateNotify:
464 event = DeviceStateNotify;
465 break;
466 case XI_DeviceMappingNotify:
467 event = DeviceMappingNotify;
468 break;
469 case XI_ChangeDeviceNotify:
470 event = ChangeDeviceNotify;
471 break;
472 case XI_DeviceKeystateNotify:
473 event = DeviceStateNotify;
474 break;
475 case XI_DeviceButtonstateNotify:
476 event = DeviceStateNotify;
477 break;
478 }
479
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]; \
487
488 switch (type) {
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,
493 valuators);
494 if (block)
495 OsBlockSIGIO();
496 QueueKeyboardEvents(pDevice, event, ke->keycode, &mask);
497 if (block)
498 OsReleaseSIGIO();
499 break;
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,
504 valuators);
505 if (block)
506 OsBlockSIGIO();
507 QueuePointerEvents(pDevice, event, ke->keycode,
508 POINTER_ABSOLUTE, &mask);
509 if (block)
510 OsReleaseSIGIO();
511 break;
512 case XI_ProximityIn:
513 case XI_ProximityOut:
514 EXTRACT_VALUATORS(ke, valuators);
515 valuator_mask_set_range(&mask, ke->first_axis, ke->axes_count,
516 valuators);
517 if (block)
518 OsBlockSIGIO();
519 QueueProximityEvents(pDevice, event, &mask);
520 if (block)
521 OsReleaseSIGIO();
522 break;
523
524 break;
525
526 case XI_DeviceMotionNotify:
527 dmxExtMotion(dmxLocal, me->axis_data, me->first_axis, me->axes_count,
528 DMX_ABSOLUTE, block);
529 break;
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.
540
541 * Perhaps ChangeDeviceNotify should
542 * generate an error, because it is
543 * unexpected? */
544 break;
545 case XI_DeviceValuator:
546 default:
547 dmxLog(dmxWarning,
548 "XInput extension event (remote=%d -> zero-based=%d)"
549 " not supported yet\n", e->type, type);
550 return -1;
551 }
552 return 0;
553}
554
555static int
556dmxGetButtonMapping(DMXLocalInputInfoPtr dmxLocal, int button)
557{
558 ButtonClassPtr b = dmxLocal->pDevice->button;
559
560 if (button > b->numButtons) { /* This shouldn't happen. */
561 dmxLog(dmxWarning, "Button %d pressed, but only %d buttons?!?\n",
562 button, b->numButtons);
563 return button;
564 }
565 return b->map[button];
566}
567
568/** Return DMX's notion of the pointer position in the global coordinate
569 * space. */
570void
571dmxGetGlobalPosition(int *x, int *y)
572{
573 *x = dmxGlobalX;
574 *y = dmxGlobalY;
575}
576
577/** Invalidate the global position for #dmxCoreMotion. */
578void
579dmxInvalidateGlobalPosition(void)
580{
581 dmxGlobalInvalid = 1;
582}
583
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
586 * firstAxes.
587 *
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).
591 *
592 * If \a block is set to \a DMX_BLOCK, then the SIGIO handler will be
593 * blocked around calls to \a enqueueMotion(). */
594void
595dmxMotion(DevicePtr pDev, int *v, int firstAxes, int axesCount,
596 DMXMotionType type, DMXBlockType block)
597{
598 GETDMXLOCALFROMPDEV;
599
600 if (!dmxLocal->sendsCore) {
601 dmxExtMotion(dmxLocal, v, firstAxes, axesCount, type, block);
602 return;
603 }
604 if (axesCount == 2) {
605 switch (type) {
606 case DMX_RELATIVE:
607 dmxCoreMotion(pDev, dmxGlobalX - v[0], dmxGlobalY - v[1], 0, block);
608 break;
609 case DMX_ABSOLUTE:
610 dmxCoreMotion(pDev, v[0], v[1], 0, block);
611 break;
612 case DMX_ABSOLUTE_CONFINED:
613 dmxCoreMotion(pDev, v[0], v[1], -1, block);
614 break;
615 }
616 }
617}
618
619static KeySym
620dmxKeyCodeToKeySym(DMXLocalInputInfoPtr dmxLocal, KeyCode keyCode)
621{
622 KeySym keysym = NoSymbol;
623 int effectiveGroup;
624 XkbSrvInfoPtr xkbi;
625
626 if (!dmxLocal || !dmxLocal->pDevice || !dmxLocal->pDevice->key)
627 goto out;
628
629 xkbi = dmxLocal->pDevice->key->xkbInfo;
630 effectiveGroup = XkbGetEffectiveGroup(xkbi, &xkbi->state, keyCode);
631
632 if (effectiveGroup == -1)
633 goto out;
634
635 keysym = XkbKeySym(xkbi->desc, keyCode, effectiveGroup);
636 DMXDBG2("dmxKeyCodeToKeySym: Translated keyCode=%d to keySym=0x%04x\n",
637 keyCode, keysym);
638
639 out:
640 return keysym;
641}
642
643static KeyCode
644dmxKeySymToKeyCode(DMXLocalInputInfoPtr dmxLocal, KeySym keySym, int tryFirst)
645{
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
648 * xkb map */
649 XkbSrvInfoPtr xkbi = dmxLocal->pDevice->key->xkbInfo;
650 KeySymsPtr pKeySyms = XkbGetCoreMap(dmxLocal->pDevice);
651 int i;
652
653 /* Optimize for similar maps */
654 if (XkbKeycodeInRange(xkbi->desc, tryFirst)
655 && pKeySyms->map[(tryFirst - xkbi->desc->min_key_code)
656 * pKeySyms->mapWidth] == keySym)
657 return tryFirst;
658
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));
665 return i;
666 }
667 }
668 return 0;
669}
670
671static int
672dmxFixup(DevicePtr pDev, int detail, KeySym keySym)
673{
674 GETDMXLOCALFROMPDEV;
675 int keyCode;
676
677 if (!dmxLocal->pDevice->key) {
678 dmxLog(dmxWarning, "dmxFixup: not a keyboard device (%s)\n",
679 dmxLocal->pDevice->name);
680 return NoSymbol;
681 }
682 if (!keySym)
683 keySym = dmxKeyCodeToKeySym(dmxLocal, detail);
684 if (keySym == NoSymbol)
685 return detail;
686 keyCode = dmxKeySymToKeyCode(dmxLocalCoreKeyboard, keySym, detail);
687
688 return keyCode ? keyCode : detail;
689}
690
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.
694 *
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(). */
698
699void
700dmxEnqueue(DevicePtr pDev, int type, int detail, KeySym keySym,
701 XEvent * e, DMXBlockType block)
702{
703 GETDMXINPUTFROMPDEV;
704 xEvent xE;
705 DeviceIntPtr p = dmxLocal->pDevice;
706 int valuators[3];
707 ValuatorMask mask;
708
709 DMXDBG2("dmxEnqueue: Enqueuing type=%d detail=0x%0x\n", type, detail);
710
711 switch (type) {
712 case KeyPress:
713 case KeyRelease:
714 if (!keySym)
715 keySym = dmxKeyCodeToKeySym(dmxLocal, detail);
716 if (dmxCheckFunctionKeys(dmxLocal, type, keySym))
717 return;
718 if (dmxLocal->sendsCore && dmxLocal != dmxLocalCoreKeyboard)
719 xE.u.u.detail = dmxFixup(pDev, detail, keySym);
720
721 /*ErrorF("KEY %d sym %d\n", detail, (int) keySym); */
722 QueueKeyboardEvents(p, type, detail, NULL);
723 return;
724
725 case ButtonPress:
726 case ButtonRelease:
727 detail = dmxGetButtonMapping(dmxLocal, detail);
728 valuator_mask_zero(&mask);
729 QueuePointerEvents(p, type, detail, 0, &mask);
730 return;
731
732 case MotionNotify:
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);
739 return;
740
741 case EnterNotify:
742 case LeaveNotify:
743 case KeymapNotify:
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. */
748 return;
749 default:
750 if (type == ProximityIn || type == ProximityOut) {
751 if (dmxLocal->sendsCore)
752 return; /* Not a core event */
753 break;
754 }
755 if (type >= LASTEvent) {
756 if (dmxTranslateAndEnqueueExtEvent(dmxLocal, e, block))
757 dmxLogInput(dmxInput, "Unhandled extension event: %d\n", type);
758 }
759 else {
760 dmxLogInput(dmxInput, "Unhandled event: %d (%s)\n",
761 type, dmxEventName(type));
762 }
763 return;
764 }
765
766}
767
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
773 * is returned. */
774int
775dmxCheckSpecialKeys(DevicePtr pDev, KeySym keySym)
776{
777 GETDMXINPUTFROMPDEV;
778 int vt = 0;
779 unsigned short state = 0;
780
781 if (dmxLocal->sendsCore)
782 state =
783 XkbStateFieldFromRec(&dmxLocalCoreKeyboard->pDevice->key->xkbInfo->
784 state);
785 else if (dmxLocal->pDevice->key)
786 state = XkbStateFieldFromRec(&dmxLocal->pDevice->key->xkbInfo->state);
787
788 if (!dmxLocal->sendsCore)
789 return 0; /* Only for core devices */
790
791 DMXDBG2("dmxCheckSpecialKeys: keySym=0x%04x state=0x%04x\n", keySym, state);
792
793 if ((state & (ControlMask | Mod1Mask)) != (ControlMask | Mod1Mask))
794 return 0;
795
796 switch (keySym) {
797 case XK_F1:
798 case XK_F2:
799 case XK_F3:
800 case XK_F4:
801 case XK_F5:
802 case XK_F6:
803 case XK_F7:
804 case XK_F8:
805 case XK_F9:
806 case XK_F10:
807 vt = keySym - XK_F1 + 1;
808 break;
809
810 case XK_F11:
811 case XK_F12:
812 vt = keySym - XK_F11 + 11;
813 break;
814
815 case XK_q: /* To avoid confusion */
816 case XK_BackSpace:
817 case XK_Delete:
818 case XK_KP_Delete:
819 dmxLog(dmxInfo, "User request for termination\n");
820 dispatchException |= DE_TERMINATE;
821 return -1; /* Terminate */
822 }
823
824 if (vt) {
825 dmxLog(dmxInfo, "Request to switch to VT %d\n", vt);
826 dmxInput->vt_switch_pending = vt;
827 return vt;
828 }
829
830 return 0; /* Do nothing */
831}