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