| 1 | /* |
| 2 | * Copyright 2001-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 | * David H. Dawes <dawes@xfree86.org> |
| 31 | * Kevin E. Martin <kem@redhat.com> |
| 32 | * Rickard E. (Rik) Faith <faith@redhat.com> |
| 33 | */ |
| 34 | |
| 35 | /** \file |
| 36 | * |
| 37 | * This file implements common routines used by the backend and console |
| 38 | * input devices. |
| 39 | */ |
| 40 | |
| 41 | #ifdef HAVE_DMX_CONFIG_H |
| 42 | #include <dmx-config.h> |
| 43 | #endif |
| 44 | |
| 45 | #define DMX_STATE_DEBUG 0 |
| 46 | |
| 47 | #include "dmxinputinit.h" |
| 48 | #include "dmxcommon.h" |
| 49 | #include "dmxconsole.h" |
| 50 | #include "dmxprop.h" |
| 51 | #include "dmxsync.h" |
| 52 | #include "dmxmap.h" |
| 53 | |
| 54 | #include "inputstr.h" |
| 55 | #include "input.h" |
| 56 | #include <X11/keysym.h> |
| 57 | #include "mipointer.h" |
| 58 | #include "scrnintstr.h" |
| 59 | |
| 60 | #include <unistd.h> /* For usleep() */ |
| 61 | |
| 62 | #if DMX_STATE_DEBUG |
| 63 | #define DMXDBG0(f) dmxLog(dmxDebug,f) |
| 64 | #else |
| 65 | #define DMXDBG0(f) |
| 66 | #endif |
| 67 | |
| 68 | /** Each device has a private area that is visible only from inside the |
| 69 | * driver code. */ |
| 70 | typedef struct _myPrivate { |
| 71 | DMX_COMMON_PRIVATE; |
| 72 | } myPrivate; |
| 73 | |
| 74 | static void |
| 75 | dmxCommonKbdSetAR(Display * display, unsigned char *old, unsigned char *new) |
| 76 | { |
| 77 | XKeyboardControl kc; |
| 78 | XKeyboardState ks; |
| 79 | unsigned long mask = KBKey | KBAutoRepeatMode; |
| 80 | int i, j; |
| 81 | int minKeycode, maxKeycode; |
| 82 | |
| 83 | if (!old) { |
| 84 | XGetKeyboardControl(display, &ks); |
| 85 | old = (unsigned char *) ks.auto_repeats; |
| 86 | } |
| 87 | |
| 88 | XDisplayKeycodes(display, &minKeycode, &maxKeycode); |
| 89 | for (i = 1; i < 32; i++) { |
| 90 | if (!old || old[i] != new[i]) { |
| 91 | for (j = 0; j < 8; j++) { |
| 92 | if ((new[i] & (1 << j)) != (old[i] & (1 << j))) { |
| 93 | kc.key = i * 8 + j; |
| 94 | kc.auto_repeat_mode = ((new[i] & (1 << j)) |
| 95 | ? AutoRepeatModeOn |
| 96 | : AutoRepeatModeOff); |
| 97 | if (kc.key >= minKeycode && kc.key <= maxKeycode) |
| 98 | XChangeKeyboardControl(display, mask, &kc); |
| 99 | } |
| 100 | } |
| 101 | } |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | static void |
| 106 | dmxCommonKbdSetLeds(Display * display, unsigned long new) |
| 107 | { |
| 108 | int i; |
| 109 | XKeyboardControl kc; |
| 110 | |
| 111 | for (i = 0; i < 32; i++) { |
| 112 | kc.led = i + 1; |
| 113 | kc.led_mode = (new & (1 << i)) ? LedModeOn : LedModeOff; |
| 114 | XChangeKeyboardControl(display, KBLed | KBLedMode, &kc); |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | static void |
| 119 | dmxCommonKbdSetCtrl(Display * display, KeybdCtrl * old, KeybdCtrl * new) |
| 120 | { |
| 121 | XKeyboardControl kc; |
| 122 | unsigned long mask = KBKeyClickPercent | KBAutoRepeatMode; |
| 123 | |
| 124 | if (!old || old->click != new->click || old->autoRepeat != new->autoRepeat) { |
| 125 | |
| 126 | kc.key_click_percent = new->click; |
| 127 | kc.auto_repeat_mode = new->autoRepeat; |
| 128 | |
| 129 | XChangeKeyboardControl(display, mask, &kc); |
| 130 | } |
| 131 | |
| 132 | dmxCommonKbdSetLeds(display, new->leds); |
| 133 | dmxCommonKbdSetAR(display, old ? old->autoRepeats : NULL, new->autoRepeats); |
| 134 | } |
| 135 | |
| 136 | static void |
| 137 | dmxCommonMouSetCtrl(Display * display, PtrCtrl * old, PtrCtrl * new) |
| 138 | { |
| 139 | Bool do_accel, do_threshold; |
| 140 | |
| 141 | if (!old |
| 142 | || old->num != new->num |
| 143 | || old->den != new->den || old->threshold != new->threshold) { |
| 144 | do_accel = (new->num > 0 && new->den > 0); |
| 145 | do_threshold = (new->threshold > 0); |
| 146 | if (do_accel || do_threshold) { |
| 147 | XChangePointerControl(display, do_accel, do_threshold, |
| 148 | new->num, new->den, new->threshold); |
| 149 | } |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | /** Update the keyboard control. */ |
| 154 | void |
| 155 | dmxCommonKbdCtrl(DevicePtr pDev, KeybdCtrl * ctrl) |
| 156 | { |
| 157 | GETPRIVFROMPDEV; |
| 158 | |
| 159 | if (!priv->stateSaved && priv->be) |
| 160 | dmxCommonSaveState(priv); |
| 161 | if (!priv->display || !priv->stateSaved) |
| 162 | return; |
| 163 | dmxCommonKbdSetCtrl(priv->display, |
| 164 | priv->kctrlset ? &priv->kctrl : NULL, ctrl); |
| 165 | priv->kctrl = *ctrl; |
| 166 | priv->kctrlset = 1; |
| 167 | } |
| 168 | |
| 169 | /** Update the mouse control. */ |
| 170 | void |
| 171 | dmxCommonMouCtrl(DevicePtr pDev, PtrCtrl * ctrl) |
| 172 | { |
| 173 | GETPRIVFROMPDEV; |
| 174 | |
| 175 | /* Don't set the acceleration for the |
| 176 | * console, because that should be |
| 177 | * controlled by the X server that the |
| 178 | * console is running on. Otherwise, |
| 179 | * the acceleration for the console |
| 180 | * window would be unexpected for the |
| 181 | * scale of the window. */ |
| 182 | if (priv->be) { |
| 183 | dmxCommonMouSetCtrl(priv->display, |
| 184 | priv->mctrlset ? &priv->mctrl : NULL, ctrl); |
| 185 | priv->mctrl = *ctrl; |
| 186 | priv->mctrlset = 1; |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | /** Sound they keyboard bell. */ |
| 191 | void |
| 192 | dmxCommonKbdBell(DevicePtr pDev, int percent, |
| 193 | int volume, int pitch, int duration) |
| 194 | { |
| 195 | GETPRIVFROMPDEV; |
| 196 | XKeyboardControl kc; |
| 197 | XKeyboardState ks; |
| 198 | unsigned long mask = KBBellPercent | KBBellPitch | KBBellDuration; |
| 199 | |
| 200 | if (!priv->be) |
| 201 | XGetKeyboardControl(priv->display, &ks); |
| 202 | kc.bell_percent = volume; |
| 203 | kc.bell_pitch = pitch; |
| 204 | kc.bell_duration = duration; |
| 205 | XChangeKeyboardControl(priv->display, mask, &kc); |
| 206 | XBell(priv->display, percent); |
| 207 | if (!priv->be) { |
| 208 | kc.bell_percent = ks.bell_percent; |
| 209 | kc.bell_pitch = ks.bell_pitch; |
| 210 | kc.bell_duration = ks.bell_duration; |
| 211 | XChangeKeyboardControl(priv->display, mask, &kc); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | /** Get the keyboard mapping. */ |
| 216 | void |
| 217 | dmxCommonKbdGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) |
| 218 | { |
| 219 | GETPRIVFROMPDEV; |
| 220 | int min_keycode; |
| 221 | int max_keycode; |
| 222 | int map_width; |
| 223 | KeySym *keyboard_mapping; |
| 224 | XModifierKeymap *modifier_mapping; |
| 225 | int i, j; |
| 226 | |
| 227 | /* Compute pKeySyms. Cast |
| 228 | * XGetKeyboardMapping because of |
| 229 | * compiler warning on 64-bit machines. |
| 230 | * We assume pointers to 32-bit and |
| 231 | * 64-bit ints are the same. */ |
| 232 | XDisplayKeycodes(priv->display, &min_keycode, &max_keycode); |
| 233 | keyboard_mapping = (KeySym *) XGetKeyboardMapping(priv->display, |
| 234 | min_keycode, |
| 235 | max_keycode |
| 236 | - min_keycode + 1, |
| 237 | &map_width); |
| 238 | pKeySyms->minKeyCode = min_keycode; |
| 239 | pKeySyms->maxKeyCode = max_keycode; |
| 240 | pKeySyms->mapWidth = map_width; |
| 241 | pKeySyms->map = keyboard_mapping; |
| 242 | |
| 243 | /* Compute pModMap */ |
| 244 | modifier_mapping = XGetModifierMapping(priv->display); |
| 245 | for (i = 0; i < MAP_LENGTH; i++) |
| 246 | pModMap[i] = 0; |
| 247 | for (j = 0; j < 8; j++) { |
| 248 | int max_keypermod = modifier_mapping->max_keypermod; |
| 249 | |
| 250 | for (i = 0; i < max_keypermod; i++) { |
| 251 | CARD8 keycode = |
| 252 | modifier_mapping->modifiermap[j * max_keypermod + i]; |
| 253 | if (keycode) |
| 254 | pModMap[keycode] |= 1 << j; |
| 255 | } |
| 256 | } |
| 257 | XFreeModifiermap(modifier_mapping); |
| 258 | } |
| 259 | |
| 260 | /** Fill in the XKEYBOARD parts of the \a info structure for the |
| 261 | * specified \a pDev. */ |
| 262 | void |
| 263 | dmxCommonKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) |
| 264 | { |
| 265 | GETPRIVFROMPDEV; |
| 266 | GETDMXINPUTFROMPRIV; |
| 267 | char *pt; |
| 268 | |
| 269 | dmxCommonSaveState(priv); |
| 270 | if (priv->xkb) { |
| 271 | #define NAME(x) \ |
| 272 | priv->xkb->names->x ? XGetAtomName(priv->display,priv->xkb->names->x) : NULL |
| 273 | info->names.keycodes = NAME(keycodes); |
| 274 | info->names.types = NAME(types); |
| 275 | info->names.compat = NAME(compat); |
| 276 | info->names.symbols = NAME(symbols); |
| 277 | info->names.geometry = NAME(geometry); |
| 278 | info->freenames = 1; |
| 279 | #undef NAME |
| 280 | dmxLogInput(dmxInput, |
| 281 | "XKEYBOARD: keycodes = %s\n", info->names.keycodes); |
| 282 | dmxLogInput(dmxInput, |
| 283 | "XKEYBOARD: symbols = %s\n", info->names.symbols); |
| 284 | dmxLogInput(dmxInput, |
| 285 | "XKEYBOARD: geometry = %s\n", info->names.geometry); |
| 286 | if ((pt = strchr(info->names.keycodes, '+'))) |
| 287 | *pt = '\0'; |
| 288 | } |
| 289 | dmxCommonRestoreState(priv); |
| 290 | } |
| 291 | |
| 292 | /** Turn \a pDev on (i.e., take input from \a pDev). */ |
| 293 | int |
| 294 | dmxCommonKbdOn(DevicePtr pDev) |
| 295 | { |
| 296 | GETPRIVFROMPDEV; |
| 297 | if (priv->be) |
| 298 | dmxCommonSaveState(priv); |
| 299 | priv->eventMask |= DMX_KEYBOARD_EVENT_MASK; |
| 300 | XSelectInput(priv->display, priv->window, priv->eventMask); |
| 301 | if (priv->be) |
| 302 | XSetInputFocus(priv->display, priv->window, RevertToPointerRoot, |
| 303 | CurrentTime); |
| 304 | return -1; |
| 305 | } |
| 306 | |
| 307 | /** Turn \a pDev off. */ |
| 308 | void |
| 309 | dmxCommonKbdOff(DevicePtr pDev) |
| 310 | { |
| 311 | GETPRIVFROMPDEV; |
| 312 | priv->eventMask &= ~DMX_KEYBOARD_EVENT_MASK; |
| 313 | XSelectInput(priv->display, priv->window, priv->eventMask); |
| 314 | dmxCommonRestoreState(priv); |
| 315 | } |
| 316 | |
| 317 | /** Turn \a pDev on (i.e., take input from \a pDev). */ |
| 318 | int |
| 319 | dmxCommonOthOn(DevicePtr pDev) |
| 320 | { |
| 321 | GETPRIVFROMPDEV; |
| 322 | GETDMXINPUTFROMPRIV; |
| 323 | XEventClass event_list[DMX_MAX_XINPUT_EVENT_TYPES]; |
| 324 | int event_type[DMX_MAX_XINPUT_EVENT_TYPES]; |
| 325 | int count = 0; |
| 326 | |
| 327 | #define ADD(type) \ |
| 328 | if (count < DMX_MAX_XINPUT_EVENT_TYPES) { \ |
| 329 | type(priv->xi, event_type[count], event_list[count]); \ |
| 330 | if (event_type[count]) { \ |
| 331 | dmxMapInsert(dmxLocal, event_type[count], XI_##type); \ |
| 332 | ++count; \ |
| 333 | } \ |
| 334 | } else { \ |
| 335 | dmxLog(dmxWarning, "More than %d event types for %s\n", \ |
| 336 | DMX_MAX_XINPUT_EVENT_TYPES, dmxInput->name); \ |
| 337 | } |
| 338 | |
| 339 | if (!(priv->xi = XOpenDevice(priv->display, dmxLocal->deviceId))) { |
| 340 | dmxLog(dmxWarning, "Cannot open %s device (id=%d) on %s\n", |
| 341 | dmxLocal->deviceName ? dmxLocal->deviceName : "(unknown)", |
| 342 | dmxLocal->deviceId, dmxInput->name); |
| 343 | return -1; |
| 344 | } |
| 345 | ADD(DeviceKeyPress); |
| 346 | ADD(DeviceKeyRelease); |
| 347 | ADD(DeviceButtonPress); |
| 348 | ADD(DeviceButtonRelease); |
| 349 | ADD(DeviceMotionNotify); |
| 350 | ADD(DeviceFocusIn); |
| 351 | ADD(DeviceFocusOut); |
| 352 | ADD(ProximityIn); |
| 353 | ADD(ProximityOut); |
| 354 | ADD(DeviceStateNotify); |
| 355 | ADD(DeviceMappingNotify); |
| 356 | ADD(ChangeDeviceNotify); |
| 357 | XSelectExtensionEvent(priv->display, priv->window, event_list, count); |
| 358 | |
| 359 | return -1; |
| 360 | } |
| 361 | |
| 362 | /** Turn \a pDev off. */ |
| 363 | void |
| 364 | dmxCommonOthOff(DevicePtr pDev) |
| 365 | { |
| 366 | GETPRIVFROMPDEV; |
| 367 | |
| 368 | if (priv->xi) |
| 369 | XCloseDevice(priv->display, priv->xi); |
| 370 | priv->xi = NULL; |
| 371 | } |
| 372 | |
| 373 | /** Fill the \a info structure with information needed to initialize \a |
| 374 | * pDev. */ |
| 375 | void |
| 376 | dmxCommonOthGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) |
| 377 | { |
| 378 | GETPRIVFROMPDEV; |
| 379 | GETDMXINPUTFROMPRIV; |
| 380 | XExtensionVersion *ext; |
| 381 | XDeviceInfo *devices; |
| 382 | Display *display = priv->display; |
| 383 | int num; |
| 384 | int i, j, k; |
| 385 | XextErrorHandler handler; |
| 386 | |
| 387 | if (!display && !(display = XOpenDisplay(dmxInput->name))) |
| 388 | return; |
| 389 | |
| 390 | /* Print out information about the XInput Extension. */ |
| 391 | handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler); |
| 392 | ext = XGetExtensionVersion(display, INAME); |
| 393 | XSetExtensionErrorHandler(handler); |
| 394 | |
| 395 | if (ext && ext != (XExtensionVersion *) NoSuchExtension) { |
| 396 | XFree(ext); |
| 397 | devices = XListInputDevices(display, &num); |
| 398 | for (i = 0; i < num; i++) { |
| 399 | if (devices[i].id == (XID) dmxLocal->deviceId) { |
| 400 | XAnyClassPtr any; |
| 401 | XKeyInfoPtr ki; |
| 402 | XButtonInfoPtr bi; |
| 403 | XValuatorInfoPtr vi; |
| 404 | |
| 405 | for (j = 0, any = devices[i].inputclassinfo; |
| 406 | j < devices[i].num_classes; |
| 407 | any = (XAnyClassPtr) ((char *) any + any->length), j++) { |
| 408 | switch (any->class) { |
| 409 | case KeyClass: |
| 410 | ki = (XKeyInfoPtr) any; |
| 411 | info->keyboard = 1; |
| 412 | info->keyClass = 1; |
| 413 | info->keySyms.minKeyCode = ki->min_keycode; |
| 414 | info->keySyms.maxKeyCode = ki->max_keycode; |
| 415 | info->kbdFeedbackClass = 1; |
| 416 | break; |
| 417 | case ButtonClass: |
| 418 | bi = (XButtonInfoPtr) any; |
| 419 | info->buttonClass = 1; |
| 420 | info->numButtons = bi->num_buttons; |
| 421 | info->ptrFeedbackClass = 1; |
| 422 | break; |
| 423 | case ValuatorClass: |
| 424 | /* This assume all axes are either |
| 425 | * Absolute or Relative. */ |
| 426 | vi = (XValuatorInfoPtr) any; |
| 427 | info->valuatorClass = 1; |
| 428 | if (vi->mode == Absolute) |
| 429 | info->numAbsAxes = vi->num_axes; |
| 430 | else |
| 431 | info->numRelAxes = vi->num_axes; |
| 432 | for (k = 0; k < vi->num_axes; k++) { |
| 433 | info->res[k] = vi->axes[k].resolution; |
| 434 | info->minres[k] = vi->axes[k].resolution; |
| 435 | info->maxres[k] = vi->axes[k].resolution; |
| 436 | info->minval[k] = vi->axes[k].min_value; |
| 437 | info->maxval[k] = vi->axes[k].max_value; |
| 438 | } |
| 439 | break; |
| 440 | case FeedbackClass: |
| 441 | /* Only keyboard and pointer feedback |
| 442 | * are handled at this time. */ |
| 443 | break; |
| 444 | case ProximityClass: |
| 445 | info->proximityClass = 1; |
| 446 | break; |
| 447 | case FocusClass: |
| 448 | info->focusClass = 1; |
| 449 | break; |
| 450 | case OtherClass: |
| 451 | break; |
| 452 | } |
| 453 | } |
| 454 | } |
| 455 | } |
| 456 | XFreeDeviceList(devices); |
| 457 | } |
| 458 | if (display != priv->display) |
| 459 | XCloseDisplay(display); |
| 460 | } |
| 461 | |
| 462 | /** Obtain the mouse button mapping. */ |
| 463 | void |
| 464 | dmxCommonMouGetMap(DevicePtr pDev, unsigned char *map, int *nButtons) |
| 465 | { |
| 466 | GETPRIVFROMPDEV; |
| 467 | int i; |
| 468 | |
| 469 | *nButtons = XGetPointerMapping(priv->display, map, DMX_MAX_BUTTONS); |
| 470 | for (i = 0; i <= *nButtons; i++) |
| 471 | map[i] = i; |
| 472 | } |
| 473 | |
| 474 | static void * |
| 475 | dmxCommonXSelect(DMXScreenInfo * dmxScreen, void *closure) |
| 476 | { |
| 477 | myPrivate *priv = closure; |
| 478 | |
| 479 | XSelectInput(dmxScreen->beDisplay, dmxScreen->scrnWin, priv->eventMask); |
| 480 | return NULL; |
| 481 | } |
| 482 | |
| 483 | static void * |
| 484 | dmxCommonAddEnabledDevice(DMXScreenInfo * dmxScreen, void *closure) |
| 485 | { |
| 486 | AddEnabledDevice(XConnectionNumber(dmxScreen->beDisplay)); |
| 487 | return NULL; |
| 488 | } |
| 489 | |
| 490 | static void * |
| 491 | dmxCommonRemoveEnabledDevice(DMXScreenInfo * dmxScreen, void *closure) |
| 492 | { |
| 493 | RemoveEnabledDevice(XConnectionNumber(dmxScreen->beDisplay)); |
| 494 | return NULL; |
| 495 | } |
| 496 | |
| 497 | /** Turn \a pDev on (i.e., take input from \a pDev). */ |
| 498 | int |
| 499 | dmxCommonMouOn(DevicePtr pDev) |
| 500 | { |
| 501 | GETPRIVFROMPDEV; |
| 502 | GETDMXINPUTFROMPRIV; |
| 503 | |
| 504 | priv->eventMask |= DMX_POINTER_EVENT_MASK; |
| 505 | if (!priv->be) { |
| 506 | XSelectInput(priv->display, priv->window, priv->eventMask); |
| 507 | AddEnabledDevice(XConnectionNumber(priv->display)); |
| 508 | } |
| 509 | else { |
| 510 | dmxPropertyIterate(priv->be, dmxCommonXSelect, priv); |
| 511 | dmxPropertyIterate(priv->be, dmxCommonAddEnabledDevice, dmxInput); |
| 512 | } |
| 513 | |
| 514 | return -1; |
| 515 | } |
| 516 | |
| 517 | /** Turn \a pDev off. */ |
| 518 | void |
| 519 | dmxCommonMouOff(DevicePtr pDev) |
| 520 | { |
| 521 | GETPRIVFROMPDEV; |
| 522 | GETDMXINPUTFROMPRIV; |
| 523 | |
| 524 | priv->eventMask &= ~DMX_POINTER_EVENT_MASK; |
| 525 | if (!priv->be) { |
| 526 | RemoveEnabledDevice(XConnectionNumber(priv->display)); |
| 527 | XSelectInput(priv->display, priv->window, priv->eventMask); |
| 528 | } |
| 529 | else { |
| 530 | dmxPropertyIterate(priv->be, dmxCommonRemoveEnabledDevice, dmxInput); |
| 531 | dmxPropertyIterate(priv->be, dmxCommonXSelect, priv); |
| 532 | } |
| 533 | } |
| 534 | |
| 535 | /** Given the global coordinates \a x and \a y, determine the screen |
| 536 | * with the lowest number on which those coordinates lie. If they are |
| 537 | * not on any screen, return -1. The number returned is an index into |
| 538 | * \a dmxScreenInfo and is between -1 and \a dmxNumScreens - 1, |
| 539 | * inclusive. */ |
| 540 | int |
| 541 | dmxFindPointerScreen(int x, int y) |
| 542 | { |
| 543 | int i; |
| 544 | |
| 545 | for (i = 0; i < dmxNumScreens; i++) { |
| 546 | ScreenPtr pScreen = screenInfo.screens[i]; |
| 547 | |
| 548 | if (x >= pScreen->x && x < pScreen->x + pScreen->width && |
| 549 | y >= pScreen->y && y < pScreen->y + pScreen->height) |
| 550 | return i; |
| 551 | } |
| 552 | return -1; |
| 553 | } |
| 554 | |
| 555 | /** Returns a pointer to the private area for the device that comes just |
| 556 | * prior to \a pDevice in the current \a dmxInput device list. This is |
| 557 | * used as the private area for the current device in some situations |
| 558 | * (e.g., when a keyboard and mouse form a pair that should share the |
| 559 | * same private area). If the requested private area cannot be located, |
| 560 | * then NULL is returned. */ |
| 561 | pointer |
| 562 | dmxCommonCopyPrivate(DeviceIntPtr pDevice) |
| 563 | { |
| 564 | GETDMXLOCALFROMPDEVICE; |
| 565 | DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; |
| 566 | int i; |
| 567 | |
| 568 | for (i = 0; i < dmxInput->numDevs; i++) |
| 569 | if (dmxInput->devs[i] == dmxLocal && i) |
| 570 | return dmxInput->devs[i - 1]->private; |
| 571 | return NULL; |
| 572 | } |
| 573 | |
| 574 | /** This routine saves and resets some important state for the backend |
| 575 | * and console device drivers: |
| 576 | * - the modifier map is saved and set to 0 (so DMX controls the LEDs) |
| 577 | * - the key click, bell, led, and repeat masks are saved and set to the |
| 578 | * values that DMX claims to be using |
| 579 | * |
| 580 | * This routine and #dmxCommonRestoreState are used when the pointer |
| 581 | * enters and leaves the console window, or when the backend window is |
| 582 | * active or not active (for a full-screen window, this only happens at |
| 583 | * server startup and server shutdown). |
| 584 | */ |
| 585 | void |
| 586 | dmxCommonSaveState(pointer private) |
| 587 | { |
| 588 | GETPRIVFROMPRIVATE; |
| 589 | XKeyboardState ks; |
| 590 | unsigned long i; |
| 591 | XModifierKeymap *modmap; |
| 592 | |
| 593 | if (dmxInput->console) |
| 594 | priv = dmxInput->devs[0]->private; |
| 595 | if (!priv->display || priv->stateSaved) |
| 596 | return; |
| 597 | DMXDBG0("dmxCommonSaveState\n"); |
| 598 | if (dmxUseXKB && (priv->xkb = XkbAllocKeyboard())) { |
| 599 | if (XkbGetIndicatorMap(priv->display, XkbAllIndicatorsMask, priv->xkb) |
| 600 | || XkbGetNames(priv->display, XkbAllNamesMask, priv->xkb)) { |
| 601 | dmxLogInput(dmxInput, "Could not get XKB information\n"); |
| 602 | XkbFreeKeyboard(priv->xkb, 0, True); |
| 603 | priv->xkb = NULL; |
| 604 | } |
| 605 | else { |
| 606 | if (priv->xkb->indicators) { |
| 607 | priv->savedIndicators = *priv->xkb->indicators; |
| 608 | for (i = 0; i < XkbNumIndicators; i++) |
| 609 | if (priv->xkb->indicators->phys_indicators & (1 << i)) { |
| 610 | priv->xkb->indicators->maps[i].flags |
| 611 | = XkbIM_NoAutomatic; |
| 612 | } |
| 613 | XkbSetIndicatorMap(priv->display, ~0, priv->xkb); |
| 614 | } |
| 615 | } |
| 616 | } |
| 617 | |
| 618 | XGetKeyboardControl(priv->display, &ks); |
| 619 | priv->savedKctrl.click = ks.key_click_percent; |
| 620 | priv->savedKctrl.bell = ks.bell_percent; |
| 621 | priv->savedKctrl.bell_pitch = ks.bell_pitch; |
| 622 | priv->savedKctrl.bell_duration = ks.bell_duration; |
| 623 | priv->savedKctrl.leds = ks.led_mask; |
| 624 | priv->savedKctrl.autoRepeat = ks.global_auto_repeat; |
| 625 | for (i = 0; i < 32; i++) |
| 626 | priv->savedKctrl.autoRepeats[i] = ks.auto_repeats[i]; |
| 627 | |
| 628 | dmxCommonKbdSetCtrl(priv->display, &priv->savedKctrl, |
| 629 | &priv->dmxLocal->kctrl); |
| 630 | |
| 631 | priv->savedModMap = XGetModifierMapping(priv->display); |
| 632 | |
| 633 | modmap = XNewModifiermap(0); |
| 634 | XSetModifierMapping(priv->display, modmap); |
| 635 | if (dmxInput->scrnIdx != -1) |
| 636 | dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE); |
| 637 | XFreeModifiermap(modmap); |
| 638 | |
| 639 | priv->stateSaved = 1; |
| 640 | } |
| 641 | |
| 642 | /** This routine restores all the information saved by #dmxCommonSaveState. */ |
| 643 | void |
| 644 | dmxCommonRestoreState(pointer private) |
| 645 | { |
| 646 | GETPRIVFROMPRIVATE; |
| 647 | int retcode = -1; |
| 648 | CARD32 start; |
| 649 | |
| 650 | if (dmxInput->console) |
| 651 | priv = dmxInput->devs[0]->private; |
| 652 | if (!priv->stateSaved) |
| 653 | return; |
| 654 | priv->stateSaved = 0; |
| 655 | |
| 656 | DMXDBG0("dmxCommonRestoreState\n"); |
| 657 | if (priv->xkb) { |
| 658 | *priv->xkb->indicators = priv->savedIndicators; |
| 659 | XkbSetIndicatorMap(priv->display, ~0, priv->xkb); |
| 660 | XkbFreeKeyboard(priv->xkb, 0, True); |
| 661 | priv->xkb = 0; |
| 662 | } |
| 663 | |
| 664 | for (start = GetTimeInMillis(); GetTimeInMillis() - start < 5000;) { |
| 665 | CARD32 tmp; |
| 666 | |
| 667 | retcode = XSetModifierMapping(priv->display, priv->savedModMap); |
| 668 | if (retcode == MappingSuccess) |
| 669 | break; |
| 670 | if (retcode == MappingBusy) |
| 671 | dmxLogInput(dmxInput, "Keyboard busy, waiting\n"); |
| 672 | else |
| 673 | dmxLogInput(dmxInput, "Keyboard error, waiting\n"); |
| 674 | |
| 675 | /* Don't generate X11 protocol for a bit */ |
| 676 | for (tmp = GetTimeInMillis(); GetTimeInMillis() - tmp < 250;) { |
| 677 | usleep(250); /* This ends up sleeping only until |
| 678 | * the next key press generates an |
| 679 | * interruption. We make the delay |
| 680 | * relatively short in case the user |
| 681 | * pressed they keys quickly. */ |
| 682 | } |
| 683 | |
| 684 | } |
| 685 | if (retcode != MappingSuccess) |
| 686 | dmxLog(dmxWarning, "Unable to restore keyboard modifier state!\n"); |
| 687 | |
| 688 | XFreeModifiermap(priv->savedModMap); |
| 689 | priv->savedModMap = NULL; |
| 690 | |
| 691 | dmxCommonKbdSetCtrl(priv->display, NULL, &priv->savedKctrl); |
| 692 | priv->kctrlset = 0; /* Invalidate copy */ |
| 693 | } |