First import
[xorg_rtime.git] / xorg-server-1.4 / hw / dmx / input / dmxevents.c
blob26dc067dcf529e7fbc2cf8f8d644873bcfe42efb
1 /*
2 * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
4 * All Rights Reserved.
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
25 * SOFTWARE.
29 * Authors:
30 * Rickard E. (Rik) Faith <faith@redhat.com>
34 /** \file
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>
40 #endif
42 #define DMX_EVENTS_DEBUG 0
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 "dmxeq.h"
51 #include "dmxsigio.h"
52 #include "dmxmap.h"
54 #include <X11/keysym.h>
55 #include "opaque.h"
56 #include "inputstr.h"
57 #include "mipointer.h"
58 #include "mi.h"
60 #ifdef XINPUT
61 #include "XIstubs.h"
62 #endif
64 static int dmxGlobalX, dmxGlobalY; /* Global cursor position */
65 static int dmxGlobalInvalid; /* Flag indicating dmxCoreMotion
66 * should move the mouse anyway. */
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
88 static int dmxApplyFunctions(DMXInputInfo *dmxInput, DMXFunctionType f)
90 int i;
91 int rc = 0;
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;
99 static int dmxCheckFunctionKeys(DMXLocalInputInfoPtr dmxLocal,
100 int type,
101 KeySym keySym)
103 DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
104 unsigned short state = 0;
106 #if 1 /* hack to detect ctrl-alt-q, etc */
107 static int ctrl = 0, alt = 0;
108 /* keep track of ctrl/alt key status */
109 if (type == KeyPress && keySym == 0xffe3) {
110 ctrl = 1;
112 else if (type == KeyRelease && keySym == 0xffe3) {
113 ctrl = 0;
115 else if (type == KeyPress && keySym == 0xffe9) {
116 alt = 1;
118 else if (type == KeyRelease && keySym == 0xffe9) {
119 alt = 0;
121 if (!ctrl || !alt)
122 return 0;
123 #else
124 if (dmxLocal->sendsCore)
125 state = dmxLocalCoreKeyboard->pDevice->key->state;
126 else if (dmxLocal->pDevice->key)
127 state = dmxLocal->pDevice->key->state;
129 DMXDBG3("dmxCheckFunctionKeys: keySym=0x%04x %s state=0x%04x\n",
130 keySym, type == KeyPress ? "press" : "release", state);
132 if ((state & (ControlMask|Mod1Mask)) != (ControlMask|Mod1Mask))
133 return 0;
134 #endif
136 switch (keySym) {
137 case XK_g:
138 if (type == KeyPress)
139 dmxApplyFunctions(dmxInput, DMX_FUNCTION_GRAB);
140 return 1;
141 case XK_f:
142 if (type == KeyPress)
143 dmxApplyFunctions(dmxInput, DMX_FUNCTION_FINE);
144 return 1;
145 case XK_q:
146 if (type == KeyPress && dmxLocal->sendsCore)
147 if (dmxApplyFunctions(dmxInput, DMX_FUNCTION_TERMINATE)) {
148 dmxLog(dmxInfo, "User request for termination\n");
149 dispatchException |= DE_TERMINATE;
151 return 1;
154 return 0;
157 #ifdef XINPUT
158 static void dmxEnqueueExtEvent(DMXLocalInputInfoPtr dmxLocal, xEvent *e,
159 DMXBlockType block)
161 xEvent xE[2];
162 deviceKeyButtonPointer *xev = (deviceKeyButtonPointer *)xE;
163 deviceValuator *xv = (deviceValuator *)xev+1;
164 DeviceIntPtr pDevice = dmxLocal->pDevice;
165 DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
166 int type = e->u.u.type;
168 switch (e->u.u.type) {
169 case KeyPress:
170 type = DeviceKeyPress;
171 break;
172 case KeyRelease:
173 type = DeviceKeyRelease;
174 break;
175 case ButtonPress:
176 type = DeviceButtonPress;
177 break;
178 case ButtonRelease:
179 type = DeviceButtonRelease;
180 break;
181 case MotionNotify:
182 dmxLog(dmxError,
183 "dmxEnqueueExtEvent: MotionNotify not allowed here\n");
184 return;
185 default:
186 if (e->u.u.type == ProximityIn || e->u.u.type == ProximityOut)
187 break;
188 dmxLogInput(dmxInput,
189 "dmxEnqueueExtEvent: Unhandled %s event (%d)\n",
190 e->u.u.type >= LASTEvent ? "extension" : "non-extension",
191 e->u.u.type);
192 return;
195 xev->type = type;
196 xev->detail = e->u.u.detail;
197 xev->deviceid = pDevice->id | MORE_EVENTS;
198 xev->time = e->u.keyButtonPointer.time;
200 xv->type = DeviceValuator;
201 xv->deviceid = pDevice->id;
202 xv->num_valuators = 0;
203 xv->first_valuator = 0;
205 if (block)
206 dmxSigioBlock();
207 dmxeqEnqueue(xE);
208 if (block)
209 dmxSigioUnblock();
211 #endif
213 DMXScreenInfo *dmxFindFirstScreen(int x, int y)
215 int i;
217 for (i = 0; i < dmxNumScreens; i++) {
218 DMXScreenInfo *dmxScreen = &dmxScreens[i];
219 if (dmxOnScreen(x, y, dmxScreen))
220 return dmxScreen;
222 return NULL;
227 * Enqueue a motion event.
229 static void enqueueMotion(DevicePtr pDev, int x, int y)
231 GETDMXLOCALFROMPDEV;
232 DeviceIntPtr p = dmxLocal->pDevice;
233 int i, nevents, valuators[3];
234 xEvent *events = Xcalloc(sizeof(xEvent), GetMaximumEventsNum());
235 int detail = 0; /* XXX should this be mask of pressed buttons? */
236 valuators[0] = x;
237 valuators[1] = y;
238 nevents = GetPointerEvents(events, p, MotionNotify, detail,
239 POINTER_ABSOLUTE, 0, 2, valuators);
240 for (i = 0; i < nevents; i++)
241 mieqEnqueue(p, events + i);
242 xfree(events);
243 return;
247 void
248 dmxCoreMotion(DevicePtr pDev, int x, int y, int delta, DMXBlockType block)
250 DMXScreenInfo *dmxScreen;
251 DMXInputInfo *dmxInput;
252 ScreenPtr pScreen;
253 int localX;
254 int localY;
255 int i;
257 if (!dmxGlobalInvalid && dmxGlobalX == x && dmxGlobalY == y)
258 return;
260 DMXDBG5("dmxCoreMotion(%d,%d,%d) dmxGlobalX=%d dmxGlobalY=%d\n",
261 x, y, delta, dmxGlobalX, dmxGlobalY);
263 dmxGlobalInvalid = 0;
264 dmxGlobalX = x;
265 dmxGlobalY = y;
267 if (dmxGlobalX < 0)
268 dmxGlobalX = 0;
269 if (dmxGlobalY < 0)
270 dmxGlobalY = 0;
271 if (dmxGlobalX >= dmxGlobalWidth)
272 dmxGlobalX = dmxGlobalWidth + delta -1;
273 if (dmxGlobalY >= dmxGlobalHeight)
274 dmxGlobalY = dmxGlobalHeight + delta -1;
276 if ((dmxScreen = dmxFindFirstScreen(dmxGlobalX, dmxGlobalY))) {
277 localX = dmxGlobalX - dmxScreen->rootXOrigin;
278 localY = dmxGlobalY - dmxScreen->rootYOrigin;
279 if ((pScreen = miPointerGetScreen(inputInfo.pointer))
280 && pScreen->myNum == dmxScreen->index) {
281 /* Screen is old screen */
282 if (block)
283 dmxSigioBlock();
284 if (pDev)
285 enqueueMotion(pDev, localX, localY);
286 if (block)
287 dmxSigioUnblock();
288 } else {
289 /* Screen is new */
290 DMXDBG4(" New screen: old=%d new=%d localX=%d localY=%d\n",
291 pScreen->myNum, dmxScreen->index, localX, localY);
292 if (block)
293 dmxSigioBlock();
294 dmxeqProcessInputEvents();
295 miPointerSetScreen(inputInfo.pointer, dmxScreen->index,
296 localX, localY);
297 if (pDev)
298 enqueueMotion(pDev, localX, localY);
299 if (block)
300 dmxSigioUnblock();
302 #if 00
303 miPointerGetPosition(inputInfo.pointer, &localX, &localY);
305 if ((pScreen = miPointerGetScreen(inputInfo.pointer))) {
306 dmxGlobalX = localX + dmxScreens[pScreen->myNum].rootXOrigin;
307 dmxGlobalY = localY + dmxScreens[pScreen->myNum].rootYOrigin;
308 ErrorF("Global is now %d, %d %d, %d\n", dmxGlobalX, dmxGlobalY,
309 localX, localY);
310 DMXDBG6(" Moved to dmxGlobalX=%d dmxGlobalY=%d"
311 " on screen index=%d/%d localX=%d localY=%d\n",
312 dmxGlobalX, dmxGlobalY,
313 dmxScreen ? dmxScreen->index : -1, pScreen->myNum,
314 localX, localY);
316 #endif
318 /* Send updates down to all core input
319 * drivers */
320 for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) {
321 int j;
322 for (j = 0; j < dmxInput->numDevs; j += dmxInput->devs[j]->binding)
323 if (!dmxInput->detached
324 && dmxInput->devs[j]->sendsCore
325 && dmxInput->devs[j]->update_position)
326 dmxInput->devs[j]->update_position(dmxInput->devs[j]->private,
327 dmxGlobalX, dmxGlobalY);
329 if (!dmxScreen) ProcessInputEvents();
334 #ifdef XINPUT
335 #define DMX_MAX_AXES 32 /* Max axes reported by this routine */
336 static void dmxExtMotion(DMXLocalInputInfoPtr dmxLocal,
337 int *v, int firstAxis, int axesCount,
338 DMXMotionType type, DMXBlockType block)
340 DeviceIntPtr pDevice = dmxLocal->pDevice;
341 xEvent xE[2 * DMX_MAX_AXES/6];
342 deviceKeyButtonPointer *xev = (deviceKeyButtonPointer *)xE;
343 deviceValuator *xv = (deviceValuator *)xev+1;
344 int thisX = 0;
345 int thisY = 0;
346 int i;
347 int count;
349 memset(xE, 0, sizeof(xE));
351 if (axesCount > DMX_MAX_AXES) axesCount = DMX_MAX_AXES;
353 if (!pDevice->valuator->mode && axesCount == 2) {
354 /* The dmx console is a relative mode
355 * device that sometimes reports
356 * absolute motion. It only has two
357 * axes. */
358 if (type == DMX_RELATIVE) {
359 thisX = -v[0];
360 thisY = -v[1];
361 dmxLocal->lastX += thisX;
362 dmxLocal->lastY += thisY;
363 if (dmxLocal->update_position)
364 dmxLocal->update_position(dmxLocal->private,
365 dmxLocal->lastX, dmxLocal->lastY);
366 } else { /* Convert to relative */
367 if (dmxLocal->lastX || dmxLocal->lastY) {
368 thisX = v[0] - dmxLocal->lastX;
369 thisY = v[1] - dmxLocal->lastY;
371 dmxLocal->lastX = v[0];
372 dmxLocal->lastY = v[1];
374 v[0] = thisX;
375 v[1] = thisY;
378 if (axesCount <= 6) {
379 /* Optimize for the common case when
380 * only 1 or 2 axes change. */
381 xev->time = GetTimeInMillis();
382 xev->type = DeviceMotionNotify;
383 xev->detail = 0;
384 xev->deviceid = pDevice->id | MORE_EVENTS;
386 xv->type = DeviceValuator;
387 xv->deviceid = pDevice->id;
388 xv->num_valuators = axesCount;
389 xv->first_valuator = firstAxis;
390 switch (xv->num_valuators) {
391 case 6: xv->valuator5 = v[5];
392 case 5: xv->valuator4 = v[4];
393 case 4: xv->valuator3 = v[3];
394 case 3: xv->valuator2 = v[2];
395 case 2: xv->valuator1 = v[1];
396 case 1: xv->valuator0 = v[0];
398 count = 2;
399 } else {
400 for (i = 0, count = 0; i < axesCount; i += 6) {
401 xev->time = GetTimeInMillis();
402 xev->type = DeviceMotionNotify;
403 xev->detail = 0;
404 xev->deviceid = pDevice->id | MORE_EVENTS;
405 xev += 2;
407 xv->type = DeviceValuator;
408 xv->deviceid = pDevice->id;
409 xv->num_valuators = (i+6 >= axesCount ? axesCount - i : 6);
410 xv->first_valuator = firstAxis + i;
411 switch (xv->num_valuators) {
412 case 6: xv->valuator5 = v[i+5];
413 case 5: xv->valuator4 = v[i+4];
414 case 4: xv->valuator3 = v[i+3];
415 case 3: xv->valuator2 = v[i+2];
416 case 2: xv->valuator1 = v[i+1];
417 case 1: xv->valuator0 = v[i+0];
419 xv += 2;
420 count += 2;
424 if (block)
425 dmxSigioBlock();
426 dmxPointerPutMotionEvent(pDevice, firstAxis, axesCount, v, xev->time);
427 dmxeqEnqueue(xE);
428 if (block)
429 dmxSigioUnblock();
432 static int dmxTranslateAndEnqueueExtEvent(DMXLocalInputInfoPtr dmxLocal,
433 XEvent *e, DMXBlockType block)
435 xEvent xE[2];
436 deviceKeyButtonPointer *xev = (deviceKeyButtonPointer *)xE;
437 deviceValuator *xv = (deviceValuator *)xev+1;
438 int type;
439 int event = -1;
440 XDeviceKeyEvent *ke = (XDeviceKeyEvent *)e;
441 XDeviceMotionEvent *me = (XDeviceMotionEvent *)e;
443 if (!e)
444 return -1; /* No extended event passed, cannot handle */
446 if ((XID)dmxLocal->deviceId != ke->deviceid) {
447 /* Search for the correct dmxLocal,
448 * since backend and console events are
449 * picked up for the first device on
450 * that X server. */
451 int i;
452 DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
453 for (i = 0; i < dmxInput->numDevs; i++) {
454 dmxLocal = dmxInput->devs[i];
455 if ((XID)dmxLocal->deviceId == ke->deviceid)
456 break;
460 if ((XID)dmxLocal->deviceId != ke->deviceid
461 || (type = dmxMapLookup(dmxLocal, e->type)) < 0)
462 return -1; /* No mapping, so this event is unhandled */
464 switch (type) {
465 case XI_DeviceValuator: event = DeviceValuator; break;
466 case XI_DeviceKeyPress: event = DeviceKeyPress; break;
467 case XI_DeviceKeyRelease: event = DeviceKeyRelease; break;
468 case XI_DeviceButtonPress: event = DeviceButtonPress; break;
469 case XI_DeviceButtonRelease: event = DeviceButtonRelease; break;
470 case XI_DeviceMotionNotify: event = DeviceMotionNotify; break;
471 case XI_DeviceFocusIn: event = DeviceFocusIn; break;
472 case XI_DeviceFocusOut: event = DeviceFocusOut; break;
473 case XI_ProximityIn: event = ProximityIn; break;
474 case XI_ProximityOut: event = ProximityOut; break;
475 case XI_DeviceStateNotify: event = DeviceStateNotify; break;
476 case XI_DeviceMappingNotify: event = DeviceMappingNotify; break;
477 case XI_ChangeDeviceNotify: event = ChangeDeviceNotify; break;
478 case XI_DeviceKeystateNotify: event = DeviceStateNotify; break;
479 case XI_DeviceButtonstateNotify: event = DeviceStateNotify; break;
482 switch (type) {
483 case XI_DeviceKeyPress:
484 case XI_DeviceKeyRelease:
485 case XI_DeviceButtonPress:
486 case XI_DeviceButtonRelease:
487 case XI_ProximityIn:
488 case XI_ProximityOut:
489 xev->type = event;
490 xev->detail = ke->keycode; /* same as ->button */
491 xev->deviceid = dmxLocal->pDevice->id | MORE_EVENTS;
492 xev->time = GetTimeInMillis();
494 xv->type = DeviceValuator;
495 xv->deviceid = dmxLocal->pDevice->id;
496 xv->num_valuators = ke->axes_count;
497 xv->first_valuator = ke->first_axis;
498 xv->valuator0 = ke->axis_data[0];
499 xv->valuator1 = ke->axis_data[1];
500 xv->valuator2 = ke->axis_data[2];
501 xv->valuator3 = ke->axis_data[3];
502 xv->valuator4 = ke->axis_data[4];
503 xv->valuator5 = ke->axis_data[5];
505 if (block)
506 dmxSigioBlock();
507 dmxeqEnqueue(xE);
508 if (block)
509 dmxSigioUnblock();
510 break;
512 case XI_DeviceMotionNotify:
513 dmxExtMotion(dmxLocal, me->axis_data, me->first_axis, me->axes_count,
514 DMX_ABSOLUTE, block);
515 break;
516 case XI_DeviceFocusIn:
517 case XI_DeviceFocusOut:
518 case XI_DeviceStateNotify:
519 case XI_DeviceMappingNotify:
520 case XI_ChangeDeviceNotify:
521 case XI_DeviceKeystateNotify:
522 case XI_DeviceButtonstateNotify:
523 /* These are ignored, since DMX will
524 * generate its own events of these
525 * types, as necessary.
527 * Perhaps ChangeDeviceNotify should
528 * generate an error, because it is
529 * unexpected? */
530 break;
531 case XI_DeviceValuator:
532 default:
533 dmxLog(dmxWarning,
534 "XInput extension event (remote=%d -> zero-based=%d)"
535 " not supported yet\n", e->type, type);
536 return -1;
538 return 0;
540 #endif
542 static int dmxGetButtonMapping(DMXLocalInputInfoPtr dmxLocal, int button)
544 ButtonClassPtr b = dmxLocal->pDevice->button;
546 if (button > b->numButtons) { /* This shouldn't happen. */
547 dmxLog(dmxWarning, "Button %d pressed, but only %d buttons?!?\n",
548 button, b->numButtons);
549 return button;
551 return b->map[button];
554 /** Return DMX's notion of the pointer position in the global coordinate
555 * space. */
556 void dmxGetGlobalPosition(int *x, int *y)
558 *x = dmxGlobalX;
559 *y = dmxGlobalY;
562 /** Invalidate the global position for #dmxCoreMotion. */
563 void dmxInvalidateGlobalPosition(void)
565 dmxGlobalInvalid = 1;
568 /** Enqueue a motion event for \a pDev. The \a v vector has length \a
569 * axesCount, and contains values for each of the axes, starting at \a
570 * firstAxes.
572 * The \a type of the motion may be \a DMX_RELATIVE, \a DMX_ABSOLUTE, or
573 * \a DMX_ABSOLUTE_CONFINED (in the latter case, the pointer will not be
574 * allowed to move outside the global boundaires).
576 * If \a block is set to \a DMX_BLOCK, then the SIGIO handler will be
577 * blocked around calls to #dmxeqEnqueue(). */
578 void dmxMotion(DevicePtr pDev, int *v, int firstAxes, int axesCount,
579 DMXMotionType type, DMXBlockType block)
581 #ifdef XINPUT
582 GETDMXLOCALFROMPDEV;
584 if (!dmxLocal->sendsCore) {
585 dmxExtMotion(dmxLocal, v, firstAxes, axesCount, type, block);
586 return;
588 #endif
589 if (axesCount == 2) {
590 switch (type) {
591 case DMX_RELATIVE:
592 dmxCoreMotion(pDev, dmxGlobalX - v[0], dmxGlobalY - v[1], 0, block);
593 break;
594 case DMX_ABSOLUTE:
595 dmxCoreMotion(pDev, v[0], v[1], 0, block);
596 break;
597 case DMX_ABSOLUTE_CONFINED:
598 dmxCoreMotion(pDev, v[0], v[1], -1, block);
599 break;
604 static KeySym dmxKeyCodeToKeySym(DMXLocalInputInfoPtr dmxLocal,
605 KeyCode keyCode)
607 KeySymsPtr pKeySyms = NULL;
609 if (!dmxLocal || !dmxLocal->pDevice || !dmxLocal->pDevice->key)
610 return NoSymbol;
611 pKeySyms = &dmxLocal->pDevice->key->curKeySyms;
612 if (!pKeySyms)
613 return NoSymbol;
615 if (keyCode > pKeySyms->minKeyCode && keyCode <= pKeySyms->maxKeyCode) {
616 DMXDBG2("dmxKeyCodeToKeySym: Translated keyCode=%d to keySym=0x%04x\n",
617 keyCode,
618 pKeySyms->map[(keyCode - pKeySyms->minKeyCode)
619 * pKeySyms->mapWidth]);
621 return pKeySyms->map[(keyCode - pKeySyms->minKeyCode)
622 * pKeySyms->mapWidth];
624 return NoSymbol;
627 static KeyCode dmxKeySymToKeyCode(DMXLocalInputInfoPtr dmxLocal, KeySym keySym,
628 int tryFirst)
630 KeySymsPtr pKeySyms = &dmxLocal->pDevice->key->curKeySyms;
631 int i;
633 /* Optimize for similar maps */
634 if (tryFirst >= pKeySyms->minKeyCode
635 && tryFirst <= pKeySyms->maxKeyCode
636 && pKeySyms->map[(tryFirst - pKeySyms->minKeyCode)
637 * pKeySyms->mapWidth] == keySym)
638 return tryFirst;
640 for (i = pKeySyms->minKeyCode; i <= pKeySyms->maxKeyCode; i++) {
641 if (pKeySyms->map[(i - pKeySyms->minKeyCode)
642 * pKeySyms->mapWidth] == keySym) {
643 DMXDBG3("dmxKeySymToKeyCode: Translated keySym=0x%04x to"
644 " keyCode=%d (reverses to core keySym=0x%04x)\n",
645 keySym, i, dmxKeyCodeToKeySym(dmxLocalCoreKeyboard,i));
646 return i;
649 return 0;
652 static int dmxFixup(DevicePtr pDev, int detail, KeySym keySym)
654 GETDMXLOCALFROMPDEV;
655 int keyCode;
657 if (!dmxLocal->pDevice->key) {
658 dmxLog(dmxWarning, "dmxFixup: not a keyboard device (%s)\n",
659 dmxLocal->pDevice->name);
660 return NoSymbol;
662 if (!keySym)
663 keySym = dmxKeyCodeToKeySym(dmxLocal, detail);
664 if (keySym == NoSymbol)
665 return detail;
666 keyCode = dmxKeySymToKeyCode(dmxLocalCoreKeyboard, keySym, detail);
668 return keyCode ? keyCode : detail;
671 /** Enqueue an event from the \a pDev device with the
672 * specified \a type and \a detail. If the event is a KeyPress or
673 * KeyRelease event, then the \a keySym is also specified.
675 * If \a block is set to \a DMX_BLOCK, then the SIGIO handler will be
676 * blocked around calls to #dmxeqEnqueue(). */
678 void dmxEnqueue(DevicePtr pDev, int type, int detail, KeySym keySym,
679 XEvent *e, DMXBlockType block)
681 GETDMXINPUTFROMPDEV;
682 xEvent xE;
683 DeviceIntPtr p = dmxLocal->pDevice;
684 int i, nevents, valuators[3];
685 xEvent *events;
687 DMXDBG2("dmxEnqueue: Enqueuing type=%d detail=0x%0x\n", type, detail);
689 switch (type) {
690 case KeyPress:
691 case KeyRelease:
692 if (!keySym)
693 keySym = dmxKeyCodeToKeySym(dmxLocal, detail);
694 if (dmxCheckFunctionKeys(dmxLocal, type, keySym))
695 return;
696 if (dmxLocal->sendsCore && dmxLocal != dmxLocalCoreKeyboard)
697 xE.u.u.detail = dmxFixup(pDev, detail, keySym);
699 events = Xcalloc(sizeof(xEvent), GetMaximumEventsNum());
700 /*ErrorF("KEY %d sym %d\n", detail, (int) keySym);*/
701 nevents = GetKeyboardEvents(events, p, type, detail);
702 for (i = 0; i < nevents; i++)
703 mieqEnqueue(p, events + i);
704 xfree(events);
705 return;
707 case ButtonPress:
708 case ButtonRelease:
709 detail = dmxGetButtonMapping(dmxLocal, detail);
710 events = Xcalloc(sizeof(xEvent), GetMaximumEventsNum());
711 nevents = GetPointerEvents(events, p, type, detail,
712 POINTER_ABSOLUTE,
713 0, /* first_valuator = 0 */
714 0, /* num_valuators = 0 */
715 valuators);
716 for (i = 0; i < nevents; i++)
717 mieqEnqueue(p, events + i);
718 xfree(events);
719 return;
721 case MotionNotify:
722 events = Xcalloc(sizeof(xEvent), GetMaximumEventsNum());
723 valuators[0] = e->xmotion.x;
724 valuators[1] = e->xmotion.y;
725 valuators[2] = e->xmotion.state;
726 nevents = GetPointerEvents(events, p, type, detail,
727 POINTER_ABSOLUTE, 0, 3, valuators);
728 for (i = 0; i < nevents; i++)
729 mieqEnqueue(p, events + i);
730 xfree(events);
731 return;
733 case EnterNotify:
734 case LeaveNotify:
735 case KeymapNotify:
736 case MappingNotify: /* This is sent because we change the
737 * modifier map on the backend/console
738 * input device so that we have complete
739 * control of the input device LEDs. */
740 return;
741 default:
742 #ifdef XINPUT
743 if (type == ProximityIn || type == ProximityOut) {
744 if (dmxLocal->sendsCore)
745 return; /* Not a core event */
746 break;
748 #endif
749 if (type >= LASTEvent) {
750 #ifdef XINPUT
751 if (dmxTranslateAndEnqueueExtEvent(dmxLocal, e, block))
752 #endif
753 dmxLogInput(dmxInput, "Unhandled extension event: %d\n", type);
754 } else {
755 dmxLogInput(dmxInput, "Unhandled event: %d (%s)\n",
756 type, dmxEventName(type));
758 return;
761 #if 00 /* dead code? */
762 memset(&xE, 0, sizeof(xE));
763 xE.u.u.type = type;
764 xE.u.u.detail = detail;
765 xE.u.keyButtonPointer.time = GetTimeInMillis();
767 #ifdef XINPUT
768 if (!dmxLocal->sendsCore)
769 dmxEnqueueExtEvent(dmxLocal, &xE, block);
770 else
771 #endif
772 dmxeqEnqueue(&xE);
773 #endif /*00*/
776 /** A pointer to this routine is passed to low-level input drivers so
777 * that all special keychecking is unified to this file. This function
778 * returns 0 if no special keys have been pressed. If the user has
779 * requested termination of the DMX server, -1 is returned. If the user
780 * has requested a switch to a VT, then the (1-based) number of that VT
781 * is returned. */
782 int dmxCheckSpecialKeys(DevicePtr pDev, KeySym keySym)
784 GETDMXINPUTFROMPDEV;
785 int vt = 0;
786 unsigned short state = 0;
788 if (dmxLocal->sendsCore)
789 state = dmxLocalCoreKeyboard->pDevice->key->state;
790 else if (dmxLocal->pDevice->key)
791 state = dmxLocal->pDevice->key->state;
793 if (!dmxLocal->sendsCore) return 0; /* Only for core devices */
795 DMXDBG2("dmxCheckSpecialKeys: keySym=0x%04x state=0x%04x\n", keySym,state);
797 if ((state & (ControlMask|Mod1Mask)) != (ControlMask|Mod1Mask)) return 0;
799 switch (keySym) {
800 case XK_F1:
801 case XK_F2:
802 case XK_F3:
803 case XK_F4:
804 case XK_F5:
805 case XK_F6:
806 case XK_F7:
807 case XK_F8:
808 case XK_F9:
809 case XK_F10:
810 vt = keySym - XK_F1 + 1;
811 break;
813 case XK_F11:
814 case XK_F12:
815 vt = keySym - XK_F11 + 11;
816 break;
818 case XK_q: /* To avoid confusion */
819 case XK_BackSpace:
820 case XK_Delete:
821 case XK_KP_Delete:
822 dmxLog(dmxInfo, "User request for termination\n");
823 dispatchException |= DE_TERMINATE;
824 return -1; /* Terminate */
827 if (vt) {
828 dmxLog(dmxInfo, "Request to switch to VT %d\n", vt);
829 dmxInput->vt_switch_pending = vt;
830 return vt;
833 return 0; /* Do nothing */