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 * This file provides generic input support. Functions here set up 36 * input and lead to the calling of low-level device drivers for 37 * input. */ 38 39#ifdef HAVE_DMX_CONFIG_H 40#include <dmx-config.h> 41#endif 42 43#define DMX_WINDOW_DEBUG 0 44 45#include "dmxinputinit.h" 46#include "dmxextension.h" /* For dmxInputCount */ 47 48#include "dmxdummy.h" 49#include "dmxbackend.h" 50#include "dmxconsole.h" 51#include "dmxcommon.h" 52#include "dmxevents.h" 53#include "dmxmotion.h" 54#include "dmxprop.h" 55#include "config/dmxconfig.h" 56#include "dmxcursor.h" 57 58#include "lnx-keyboard.h" 59#include "lnx-ms.h" 60#include "lnx-ps2.h" 61#include "usb-keyboard.h" 62#include "usb-mouse.h" 63#include "usb-other.h" 64#include "usb-common.h" 65 66#include "dmxsigio.h" 67#include "dmxarg.h" 68 69#include "inputstr.h" 70#include "input.h" 71#include "mipointer.h" 72#include "windowstr.h" 73#include "mi.h" 74#include "xkbsrv.h" 75 76#include <X11/extensions/XI.h> 77#include <X11/extensions/XIproto.h> 78#include "exevents.h" 79#include "extinit.h" 80 81DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard; 82 83static DMXLocalInputInfoRec DMXDummyMou = { 84 "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, 85 NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo 86}; 87 88static DMXLocalInputInfoRec DMXDummyKbd = { 89 "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, 90 NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo 91}; 92 93static DMXLocalInputInfoRec DMXBackendMou = { 94 "backend-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_BACKEND, 2, 95 dmxBackendCreatePrivate, dmxBackendDestroyPrivate, 96 dmxBackendInit, NULL, dmxBackendLateReInit, dmxBackendMouGetInfo, 97 dmxCommonMouOn, dmxCommonMouOff, dmxBackendUpdatePosition, 98 NULL, NULL, NULL, 99 dmxBackendCollectEvents, dmxBackendProcessInput, dmxBackendFunctions, NULL, 100 dmxCommonMouCtrl 101}; 102 103static DMXLocalInputInfoRec DMXBackendKbd = { 104 "backend-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_BACKEND, 105 1, /* With backend-mou or console-mou */ 106 dmxCommonCopyPrivate, NULL, 107 dmxBackendInit, NULL, NULL, dmxBackendKbdGetInfo, 108 dmxCommonKbdOn, dmxCommonKbdOff, NULL, 109 NULL, NULL, NULL, 110 NULL, NULL, NULL, NULL, 111 NULL, dmxCommonKbdCtrl, dmxCommonKbdBell 112}; 113 114static DMXLocalInputInfoRec DMXConsoleMou = { 115 "console-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_CONSOLE, 2, 116 dmxConsoleCreatePrivate, dmxConsoleDestroyPrivate, 117 dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleMouGetInfo, 118 dmxCommonMouOn, dmxCommonMouOff, dmxConsoleUpdatePosition, 119 NULL, NULL, NULL, 120 dmxConsoleCollectEvents, NULL, dmxConsoleFunctions, dmxConsoleUpdateInfo, 121 dmxCommonMouCtrl 122}; 123 124static DMXLocalInputInfoRec DMXConsoleKbd = { 125 "console-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_CONSOLE, 126 1, /* With backend-mou or console-mou */ 127 dmxCommonCopyPrivate, NULL, 128 dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleKbdGetInfo, 129 dmxCommonKbdOn, dmxCommonKbdOff, NULL, 130 NULL, NULL, NULL, 131 NULL, NULL, NULL, NULL, 132 NULL, dmxCommonKbdCtrl, dmxCommonKbdBell 133}; 134 135static DMXLocalInputInfoRec DMXLocalDevices[] = { 136 /* Dummy drivers that can compile on any OS */ 137#ifdef __linux__ 138 /* Linux-specific drivers */ 139 { 140 "kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, 141 kbdLinuxCreatePrivate, kbdLinuxDestroyPrivate, 142 kbdLinuxInit, NULL, NULL, kbdLinuxGetInfo, 143 kbdLinuxOn, kbdLinuxOff, NULL, 144 kbdLinuxVTPreSwitch, kbdLinuxVTPostSwitch, kbdLinuxVTSwitch, 145 kbdLinuxRead, NULL, NULL, NULL, 146 NULL, kbdLinuxCtrl, kbdLinuxBell 147 }, 148 { 149 "ms", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, 150 msLinuxCreatePrivate, msLinuxDestroyPrivate, 151 msLinuxInit, NULL, NULL, msLinuxGetInfo, 152 msLinuxOn, msLinuxOff, NULL, 153 msLinuxVTPreSwitch, msLinuxVTPostSwitch, NULL, 154 msLinuxRead 155 }, 156 { 157 "ps2", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, 158 ps2LinuxCreatePrivate, ps2LinuxDestroyPrivate, 159 ps2LinuxInit, NULL, NULL, ps2LinuxGetInfo, 160 ps2LinuxOn, ps2LinuxOff, NULL, 161 ps2LinuxVTPreSwitch, ps2LinuxVTPostSwitch, NULL, 162 ps2LinuxRead 163 }, 164#endif 165#ifdef __linux__ 166 /* USB drivers, currently only for 167 Linux, but relatively easy to port to 168 other OSs */ 169 { 170 "usb-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, 171 usbCreatePrivate, usbDestroyPrivate, 172 kbdUSBInit, NULL, NULL, kbdUSBGetInfo, 173 kbdUSBOn, usbOff, NULL, 174 NULL, NULL, NULL, 175 kbdUSBRead, NULL, NULL, NULL, 176 NULL, kbdUSBCtrl 177 }, 178 { 179 "usb-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, 180 usbCreatePrivate, usbDestroyPrivate, 181 mouUSBInit, NULL, NULL, mouUSBGetInfo, 182 mouUSBOn, usbOff, NULL, 183 NULL, NULL, NULL, 184 mouUSBRead 185 }, 186 { 187 "usb-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_LOCAL, 1, 188 usbCreatePrivate, usbDestroyPrivate, 189 othUSBInit, NULL, NULL, othUSBGetInfo, 190 othUSBOn, usbOff, NULL, 191 NULL, NULL, NULL, 192 othUSBRead 193 }, 194#endif 195 { 196 "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, 197 NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo 198 }, 199 { 200 "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, 201 NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo 202 }, 203 { NULL } /* Must be last */ 204}; 205 206 207#if 11 /*BP*/ 208void 209DDXRingBell(int volume, int pitch, int duration) 210{ 211 /* NO-OP */ 212} 213 214/* taken from kdrive/src/kinput.c: */ 215static void 216dmxKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl) 217{ 218#if 0 219 KdKeyboardInfo *ki; 220 221 for (ki = kdKeyboards; ki; ki = ki->next) { 222 if (ki->dixdev && ki->dixdev->id == pDevice->id) 223 break; 224 } 225 226 if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver) 227 return; 228 229 KdSetLeds(ki, ctrl->leds); 230 ki->bellPitch = ctrl->bell_pitch; 231 ki->bellDuration = ctrl->bell_duration; 232#endif 233} 234 235/* taken from kdrive/src/kinput.c: */ 236static void 237dmxBell(int volume, DeviceIntPtr pDev, pointer arg, int something) 238{ 239#if 0 240 KeybdCtrl *ctrl = arg; 241 KdKeyboardInfo *ki = NULL; 242 243 for (ki = kdKeyboards; ki; ki = ki->next) { 244 if (ki->dixdev && ki->dixdev->id == pDev->id) 245 break; 246 } 247 248 if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver) 249 return; 250 251 KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration); 252#endif 253} 254 255#endif /*BP*/ 256 257static void _dmxChangePointerControl(DMXLocalInputInfoPtr dmxLocal, 258 PtrCtrl *ctrl) 259{ 260 if (!dmxLocal) return; 261 dmxLocal->mctrl = *ctrl; 262 if (dmxLocal->mCtrl) dmxLocal->mCtrl(&dmxLocal->pDevice->public, ctrl); 263} 264 265/** Change the pointer control information for the \a pDevice. If the 266 * device sends core events, then also change the control information 267 * for all of the pointer devices that send core events. */ 268void dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl *ctrl) 269{ 270 GETDMXLOCALFROMPDEVICE; 271 int i, j; 272 273 if (dmxLocal->sendsCore) { /* Do for all core devices */ 274 for (i = 0; i < dmxNumInputs; i++) { 275 DMXInputInfo *dmxInput = &dmxInputs[i]; 276 if (dmxInput->detached) continue; 277 for (j = 0; j < dmxInput->numDevs; j++) 278 if (dmxInput->devs[j]->sendsCore) 279 _dmxChangePointerControl(dmxInput->devs[j], ctrl); 280 } 281 } else { /* Do for this device only */ 282 _dmxChangePointerControl(dmxLocal, ctrl); 283 } 284} 285 286static void _dmxKeyboardKbdCtrlProc(DMXLocalInputInfoPtr dmxLocal, 287 KeybdCtrl *ctrl) 288{ 289 dmxLocal->kctrl = *ctrl; 290 if (dmxLocal->kCtrl) { 291 dmxLocal->kCtrl(&dmxLocal->pDevice->public, ctrl); 292 if (dmxLocal->pDevice->kbdfeed) { 293 XkbEventCauseRec cause; 294 XkbSetCauseUnknown(&cause); 295 /* Generate XKB events, as necessary */ 296 XkbUpdateIndicators(dmxLocal->pDevice, XkbAllIndicatorsMask, False, 297 NULL, &cause); 298 } 299 } 300} 301 302 303/** Change the keyboard control information for the \a pDevice. If the 304 * device sends core events, then also change the control information 305 * for all of the keyboard devices that send core events. */ 306void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl) 307{ 308 GETDMXLOCALFROMPDEVICE; 309 int i, j; 310 311 if (dmxLocal->sendsCore) { /* Do for all core devices */ 312 for (i = 0; i < dmxNumInputs; i++) { 313 DMXInputInfo *dmxInput = &dmxInputs[i]; 314 if (dmxInput->detached) continue; 315 for (j = 0; j < dmxInput->numDevs; j++) 316 if (dmxInput->devs[j]->sendsCore) 317 _dmxKeyboardKbdCtrlProc(dmxInput->devs[j], ctrl); 318 } 319 } else { /* Do for this device only */ 320 _dmxKeyboardKbdCtrlProc(dmxLocal, ctrl); 321 } 322} 323 324static void _dmxKeyboardBellProc(DMXLocalInputInfoPtr dmxLocal, int percent) 325{ 326 if (dmxLocal->kBell) dmxLocal->kBell(&dmxLocal->pDevice->public, 327 percent, 328 dmxLocal->kctrl.bell, 329 dmxLocal->kctrl.bell_pitch, 330 dmxLocal->kctrl.bell_duration); 331} 332 333/** Sound the bell on the device. If the device send core events, then 334 * sound the bell on all of the devices that send core events. */ 335void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice, 336 pointer ctrl, int unknown) 337{ 338 GETDMXLOCALFROMPDEVICE; 339 int i, j; 340 341 if (dmxLocal->sendsCore) { /* Do for all core devices */ 342 for (i = 0; i < dmxNumInputs; i++) { 343 DMXInputInfo *dmxInput = &dmxInputs[i]; 344 if (dmxInput->detached) continue; 345 for (j = 0; j < dmxInput->numDevs; j++) 346 if (dmxInput->devs[j]->sendsCore) 347 _dmxKeyboardBellProc(dmxInput->devs[j], percent); 348 } 349 } else { /* Do for this device only */ 350 _dmxKeyboardBellProc(dmxLocal, percent); 351 } 352} 353 354static void dmxKeyboardFreeNames(XkbComponentNamesPtr names) 355{ 356 if (names->keycodes) XFree(names->keycodes); 357 if (names->types) XFree(names->types); 358 if (names->compat) XFree(names->compat); 359 if (names->symbols) XFree(names->symbols); 360 if (names->geometry) XFree(names->geometry); 361} 362 363 364static int dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo *info) 365{ 366 GETDMXINPUTFROMPDEVICE; 367 XkbRMLVOSet rmlvo; 368 369 rmlvo.rules = dmxConfigGetXkbRules(); 370 rmlvo.model = dmxConfigGetXkbModel(); 371 rmlvo.layout = dmxConfigGetXkbLayout(); 372 rmlvo.variant = dmxConfigGetXkbVariant(); 373 rmlvo.options = dmxConfigGetXkbOptions(); 374 375 XkbSetRulesDflts(&rmlvo); 376 if (!info->force && (dmxInput->keycodes 377 || dmxInput->symbols 378 || dmxInput->geometry)) { 379 if (info->freenames) dmxKeyboardFreeNames(&info->names); 380 info->freenames = 0; 381 info->names.keycodes = dmxInput->keycodes; 382 info->names.types = NULL; 383 info->names.compat = NULL; 384 info->names.symbols = dmxInput->symbols; 385 info->names.geometry = dmxInput->geometry; 386 387 dmxLogInput(dmxInput, "XKEYBOARD: From command line: %s", 388 info->names.keycodes); 389 if (info->names.symbols && *info->names.symbols) 390 dmxLogInputCont(dmxInput, " %s", info->names.symbols); 391 if (info->names.geometry && *info->names.geometry) 392 dmxLogInputCont(dmxInput, " %s", info->names.geometry); 393 dmxLogInputCont(dmxInput, "\n"); 394 } else if (info->names.keycodes) { 395 dmxLogInput(dmxInput, "XKEYBOARD: From device: %s", 396 info->names.keycodes); 397 if (info->names.symbols && *info->names.symbols) 398 dmxLogInputCont(dmxInput, " %s", info->names.symbols); 399 if (info->names.geometry && *info->names.geometry) 400 dmxLogInputCont(dmxInput, " %s", info->names.geometry); 401 dmxLogInputCont(dmxInput, "\n"); 402 } else { 403 dmxLogInput(dmxInput, "XKEYBOARD: Defaults: %s %s %s %s %s\n", 404 dmxConfigGetXkbRules(), 405 dmxConfigGetXkbLayout(), 406 dmxConfigGetXkbModel(), 407 dmxConfigGetXkbVariant() 408 ? dmxConfigGetXkbVariant() : "", 409 dmxConfigGetXkbOptions() 410 ? dmxConfigGetXkbOptions() : ""); 411 } 412 InitKeyboardDeviceStruct(pDevice, &rmlvo, 413 dmxKeyboardBellProc, 414 dmxKeyboardKbdCtrlProc); 415 416 if (info->freenames) dmxKeyboardFreeNames(&info->names); 417 418 return Success; 419} 420 421 422static int dmxDeviceOnOff(DeviceIntPtr pDevice, int what) 423{ 424 GETDMXINPUTFROMPDEVICE; 425 int fd; 426 DMXLocalInitInfo info; 427 int i; 428 Atom btn_labels[MAX_BUTTONS] = {0}; /* FIXME */ 429 Atom axis_labels[MAX_VALUATORS] = {0}; /* FIXME */ 430 431 if (dmxInput->detached) return Success; 432 433 memset(&info, 0, sizeof(info)); 434 switch (what) { 435 case DEVICE_INIT: 436 if (dmxLocal->init) 437 dmxLocal->init(pDev); 438 if (dmxLocal->get_info) 439 dmxLocal->get_info(pDev, &info); 440 if (info.keyboard) { /* XKEYBOARD makes this a special case */ 441 dmxKeyboardOn(pDevice, &info); 442 break; 443 } 444 if (info.keyClass) { 445 XkbRMLVOSet rmlvo; 446 447 rmlvo.rules = dmxConfigGetXkbRules(); 448 rmlvo.model = dmxConfigGetXkbModel(); 449 rmlvo.layout = dmxConfigGetXkbLayout(); 450 rmlvo.variant = dmxConfigGetXkbVariant(); 451 rmlvo.options = dmxConfigGetXkbOptions(); 452 453 InitKeyboardDeviceStruct(pDevice, 454 &rmlvo, 455 dmxBell, dmxKbdCtrl); 456 } 457 if (info.buttonClass) { 458 InitButtonClassDeviceStruct(pDevice, info.numButtons, 459 btn_labels, info.map); 460 } 461 if (info.valuatorClass) { 462 if (info.numRelAxes && dmxLocal->sendsCore) { 463 InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, 464 axis_labels, 465 GetMaximumEventsNum(), 466 Relative); 467 for (i = 0; i < info.numRelAxes; i++) 468 InitValuatorAxisStruct(pDevice, i, axis_labels[i], 469 info.minval[i], info.maxval[i], 470 info.res[i], 471 info.minres[i], info.maxres[i], 472 Relative); 473 } else if (info.numRelAxes) { 474 InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, 475 axis_labels, 476 dmxPointerGetMotionBufferSize(), 477 Relative); 478 for (i = 0; i < info.numRelAxes; i++) 479 InitValuatorAxisStruct(pDevice, i, axis_labels[i], 480 info.minval[i], 481 info.maxval[i], info.res[i], 482 info.minres[i], info.maxres[i], 483 Relative); 484 } else if (info.numAbsAxes) { 485 InitValuatorClassDeviceStruct(pDevice, info.numAbsAxes, 486 axis_labels, 487 dmxPointerGetMotionBufferSize(), 488 Absolute); 489 for (i = 0; i < info.numAbsAxes; i++) 490 InitValuatorAxisStruct(pDevice, i, 491 axis_labels[i], 492 info.minval[i], info.maxval[i], 493 info.res[i], info.minres[i], 494 info.maxres[i], Absolute); 495 } 496 } 497 if (info.focusClass) InitFocusClassDeviceStruct(pDevice); 498 if (info.proximityClass) InitProximityClassDeviceStruct(pDevice); 499 if (info.ptrFeedbackClass) 500 InitPtrFeedbackClassDeviceStruct(pDevice, dmxChangePointerControl); 501 if (info.intFeedbackClass || info.strFeedbackClass) 502 dmxLog(dmxWarning, 503 "Integer and string feedback not supported for %s\n", 504 pDevice->name); 505 if (!info.keyboard && (info.ledFeedbackClass || info.belFeedbackClass)) 506 dmxLog(dmxWarning, 507 "Led and bel feedback not supported for non-keyboard %s\n", 508 pDevice->name); 509 break; 510 case DEVICE_ON: 511 if (!pDev->on) { 512 if (dmxLocal->on && (fd = dmxLocal->on(pDev)) >= 0) 513 dmxSigioRegister(dmxInput, fd); 514 pDev->on = TRUE; 515 } 516 break; 517 case DEVICE_OFF: 518 case DEVICE_CLOSE: 519 /* This can get called twice consecutively: once for a 520 * detached screen (DEVICE_OFF), and then again at server 521 * generation time (DEVICE_CLOSE). */ 522 if (pDev->on) { 523 dmxSigioUnregister(dmxInput); 524 if (dmxLocal->off) dmxLocal->off(pDev); 525 pDev->on = FALSE; 526 } 527 break; 528 } 529 if (info.keySyms.map && info.freemap) { 530 XFree(info.keySyms.map); 531 info.keySyms.map = NULL; 532 } 533 if (info.xkb) XkbFreeKeyboard(info.xkb, 0, True); 534 return Success; 535} 536 537static void dmxProcessInputEvents(DMXInputInfo *dmxInput) 538{ 539 int i; 540 541 mieqProcessInputEvents(); 542#if 00 /*BP*/ 543 miPointerUpdate(); 544#endif 545 if (dmxInput->detached) 546 return; 547 for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) 548 if (dmxInput->devs[i]->process_input) { 549#if 11 /*BP*/ 550 miPointerUpdateSprite(dmxInput->devs[i]->pDevice); 551#endif 552 dmxInput->devs[i]->process_input(dmxInput->devs[i]->private); 553 } 554 555#if 11 /*BP*/ 556 mieqProcessInputEvents(); 557#endif 558} 559 560static void dmxUpdateWindowInformation(DMXInputInfo *dmxInput, 561 DMXUpdateType type, 562 WindowPtr pWindow) 563{ 564 int i; 565 566#ifdef PANORAMIX 567 if (!noPanoramiXExtension && pWindow && pWindow->parent != screenInfo.screens[0]->root) 568 return; 569#endif 570#if DMX_WINDOW_DEBUG 571 { 572 const char *name = "Unknown"; 573 switch (type) { 574 case DMX_UPDATE_REALIZE: name = "Realize"; break; 575 case DMX_UPDATE_UNREALIZE: name = "Unrealize"; break; 576 case DMX_UPDATE_RESTACK: name = "Restack"; break; 577 case DMX_UPDATE_COPY: name = "Copy"; break; 578 case DMX_UPDATE_RESIZE: name = "Resize"; break; 579 case DMX_UPDATE_REPARENT: name = "Repaint"; break; 580 } 581 dmxLog(dmxDebug, "Window %p changed: %s\n", pWindow, name); 582 } 583#endif 584 585 if (dmxInput->detached) 586 return; 587 for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) 588 if (dmxInput->devs[i]->update_info) 589 dmxInput->devs[i]->update_info(dmxInput->devs[i]->private, 590 type, pWindow); 591} 592 593static void dmxCollectAll(DMXInputInfo *dmxInput) 594{ 595 int i; 596 597 if (dmxInput->detached) 598 return; 599 for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) 600 if (dmxInput->devs[i]->collect_events) 601 dmxInput->devs[i]->collect_events(&dmxInput->devs[i]->pDevice->public, 602 dmxMotion, 603 dmxEnqueue, 604 dmxCheckSpecialKeys, DMX_BLOCK); 605} 606 607static void dmxBlockHandler(pointer blockData, OSTimePtr pTimeout, 608 pointer pReadMask) 609{ 610 DMXInputInfo *dmxInput = &dmxInputs[(uintptr_t)blockData]; 611 static unsigned long generation = 0; 612 613 if (generation != serverGeneration) { 614 generation = serverGeneration; 615 dmxCollectAll(dmxInput); 616 } 617} 618 619static void dmxSwitchReturn(pointer p) 620{ 621 DMXInputInfo *dmxInput = p; 622 int i; 623 624 dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched); 625 626 if (!dmxInput->vt_switched) 627 dmxLog(dmxFatal, "dmxSwitchReturn called, but not switched\n"); 628 dmxSigioEnableInput(); 629 for (i = 0; i < dmxInput->numDevs; i++) 630 if (dmxInput->devs[i]->vt_post_switch) 631 dmxInput->devs[i]->vt_post_switch(dmxInput->devs[i]->private); 632 dmxInput->vt_switched = 0; 633} 634 635static void dmxWakeupHandler(pointer blockData, int result, pointer pReadMask) 636{ 637 DMXInputInfo *dmxInput = &dmxInputs[(uintptr_t)blockData]; 638 int i; 639 640 if (dmxInput->vt_switch_pending) { 641 dmxLog(dmxInfo, "Switching to VT %d\n", dmxInput->vt_switch_pending); 642 for (i = 0; i < dmxInput->numDevs; i++) 643 if (dmxInput->devs[i]->vt_pre_switch) 644 dmxInput->devs[i]->vt_pre_switch(dmxInput->devs[i]->private); 645 dmxInput->vt_switched = dmxInput->vt_switch_pending; 646 dmxInput->vt_switch_pending = 0; 647 for (i = 0; i < dmxInput->numDevs; i++) { 648 if (dmxInput->devs[i]->vt_switch) { 649 dmxSigioDisableInput(); 650 if (!dmxInput->devs[i]->vt_switch(dmxInput->devs[i]->private, 651 dmxInput->vt_switched, 652 dmxSwitchReturn, 653 dmxInput)) 654 dmxSwitchReturn(dmxInput); 655 break; /* Only call one vt_switch routine */ 656 } 657 } 658 } 659 dmxCollectAll(dmxInput); 660} 661 662static char *dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal) 663{ 664 static int k = 0; 665 static int m = 0; 666 static int o = 0; 667 static unsigned long dmxGeneration = 0; 668#define LEN 32 669 char * buf = malloc(LEN); 670 671 if (dmxGeneration != serverGeneration) { 672 k = m = o = 0; 673 dmxGeneration = serverGeneration; 674 } 675 676 switch (dmxLocal->type) { 677 case DMX_LOCAL_KEYBOARD: XmuSnprintf(buf, LEN, "Keyboard%d", k++); break; 678 case DMX_LOCAL_MOUSE: XmuSnprintf(buf, LEN, "Mouse%d", m++); break; 679 default: XmuSnprintf(buf, LEN, "Other%d", o++); break; 680 } 681 682 return buf; 683} 684 685static DeviceIntPtr dmxAddDevice(DMXLocalInputInfoPtr dmxLocal) 686{ 687 DeviceIntPtr pDevice; 688 Atom atom; 689 const char *name = NULL; 690 char *devname; 691 DMXInputInfo *dmxInput; 692 693 if (!dmxLocal) 694 return NULL; 695 dmxInput = &dmxInputs[dmxLocal->inputIdx]; 696 697 if (dmxLocal->sendsCore) { 698 if (dmxLocal->type == DMX_LOCAL_KEYBOARD && !dmxLocalCoreKeyboard) { 699 dmxLocal->isCore = 1; 700 dmxLocalCoreKeyboard = dmxLocal; 701 name = "keyboard"; 702 } 703 if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) { 704 dmxLocal->isCore = 1; 705 dmxLocalCorePointer = dmxLocal; 706 name = "pointer"; 707 } 708 } 709 710 if (!name) { 711 name = "extension"; 712 } 713 714 if (!name) 715 dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name); 716 717 pDevice = AddInputDevice(serverClient, dmxDeviceOnOff, TRUE); 718 if (!pDevice) { 719 dmxLog(dmxError, "Too many devices -- cannot add device %s\n", 720 dmxLocal->name); 721 return NULL; 722 } 723 pDevice->public.devicePrivate = dmxLocal; 724 dmxLocal->pDevice = pDevice; 725 726 devname = dmxMakeUniqueDeviceName(dmxLocal); 727 atom = MakeAtom((char *)devname, strlen(devname), TRUE); 728 pDevice->type = atom; 729 pDevice->name = devname; 730 731 if (dmxLocal->isCore && dmxLocal->type == DMX_LOCAL_MOUSE) { 732#if 00 /*BP*/ 733 miRegisterPointerDevice(screenInfo.screens[0], pDevice); 734#else 735 /* Nothing? dmxDeviceOnOff() should get called to init, right? */ 736#endif 737 } 738 739 if (dmxLocal->create_private) 740 dmxLocal->private = dmxLocal->create_private(pDevice); 741 742 dmxLogInput(dmxInput, "Added %s as %s device called %s%s\n", 743 dmxLocal->name, name, devname, 744 dmxLocal->isCore 745 ? " [core]" 746 : (dmxLocal->sendsCore 747 ? " [sends core events]" 748 : "")); 749 750 return pDevice; 751} 752 753static DMXLocalInputInfoPtr dmxLookupLocal(const char *name) 754{ 755 DMXLocalInputInfoPtr pt; 756 757 for (pt = &DMXLocalDevices[0]; pt->name; ++pt) 758 if (!strcmp(pt->name, name)) return pt; /* search for device name */ 759 return NULL; 760} 761 762/** Copy the local input information from \a s into a new \a devs slot 763 * in \a dmxInput. */ 764DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput, 765 DMXLocalInputInfoPtr s) 766{ 767 DMXLocalInputInfoPtr dmxLocal = malloc(sizeof(*dmxLocal)); 768 769 if (!dmxLocal) 770 dmxLog(dmxFatal, "DMXLocalInputInfoPtr: out of memory\n"); 771 772 memcpy(dmxLocal, s, sizeof(*dmxLocal)); 773 dmxLocal->inputIdx = dmxInput->inputIdx; 774 dmxLocal->sendsCore = dmxInput->core; 775 dmxLocal->savedSendsCore = dmxInput->core; 776 dmxLocal->deviceId = -1; 777 778 ++dmxInput->numDevs; 779 dmxInput->devs = realloc(dmxInput->devs, 780 dmxInput->numDevs * sizeof(*dmxInput->devs)); 781 dmxInput->devs[dmxInput->numDevs-1] = dmxLocal; 782 783 return dmxLocal; 784} 785 786static void dmxPopulateLocal(DMXInputInfo *dmxInput, dmxArg a) 787{ 788 int i; 789 int help = 0; 790 DMXLocalInputInfoRec *pt; 791 792 for (i = 1; i < dmxArgC(a); i++) { 793 const char *name = dmxArgV(a, i); 794 if ((pt = dmxLookupLocal(name))) { 795 dmxInputCopyLocal(dmxInput, pt); 796 } else { 797 if (strlen(name)) 798 dmxLog(dmxWarning, 799 "Could not find a driver called %s\n", name); 800 ++help; 801 } 802 } 803 if (help) { 804 dmxLog(dmxInfo, "Available local device drivers:\n"); 805 for (pt = &DMXLocalDevices[0]; pt->name; ++pt) { 806 const char *type; 807 switch (pt->type) { 808 case DMX_LOCAL_KEYBOARD: type = "keyboard"; break; 809 case DMX_LOCAL_MOUSE: type = "pointer"; break; 810 default: type = "unknown"; break; 811 } 812 dmxLog(dmxInfo, " %s (%s)\n", pt->name, type); 813 } 814 dmxLog(dmxFatal, "Must have valid local device driver\n"); 815 } 816} 817 818int dmxInputExtensionErrorHandler(Display *dsp, _Xconst char *name, _Xconst char *reason) 819{ 820 return 0; 821} 822 823static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI) 824{ 825 XExtensionVersion *ext; 826 XDeviceInfo *devices; 827 Display *display; 828 int num; 829 int i, j; 830 XextErrorHandler handler; 831 832 if (!(display = XOpenDisplay(dmxInput->name))) return; 833 834 /* Print out information about the XInput Extension. */ 835 handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler); 836 ext = XGetExtensionVersion(display, INAME); 837 XSetExtensionErrorHandler(handler); 838 839 if (!ext || ext == (XExtensionVersion *)NoSuchExtension) { 840 dmxLogInput(dmxInput, "%s is not available\n", INAME); 841 } else { 842 dmxLogInput(dmxInput, "Locating devices on %s (%s version %d.%d)\n", 843 dmxInput->name, INAME, 844 ext->major_version, ext->minor_version); 845 devices = XListInputDevices(display, &num); 846 847 XFree(ext); 848 ext = NULL; 849 850 /* Print a list of all devices */ 851 for (i = 0; i < num; i++) { 852 const char *use = "Unknown"; 853 switch (devices[i].use) { 854 case IsXPointer: use = "XPointer"; break; 855 case IsXKeyboard: use = "XKeyboard"; break; 856 case IsXExtensionDevice: use = "XExtensionDevice"; break; 857 case IsXExtensionPointer: use = "XExtensionPointer"; break; 858 case IsXExtensionKeyboard: use = "XExtensionKeyboard"; break; 859 } 860 dmxLogInput(dmxInput, " %2d %-10.10s %-16.16s\n", 861 devices[i].id, 862 devices[i].name ? devices[i].name : "", 863 use); 864 } 865 866 /* Search for extensions */ 867 for (i = 0; i < num; i++) { 868 switch (devices[i].use) { 869 case IsXKeyboard: 870 for (j = 0; j < dmxInput->numDevs; j++) { 871 DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; 872 if (dmxL->type == DMX_LOCAL_KEYBOARD 873 && dmxL->deviceId < 0) { 874 dmxL->deviceId = devices[i].id; 875 dmxL->deviceName = (devices[i].name 876 ? strdup(devices[i].name) 877 : NULL); 878 } 879 } 880 break; 881 case IsXPointer: 882 for (j = 0; j < dmxInput->numDevs; j++) { 883 DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; 884 if (dmxL->type == DMX_LOCAL_MOUSE && dmxL->deviceId < 0) { 885 dmxL->deviceId = devices[i].id; 886 dmxL->deviceName = (devices[i].name 887 ? xstrdup(devices[i].name) 888 : NULL); 889 } 890 } 891 break; 892 } 893 } 894 XFreeDeviceList(devices); 895 } 896 XCloseDisplay(display); 897} 898 899/** Re-initialize all the devices described in \a dmxInput. Called from 900 #dmxAdjustCursorBoundaries before the cursor is redisplayed. */ 901void dmxInputReInit(DMXInputInfo *dmxInput) 902{ 903 int i; 904 905 for (i = 0; i < dmxInput->numDevs; i++) { 906 DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; 907 if (dmxLocal->reinit) 908 dmxLocal->reinit(&dmxLocal->pDevice->public); 909 } 910} 911 912/** Re-initialize all the devices described in \a dmxInput. Called from 913 #dmxAdjustCursorBoundaries after the cursor is redisplayed. */ 914void dmxInputLateReInit(DMXInputInfo *dmxInput) 915{ 916 int i; 917 918 for (i = 0; i < dmxInput->numDevs; i++) { 919 DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; 920 if (dmxLocal->latereinit) 921 dmxLocal->latereinit(&dmxLocal->pDevice->public); 922 } 923} 924 925/** Initialize all of the devices described in \a dmxInput. */ 926void dmxInputInit(DMXInputInfo *dmxInput) 927{ 928 DeviceIntPtr pPointer = NULL, pKeyboard = NULL; 929 dmxArg a; 930 const char *name; 931 int i; 932 int doXI = 1; /* Include by default */ 933 int forceConsole = 0; 934 int doWindows = 1; /* On by default */ 935 int hasXkb = 0; 936 937 a = dmxArgParse(dmxInput->name); 938 939 for (i = 1; i < dmxArgC(a); i++) { 940 switch (hasXkb) { 941 case 1: 942 dmxInput->keycodes = xstrdup(dmxArgV(a, i)); 943 ++hasXkb; 944 break; 945 case 2: 946 dmxInput->symbols = xstrdup(dmxArgV(a, i)); 947 ++hasXkb; 948 break; 949 case 3: 950 dmxInput->geometry = xstrdup(dmxArgV(a, i)); 951 hasXkb = 0; 952 break; 953 case 0: 954 if (!strcmp(dmxArgV(a, i), "noxi")) doXI = 0; 955 else if (!strcmp(dmxArgV(a, i), "xi")) doXI = 1; 956 else if (!strcmp(dmxArgV(a, i), "console")) forceConsole = 1; 957 else if (!strcmp(dmxArgV(a, i), "noconsole")) forceConsole = 0; 958 else if (!strcmp(dmxArgV(a, i), "windows")) doWindows = 1; 959 else if (!strcmp(dmxArgV(a, i), "nowindows")) doWindows = 0; 960 else if (!strcmp(dmxArgV(a, i), "xkb")) hasXkb = 1; 961 else { 962 dmxLog(dmxFatal, 963 "Unknown input argument: %s\n", dmxArgV(a, i)); 964 } 965 } 966 } 967 968 name = dmxArgV(a, 0); 969 970 if (!strcmp(name, "local")) { 971 dmxPopulateLocal(dmxInput, a); 972 } else if (!strcmp(name, "dummy")) { 973 dmxInputCopyLocal(dmxInput, &DMXDummyMou); 974 dmxInputCopyLocal(dmxInput, &DMXDummyKbd); 975 dmxLogInput(dmxInput, "Using dummy input\n"); 976 } else { 977 int found; 978 979 for (found = 0, i = 0; i < dmxNumScreens; i++) { 980 if (dmxPropertySameDisplay(&dmxScreens[i], name)) { 981 if (dmxScreens[i].shared) 982 dmxLog(dmxFatal, 983 "Cannot take input from shared backend (%s)\n", 984 name); 985 if (!dmxInput->core) { 986 dmxLog(dmxWarning, 987 "Cannot use core devices on a backend (%s)" 988 " as XInput devices\n", name); 989 } else { 990 char *pt; 991 for (pt = (char *)dmxInput->name; pt && *pt; pt++) 992 if (*pt == ',') *pt = '\0'; 993 dmxInputCopyLocal(dmxInput, &DMXBackendMou); 994 dmxInputCopyLocal(dmxInput, &DMXBackendKbd); 995 dmxInput->scrnIdx = i; 996 dmxLogInput(dmxInput, 997 "Using backend input from %s\n", name); 998 } 999 ++found; 1000 break; 1001 } 1002 } 1003 if (!found || forceConsole) { 1004 char *pt; 1005 if (found) dmxInput->console = TRUE; 1006 for (pt = (char *)dmxInput->name; pt && *pt; pt++) 1007 if (*pt == ',') *pt = '\0'; 1008 dmxInputCopyLocal(dmxInput, &DMXConsoleMou); 1009 dmxInputCopyLocal(dmxInput, &DMXConsoleKbd); 1010 if (doWindows) { 1011 dmxInput->windows = TRUE; 1012 dmxInput->updateWindowInfo = dmxUpdateWindowInformation; 1013 } 1014 dmxLogInput(dmxInput, 1015 "Using console input from %s (%s windows)\n", 1016 name, doWindows ? "with" : "without"); 1017 } 1018 } 1019 1020 dmxArgFree(a); 1021 1022 /* Locate extensions we may be interested in */ 1023 dmxInputScanForExtensions(dmxInput, doXI); 1024 1025 for (i = 0; i < dmxInput->numDevs; i++) { 1026 DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; 1027 dmxLocal->pDevice = dmxAddDevice(dmxLocal); 1028 if (dmxLocal->isCore) { 1029 if (dmxLocal->type == DMX_LOCAL_MOUSE) 1030 pPointer = dmxLocal->pDevice; 1031 if (dmxLocal->type == DMX_LOCAL_KEYBOARD) 1032 pKeyboard = dmxLocal->pDevice; 1033 } 1034 } 1035 1036 dmxInput->processInputEvents = dmxProcessInputEvents; 1037 dmxInput->detached = False; 1038 1039 RegisterBlockAndWakeupHandlers(dmxBlockHandler, dmxWakeupHandler, 1040 (void *)(uintptr_t)dmxInput->inputIdx); 1041} 1042 1043static void dmxInputFreeLocal(DMXLocalInputInfoRec *local) 1044{ 1045 if (!local) return; 1046 if (local->isCore && local->type == DMX_LOCAL_MOUSE) 1047 dmxLocalCorePointer = NULL; 1048 if (local->isCore && local->type == DMX_LOCAL_KEYBOARD) 1049 dmxLocalCoreKeyboard = NULL; 1050 if (local->destroy_private) local->destroy_private(local->private); 1051 free(local->history); 1052 free(local->valuators); 1053 free(local->deviceName); 1054 local->private = NULL; 1055 local->history = NULL; 1056 local->deviceName = NULL; 1057 free(local); 1058} 1059 1060/** Free all of the memory associated with \a dmxInput */ 1061void dmxInputFree(DMXInputInfo *dmxInput) 1062{ 1063 int i; 1064 1065 if (!dmxInput) return; 1066 1067 free(dmxInput->keycodes); 1068 free(dmxInput->symbols); 1069 free(dmxInput->geometry); 1070 1071 for (i = 0; i < dmxInput->numDevs; i++) { 1072 dmxInputFreeLocal(dmxInput->devs[i]); 1073 dmxInput->devs[i] = NULL; 1074 } 1075 free(dmxInput->devs); 1076 dmxInput->devs = NULL; 1077 dmxInput->numDevs = 0; 1078 if (dmxInput->freename) free(dmxInput->name); 1079 dmxInput->name = NULL; 1080} 1081 1082/** Log information about all of the known devices using #dmxLog(). */ 1083void dmxInputLogDevices(void) 1084{ 1085 int i, j; 1086 1087 dmxLog(dmxInfo, "%d devices:\n", dmxGetInputCount()); 1088 dmxLog(dmxInfo, " Id Name Classes\n"); 1089 for (j = 0; j < dmxNumInputs; j++) { 1090 DMXInputInfo *dmxInput = &dmxInputs[j]; 1091 const char *pt = strchr(dmxInput->name, ','); 1092 int len = (pt 1093 ? (size_t)(pt-dmxInput->name) 1094 : strlen(dmxInput->name)); 1095 1096 for (i = 0; i < dmxInput->numDevs; i++) { 1097 DeviceIntPtr pDevice = dmxInput->devs[i]->pDevice; 1098 if (pDevice) { 1099 dmxLog(dmxInfo, " %2d%c %-20.20s", 1100 pDevice->id, 1101 dmxInput->detached ? 'D' : ' ', 1102 pDevice->name); 1103 if (pDevice->key) dmxLogCont(dmxInfo, " key"); 1104 if (pDevice->valuator) dmxLogCont(dmxInfo, " val"); 1105 if (pDevice->button) dmxLogCont(dmxInfo, " btn"); 1106 if (pDevice->focus) dmxLogCont(dmxInfo, " foc"); 1107 if (pDevice->kbdfeed) dmxLogCont(dmxInfo, " fb/kbd"); 1108 if (pDevice->ptrfeed) dmxLogCont(dmxInfo, " fb/ptr"); 1109 if (pDevice->intfeed) dmxLogCont(dmxInfo, " fb/int"); 1110 if (pDevice->stringfeed) dmxLogCont(dmxInfo, " fb/str"); 1111 if (pDevice->bell) dmxLogCont(dmxInfo, " fb/bel"); 1112 if (pDevice->leds) dmxLogCont(dmxInfo, " fb/led"); 1113 if (!pDevice->key && !pDevice->valuator && !pDevice->button 1114 && !pDevice->focus && !pDevice->kbdfeed 1115 && !pDevice->ptrfeed && !pDevice->intfeed 1116 && !pDevice->stringfeed && !pDevice->bell 1117 && !pDevice->leds) dmxLogCont(dmxInfo, " (none)"); 1118 1119 dmxLogCont(dmxInfo, "\t[i%d/%*.*s", 1120 dmxInput->inputIdx, len, len, dmxInput->name); 1121 if (dmxInput->devs[i]->deviceId >= 0) 1122 dmxLogCont(dmxInfo, "/id%d", dmxInput->devs[i]->deviceId); 1123 if (dmxInput->devs[i]->deviceName) 1124 dmxLogCont(dmxInfo, "=%s", dmxInput->devs[i]->deviceName); 1125 dmxLogCont(dmxInfo, "] %s\n", 1126 dmxInput->devs[i]->isCore 1127 ? "core" 1128 : (dmxInput->devs[i]->sendsCore 1129 ? "extension (sends core events)" 1130 : "extension")); 1131 } 1132 } 1133 } 1134} 1135 1136/** Detach an input */ 1137int dmxInputDetach(DMXInputInfo *dmxInput) 1138{ 1139 int i; 1140 1141 if (dmxInput->detached) return BadAccess; 1142 1143 for (i = 0; i < dmxInput->numDevs; i++) { 1144 DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; 1145 dmxLogInput(dmxInput, "Detaching device id %d: %s%s\n", 1146 dmxLocal->pDevice->id, 1147 dmxLocal->pDevice->name, 1148 dmxLocal->isCore 1149 ? " [core]" 1150 : (dmxLocal->sendsCore 1151 ? " [sends core events]" 1152 : "")); 1153 DisableDevice(dmxLocal->pDevice, TRUE); 1154 } 1155 dmxInput->detached = True; 1156 dmxInputLogDevices(); 1157 return 0; 1158} 1159 1160/** Search for input associated with \a dmxScreen, and detach. */ 1161void dmxInputDetachAll(DMXScreenInfo *dmxScreen) 1162{ 1163 int i; 1164 1165 for (i = 0; i < dmxNumInputs; i++) { 1166 DMXInputInfo *dmxInput = &dmxInputs[i]; 1167 if (dmxInput->scrnIdx == dmxScreen->index) dmxInputDetach(dmxInput); 1168 } 1169} 1170 1171/** Search for input associated with \a deviceId, and detach. */ 1172int dmxInputDetachId(int id) 1173{ 1174 DMXInputInfo *dmxInput = dmxInputLocateId(id); 1175 1176 if (!dmxInput) return BadValue; 1177 1178 return dmxInputDetach(dmxInput); 1179} 1180 1181DMXInputInfo *dmxInputLocateId(int id) 1182{ 1183 int i, j; 1184 1185 for (i = 0; i < dmxNumInputs; i++) { 1186 DMXInputInfo *dmxInput = &dmxInputs[i]; 1187 for (j = 0; j < dmxInput->numDevs; j++) { 1188 DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; 1189 if (dmxLocal->pDevice->id == id) return dmxInput; 1190 } 1191 } 1192 return NULL; 1193} 1194 1195static int dmxInputAttachNew(DMXInputInfo *dmxInput, int *id) 1196{ 1197 dmxInputInit(dmxInput); 1198 InitAndStartDevices(); 1199 if (id && dmxInput->devs) *id = dmxInput->devs[0]->pDevice->id; 1200 dmxInputLogDevices(); 1201 return 0; 1202} 1203 1204static int dmxInputAttachOld(DMXInputInfo *dmxInput, int *id) 1205{ 1206 int i; 1207 1208 dmxInput->detached = False; 1209 for (i = 0; i < dmxInput->numDevs; i++) { 1210 DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; 1211 if (id) *id = dmxLocal->pDevice->id; 1212 dmxLogInput(dmxInput, 1213 "Attaching device id %d: %s%s\n", 1214 dmxLocal->pDevice->id, 1215 dmxLocal->pDevice->name, 1216 dmxLocal->isCore 1217 ? " [core]" 1218 : (dmxLocal->sendsCore 1219 ? " [sends core events]" 1220 : "")); 1221 EnableDevice(dmxLocal->pDevice, TRUE); 1222 } 1223 dmxInputLogDevices(); 1224 return 0; 1225} 1226 1227int dmxInputAttachConsole(const char *name, int isCore, int *id) 1228{ 1229 DMXInputInfo *dmxInput; 1230 int i; 1231 1232 for (i = 0; i < dmxNumInputs; i++) { 1233 dmxInput = &dmxInputs[i]; 1234 if (dmxInput->scrnIdx == -1 1235 && dmxInput->detached 1236 && !strcmp(dmxInput->name, name)) { 1237 /* Found match */ 1238 dmxLogInput(dmxInput, "Reattaching detached console input\n"); 1239 return dmxInputAttachOld(dmxInput, id); 1240 } 1241 } 1242 1243 /* No match found */ 1244 dmxInput = dmxConfigAddInput(xstrdup(name), isCore); 1245 dmxInput->freename = TRUE; 1246 dmxLogInput(dmxInput, "Attaching new console input\n"); 1247 return dmxInputAttachNew(dmxInput, id); 1248} 1249 1250int dmxInputAttachBackend(int physicalScreen, int isCore, int *id) 1251{ 1252 DMXInputInfo *dmxInput; 1253 DMXScreenInfo *dmxScreen; 1254 int i; 1255 1256 if (physicalScreen < 0 || physicalScreen >= dmxNumScreens) return BadValue; 1257 for (i = 0; i < dmxNumInputs; i++) { 1258 dmxInput = &dmxInputs[i]; 1259 if (dmxInput->scrnIdx != -1 && dmxInput->scrnIdx == physicalScreen) { 1260 /* Found match */ 1261 if (!dmxInput->detached) return BadAccess; /* Already attached */ 1262 dmxScreen = &dmxScreens[physicalScreen]; 1263 if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ 1264 dmxLogInput(dmxInput, "Reattaching detached backend input\n"); 1265 return dmxInputAttachOld(dmxInput, id); 1266 } 1267 } 1268 /* No match found */ 1269 dmxScreen = &dmxScreens[physicalScreen]; 1270 if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ 1271 dmxInput = dmxConfigAddInput(dmxScreen->name, isCore); 1272 dmxLogInput(dmxInput, "Attaching new backend input\n"); 1273 return dmxInputAttachNew(dmxInput, id); 1274} 1275