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 */
28 /*
29 * Authors:
30 * Rickard E. (Rik) Faith <faith@redhat.com>
31 *
32 */
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. */
39 #ifdef HAVE_DMX_CONFIG_H
40 #include <dmx-config.h>
41 #endif
43 #define DMX_WINDOW_DEBUG 0
45 #include "dmxinputinit.h"
46 #include "dmxextension.h" /* For dmxInputCount */
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"
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"
66 #include "dmxsigio.h"
67 #include "dmxarg.h"
69 #include "inputstr.h"
70 #include "input.h"
71 #include "mipointer.h"
72 #include "windowstr.h"
73 #include "mi.h"
74 #include "xkbsrv.h"
76 #include <X11/extensions/XI.h>
77 #include <X11/extensions/XIproto.h>
78 #include "exevents.h"
79 #include "extinit.h"
81 DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard;
83 static DMXLocalInputInfoRec DMXDummyMou = {
84 "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
85 NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo
86 };
88 static DMXLocalInputInfoRec DMXDummyKbd = {
89 "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
90 NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo
91 };
93 static 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 };
103 static 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 };
114 static 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 };
124 static 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 };
135 static 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 };
207 #if 11 /*BP*/
208 void
209 DDXRingBell(int volume, int pitch, int duration)
210 {
211 /* NO-OP */
212 }
214 /* taken from kdrive/src/kinput.c: */
215 static void
216 dmxKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl)
217 {
218 #if 0
219 KdKeyboardInfo *ki;
221 for (ki = kdKeyboards; ki; ki = ki->next) {
222 if (ki->dixdev && ki->dixdev->id == pDevice->id)
223 break;
224 }
226 if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver)
227 return;
229 KdSetLeds(ki, ctrl->leds);
230 ki->bellPitch = ctrl->bell_pitch;
231 ki->bellDuration = ctrl->bell_duration;
232 #endif
233 }
235 /* taken from kdrive/src/kinput.c: */
236 static void
237 dmxBell(int volume, DeviceIntPtr pDev, pointer arg, int something)
238 {
239 #if 0
240 KeybdCtrl *ctrl = arg;
241 KdKeyboardInfo *ki = NULL;
243 for (ki = kdKeyboards; ki; ki = ki->next) {
244 if (ki->dixdev && ki->dixdev->id == pDev->id)
245 break;
246 }
248 if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver)
249 return;
251 KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration);
252 #endif
253 }
255 #endif /*BP*/
257 static 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 }
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. */
268 void dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl *ctrl)
269 {
270 GETDMXLOCALFROMPDEVICE;
271 int i, j;
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 }
286 static 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 }
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. */
306 void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl)
307 {
308 GETDMXLOCALFROMPDEVICE;
309 int i, j;
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 }
324 static 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 }
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. */
335 void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice,
336 pointer ctrl, int unknown)
337 {
338 GETDMXLOCALFROMPDEVICE;
339 int i, j;
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 }
354 static 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 }
364 static int dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo *info)
365 {
366 GETDMXINPUTFROMPDEVICE;
367 XkbRMLVOSet rmlvo;
369 rmlvo.rules = dmxConfigGetXkbRules();
370 rmlvo.model = dmxConfigGetXkbModel();
371 rmlvo.layout = dmxConfigGetXkbLayout();
372 rmlvo.variant = dmxConfigGetXkbVariant();
373 rmlvo.options = dmxConfigGetXkbOptions();
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;
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);
416 if (info->freenames) dmxKeyboardFreeNames(&info->names);
418 return Success;
419 }
422 static 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 */
431 if (dmxInput->detached) return Success;
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;
447 rmlvo.rules = dmxConfigGetXkbRules();
448 rmlvo.model = dmxConfigGetXkbModel();
449 rmlvo.layout = dmxConfigGetXkbLayout();
450 rmlvo.variant = dmxConfigGetXkbVariant();
451 rmlvo.options = dmxConfigGetXkbOptions();
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 }
537 static void dmxProcessInputEvents(DMXInputInfo *dmxInput)
538 {
539 int i;
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 dmxInput->devs[i]->process_input(dmxInput->devs[i]->private);
550 }
552 #if 11 /*BP*/
553 mieqProcessInputEvents();
554 #endif
555 }
557 static void dmxUpdateWindowInformation(DMXInputInfo *dmxInput,
558 DMXUpdateType type,
559 WindowPtr pWindow)
560 {
561 int i;
563 #ifdef PANORAMIX
564 if (!noPanoramiXExtension && pWindow && pWindow->parent != screenInfo.screens[0]->root)
565 return;
566 #endif
567 #if DMX_WINDOW_DEBUG
568 {
569 const char *name = "Unknown";
570 switch (type) {
571 case DMX_UPDATE_REALIZE: name = "Realize"; break;
572 case DMX_UPDATE_UNREALIZE: name = "Unrealize"; break;
573 case DMX_UPDATE_RESTACK: name = "Restack"; break;
574 case DMX_UPDATE_COPY: name = "Copy"; break;
575 case DMX_UPDATE_RESIZE: name = "Resize"; break;
576 case DMX_UPDATE_REPARENT: name = "Repaint"; break;
577 }
578 dmxLog(dmxDebug, "Window %p changed: %s\n", pWindow, name);
579 }
580 #endif
582 if (dmxInput->detached)
583 return;
584 for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding)
585 if (dmxInput->devs[i]->update_info)
586 dmxInput->devs[i]->update_info(dmxInput->devs[i]->private,
587 type, pWindow);
588 }
590 static void dmxCollectAll(DMXInputInfo *dmxInput)
591 {
592 int i;
594 if (dmxInput->detached)
595 return;
596 for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding)
597 if (dmxInput->devs[i]->collect_events)
598 dmxInput->devs[i]->collect_events(&dmxInput->devs[i]->pDevice->public,
599 dmxMotion,
600 dmxEnqueue,
601 dmxCheckSpecialKeys, DMX_BLOCK);
602 }
604 static void dmxBlockHandler(pointer blockData, OSTimePtr pTimeout,
605 pointer pReadMask)
606 {
607 DMXInputInfo *dmxInput = &dmxInputs[(uintptr_t)blockData];
608 static unsigned long generation = 0;
610 if (generation != serverGeneration) {
611 generation = serverGeneration;
612 dmxCollectAll(dmxInput);
613 }
614 }
616 static void dmxSwitchReturn(pointer p)
617 {
618 DMXInputInfo *dmxInput = p;
619 int i;
621 dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched);
623 if (!dmxInput->vt_switched)
624 dmxLog(dmxFatal, "dmxSwitchReturn called, but not switched\n");
625 dmxSigioEnableInput();
626 for (i = 0; i < dmxInput->numDevs; i++)
627 if (dmxInput->devs[i]->vt_post_switch)
628 dmxInput->devs[i]->vt_post_switch(dmxInput->devs[i]->private);
629 dmxInput->vt_switched = 0;
630 }
632 static void dmxWakeupHandler(pointer blockData, int result, pointer pReadMask)
633 {
634 DMXInputInfo *dmxInput = &dmxInputs[(uintptr_t)blockData];
635 int i;
637 if (dmxInput->vt_switch_pending) {
638 dmxLog(dmxInfo, "Switching to VT %d\n", dmxInput->vt_switch_pending);
639 for (i = 0; i < dmxInput->numDevs; i++)
640 if (dmxInput->devs[i]->vt_pre_switch)
641 dmxInput->devs[i]->vt_pre_switch(dmxInput->devs[i]->private);
642 dmxInput->vt_switched = dmxInput->vt_switch_pending;
643 dmxInput->vt_switch_pending = 0;
644 for (i = 0; i < dmxInput->numDevs; i++) {
645 if (dmxInput->devs[i]->vt_switch) {
646 dmxSigioDisableInput();
647 if (!dmxInput->devs[i]->vt_switch(dmxInput->devs[i]->private,
648 dmxInput->vt_switched,
649 dmxSwitchReturn,
650 dmxInput))
651 dmxSwitchReturn(dmxInput);
652 break; /* Only call one vt_switch routine */
653 }
654 }
655 }
656 dmxCollectAll(dmxInput);
657 }
659 static char *dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal)
660 {
661 static int k = 0;
662 static int m = 0;
663 static int o = 0;
664 static unsigned long dmxGeneration = 0;
665 #define LEN 32
666 char * buf = malloc(LEN);
668 if (dmxGeneration != serverGeneration) {
669 k = m = o = 0;
670 dmxGeneration = serverGeneration;
671 }
673 switch (dmxLocal->type) {
674 case DMX_LOCAL_KEYBOARD: XmuSnprintf(buf, LEN, "Keyboard%d", k++); break;
675 case DMX_LOCAL_MOUSE: XmuSnprintf(buf, LEN, "Mouse%d", m++); break;
676 default: XmuSnprintf(buf, LEN, "Other%d", o++); break;
677 }
679 return buf;
680 }
682 static DeviceIntPtr dmxAddDevice(DMXLocalInputInfoPtr dmxLocal)
683 {
684 DeviceIntPtr pDevice;
685 Atom atom;
686 const char *name = NULL;
687 char *devname;
688 DMXInputInfo *dmxInput;
690 if (!dmxLocal)
691 return NULL;
692 dmxInput = &dmxInputs[dmxLocal->inputIdx];
694 if (dmxLocal->sendsCore) {
695 if (dmxLocal->type == DMX_LOCAL_KEYBOARD && !dmxLocalCoreKeyboard) {
696 dmxLocal->isCore = 1;
697 dmxLocalCoreKeyboard = dmxLocal;
698 name = "keyboard";
699 }
700 if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) {
701 dmxLocal->isCore = 1;
702 dmxLocalCorePointer = dmxLocal;
703 name = "pointer";
704 }
705 }
707 if (!name) {
708 name = "extension";
709 }
711 if (!name)
712 dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name);
714 pDevice = AddInputDevice(serverClient, dmxDeviceOnOff, TRUE);
715 if (!pDevice) {
716 dmxLog(dmxError, "Too many devices -- cannot add device %s\n",
717 dmxLocal->name);
718 return NULL;
719 }
720 pDevice->public.devicePrivate = dmxLocal;
721 dmxLocal->pDevice = pDevice;
723 devname = dmxMakeUniqueDeviceName(dmxLocal);
724 atom = MakeAtom((char *)devname, strlen(devname), TRUE);
725 pDevice->type = atom;
726 pDevice->name = devname;
728 if (dmxLocal->isCore && dmxLocal->type == DMX_LOCAL_MOUSE) {
729 #if 00 /*BP*/
730 miRegisterPointerDevice(screenInfo.screens[0], pDevice);
731 #else
732 /* Nothing? dmxDeviceOnOff() should get called to init, right? */
733 #endif
734 }
736 if (dmxLocal->create_private)
737 dmxLocal->private = dmxLocal->create_private(pDevice);
739 dmxLogInput(dmxInput, "Added %s as %s device called %s%s\n",
740 dmxLocal->name, name, devname,
741 dmxLocal->isCore
742 ? " [core]"
743 : (dmxLocal->sendsCore
744 ? " [sends core events]"
745 : ""));
747 return pDevice;
748 }
750 static DMXLocalInputInfoPtr dmxLookupLocal(const char *name)
751 {
752 DMXLocalInputInfoPtr pt;
754 for (pt = &DMXLocalDevices[0]; pt->name; ++pt)
755 if (!strcmp(pt->name, name)) return pt; /* search for device name */
756 return NULL;
757 }
759 /** Copy the local input information from \a s into a new \a devs slot
760 * in \a dmxInput. */
761 DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput,
762 DMXLocalInputInfoPtr s)
763 {
764 DMXLocalInputInfoPtr dmxLocal = malloc(sizeof(*dmxLocal));
766 if (!dmxLocal)
767 dmxLog(dmxFatal, "DMXLocalInputInfoPtr: out of memory\n");
769 memcpy(dmxLocal, s, sizeof(*dmxLocal));
770 dmxLocal->inputIdx = dmxInput->inputIdx;
771 dmxLocal->sendsCore = dmxInput->core;
772 dmxLocal->savedSendsCore = dmxInput->core;
773 dmxLocal->deviceId = -1;
775 ++dmxInput->numDevs;
776 dmxInput->devs = realloc(dmxInput->devs,
777 dmxInput->numDevs * sizeof(*dmxInput->devs));
778 dmxInput->devs[dmxInput->numDevs-1] = dmxLocal;
780 return dmxLocal;
781 }
783 static void dmxPopulateLocal(DMXInputInfo *dmxInput, dmxArg a)
784 {
785 int i;
786 int help = 0;
787 DMXLocalInputInfoRec *pt;
789 for (i = 1; i < dmxArgC(a); i++) {
790 const char *name = dmxArgV(a, i);
791 if ((pt = dmxLookupLocal(name))) {
792 dmxInputCopyLocal(dmxInput, pt);
793 } else {
794 if (strlen(name))
795 dmxLog(dmxWarning,
796 "Could not find a driver called %s\n", name);
797 ++help;
798 }
799 }
800 if (help) {
801 dmxLog(dmxInfo, "Available local device drivers:\n");
802 for (pt = &DMXLocalDevices[0]; pt->name; ++pt) {
803 const char *type;
804 switch (pt->type) {
805 case DMX_LOCAL_KEYBOARD: type = "keyboard"; break;
806 case DMX_LOCAL_MOUSE: type = "pointer"; break;
807 default: type = "unknown"; break;
808 }
809 dmxLog(dmxInfo, " %s (%s)\n", pt->name, type);
810 }
811 dmxLog(dmxFatal, "Must have valid local device driver\n");
812 }
813 }
815 int dmxInputExtensionErrorHandler(Display *dsp, _Xconst char *name, _Xconst char *reason)
816 {
817 return 0;
818 }
820 static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI)
821 {
822 XExtensionVersion *ext;
823 XDeviceInfo *devices;
824 Display *display;
825 int num;
826 int i, j;
827 XextErrorHandler handler;
829 if (!(display = XOpenDisplay(dmxInput->name))) return;
831 /* Print out information about the XInput Extension. */
832 handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler);
833 ext = XGetExtensionVersion(display, INAME);
834 XSetExtensionErrorHandler(handler);
836 if (!ext || ext == (XExtensionVersion *)NoSuchExtension) {
837 dmxLogInput(dmxInput, "%s is not available\n", INAME);
838 } else {
839 dmxLogInput(dmxInput, "Locating devices on %s (%s version %d.%d)\n",
840 dmxInput->name, INAME,
841 ext->major_version, ext->minor_version);
842 devices = XListInputDevices(display, &num);
844 XFree(ext);
845 ext = NULL;
847 /* Print a list of all devices */
848 for (i = 0; i < num; i++) {
849 const char *use = "Unknown";
850 switch (devices[i].use) {
851 case IsXPointer: use = "XPointer"; break;
852 case IsXKeyboard: use = "XKeyboard"; break;
853 case IsXExtensionDevice: use = "XExtensionDevice"; break;
854 case IsXExtensionPointer: use = "XExtensionPointer"; break;
855 case IsXExtensionKeyboard: use = "XExtensionKeyboard"; break;
856 }
857 dmxLogInput(dmxInput, " %2d %-10.10s %-16.16s\n",
858 devices[i].id,
859 devices[i].name ? devices[i].name : "",
860 use);
861 }
863 /* Search for extensions */
864 for (i = 0; i < num; i++) {
865 switch (devices[i].use) {
866 case IsXKeyboard:
867 for (j = 0; j < dmxInput->numDevs; j++) {
868 DMXLocalInputInfoPtr dmxL = dmxInput->devs[j];
869 if (dmxL->type == DMX_LOCAL_KEYBOARD
870 && dmxL->deviceId < 0) {
871 dmxL->deviceId = devices[i].id;
872 dmxL->deviceName = (devices[i].name
873 ? strdup(devices[i].name)
874 : NULL);
875 }
876 }
877 break;
878 case IsXPointer:
879 for (j = 0; j < dmxInput->numDevs; j++) {
880 DMXLocalInputInfoPtr dmxL = dmxInput->devs[j];
881 if (dmxL->type == DMX_LOCAL_MOUSE && dmxL->deviceId < 0) {
882 dmxL->deviceId = devices[i].id;
883 dmxL->deviceName = (devices[i].name
884 ? xstrdup(devices[i].name)
885 : NULL);
886 }
887 }
888 break;
889 }
890 }
891 XFreeDeviceList(devices);
892 }
893 XCloseDisplay(display);
894 }
896 /** Re-initialize all the devices described in \a dmxInput. Called from
897 #dmxAdjustCursorBoundaries before the cursor is redisplayed. */
898 void dmxInputReInit(DMXInputInfo *dmxInput)
899 {
900 int i;
902 for (i = 0; i < dmxInput->numDevs; i++) {
903 DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
904 if (dmxLocal->reinit)
905 dmxLocal->reinit(&dmxLocal->pDevice->public);
906 }
907 }
909 /** Re-initialize all the devices described in \a dmxInput. Called from
910 #dmxAdjustCursorBoundaries after the cursor is redisplayed. */
911 void dmxInputLateReInit(DMXInputInfo *dmxInput)
912 {
913 int i;
915 for (i = 0; i < dmxInput->numDevs; i++) {
916 DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
917 if (dmxLocal->latereinit)
918 dmxLocal->latereinit(&dmxLocal->pDevice->public);
919 }
920 }
922 /** Initialize all of the devices described in \a dmxInput. */
923 void dmxInputInit(DMXInputInfo *dmxInput)
924 {
925 DeviceIntPtr pPointer = NULL, pKeyboard = NULL;
926 dmxArg a;
927 const char *name;
928 int i;
929 int doXI = 1; /* Include by default */
930 int forceConsole = 0;
931 int doWindows = 1; /* On by default */
932 int hasXkb = 0;
934 a = dmxArgParse(dmxInput->name);
936 for (i = 1; i < dmxArgC(a); i++) {
937 switch (hasXkb) {
938 case 1:
939 dmxInput->keycodes = xstrdup(dmxArgV(a, i));
940 ++hasXkb;
941 break;
942 case 2:
943 dmxInput->symbols = xstrdup(dmxArgV(a, i));
944 ++hasXkb;
945 break;
946 case 3:
947 dmxInput->geometry = xstrdup(dmxArgV(a, i));
948 hasXkb = 0;
949 break;
950 case 0:
951 if (!strcmp(dmxArgV(a, i), "noxi")) doXI = 0;
952 else if (!strcmp(dmxArgV(a, i), "xi")) doXI = 1;
953 else if (!strcmp(dmxArgV(a, i), "console")) forceConsole = 1;
954 else if (!strcmp(dmxArgV(a, i), "noconsole")) forceConsole = 0;
955 else if (!strcmp(dmxArgV(a, i), "windows")) doWindows = 1;
956 else if (!strcmp(dmxArgV(a, i), "nowindows")) doWindows = 0;
957 else if (!strcmp(dmxArgV(a, i), "xkb")) hasXkb = 1;
958 else {
959 dmxLog(dmxFatal,
960 "Unknown input argument: %s\n", dmxArgV(a, i));
961 }
962 }
963 }
965 name = dmxArgV(a, 0);
967 if (!strcmp(name, "local")) {
968 dmxPopulateLocal(dmxInput, a);
969 } else if (!strcmp(name, "dummy")) {
970 dmxInputCopyLocal(dmxInput, &DMXDummyMou);
971 dmxInputCopyLocal(dmxInput, &DMXDummyKbd);
972 dmxLogInput(dmxInput, "Using dummy input\n");
973 } else {
974 int found;
976 for (found = 0, i = 0; i < dmxNumScreens; i++) {
977 if (dmxPropertySameDisplay(&dmxScreens[i], name)) {
978 if (dmxScreens[i].shared)
979 dmxLog(dmxFatal,
980 "Cannot take input from shared backend (%s)\n",
981 name);
982 if (!dmxInput->core) {
983 dmxLog(dmxWarning,
984 "Cannot use core devices on a backend (%s)"
985 " as XInput devices\n", name);
986 } else {
987 char *pt;
988 for (pt = (char *)dmxInput->name; pt && *pt; pt++)
989 if (*pt == ',') *pt = '\0';
990 dmxInputCopyLocal(dmxInput, &DMXBackendMou);
991 dmxInputCopyLocal(dmxInput, &DMXBackendKbd);
992 dmxInput->scrnIdx = i;
993 dmxLogInput(dmxInput,
994 "Using backend input from %s\n", name);
995 }
996 ++found;
997 break;
998 }
999 }
1000 if (!found || forceConsole) {
1001 char *pt;
1002 if (found) dmxInput->console = TRUE;
1003 for (pt = (char *)dmxInput->name; pt && *pt; pt++)
1004 if (*pt == ',') *pt = '\0';
1005 dmxInputCopyLocal(dmxInput, &DMXConsoleMou);
1006 dmxInputCopyLocal(dmxInput, &DMXConsoleKbd);
1007 if (doWindows) {
1008 dmxInput->windows = TRUE;
1009 dmxInput->updateWindowInfo = dmxUpdateWindowInformation;
1010 }
1011 dmxLogInput(dmxInput,
1012 "Using console input from %s (%s windows)\n",
1013 name, doWindows ? "with" : "without");
1014 }
1015 }
1017 dmxArgFree(a);
1019 /* Locate extensions we may be interested in */
1020 dmxInputScanForExtensions(dmxInput, doXI);
1022 for (i = 0; i < dmxInput->numDevs; i++) {
1023 DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
1024 dmxLocal->pDevice = dmxAddDevice(dmxLocal);
1025 if (dmxLocal->isCore) {
1026 if (dmxLocal->type == DMX_LOCAL_MOUSE)
1027 pPointer = dmxLocal->pDevice;
1028 if (dmxLocal->type == DMX_LOCAL_KEYBOARD)
1029 pKeyboard = dmxLocal->pDevice;
1030 }
1031 }
1033 dmxInput->processInputEvents = dmxProcessInputEvents;
1034 dmxInput->detached = False;
1036 RegisterBlockAndWakeupHandlers(dmxBlockHandler, dmxWakeupHandler,
1037 (void *)(uintptr_t)dmxInput->inputIdx);
1038 }
1040 static void dmxInputFreeLocal(DMXLocalInputInfoRec *local)
1041 {
1042 if (!local) return;
1043 if (local->isCore && local->type == DMX_LOCAL_MOUSE)
1044 dmxLocalCorePointer = NULL;
1045 if (local->isCore && local->type == DMX_LOCAL_KEYBOARD)
1046 dmxLocalCoreKeyboard = NULL;
1047 if (local->destroy_private) local->destroy_private(local->private);
1048 free(local->history);
1049 free(local->valuators);
1050 free(local->deviceName);
1051 local->private = NULL;
1052 local->history = NULL;
1053 local->deviceName = NULL;
1054 free(local);
1055 }
1057 /** Free all of the memory associated with \a dmxInput */
1058 void dmxInputFree(DMXInputInfo *dmxInput)
1059 {
1060 int i;
1062 if (!dmxInput) return;
1064 free(dmxInput->keycodes);
1065 free(dmxInput->symbols);
1066 free(dmxInput->geometry);
1068 for (i = 0; i < dmxInput->numDevs; i++) {
1069 dmxInputFreeLocal(dmxInput->devs[i]);
1070 dmxInput->devs[i] = NULL;
1071 }
1072 free(dmxInput->devs);
1073 dmxInput->devs = NULL;
1074 dmxInput->numDevs = 0;
1075 if (dmxInput->freename) free(dmxInput->name);
1076 dmxInput->name = NULL;
1077 }
1079 /** Log information about all of the known devices using #dmxLog(). */
1080 void dmxInputLogDevices(void)
1081 {
1082 int i, j;
1084 dmxLog(dmxInfo, "%d devices:\n", dmxGetInputCount());
1085 dmxLog(dmxInfo, " Id Name Classes\n");
1086 for (j = 0; j < dmxNumInputs; j++) {
1087 DMXInputInfo *dmxInput = &dmxInputs[j];
1088 const char *pt = strchr(dmxInput->name, ',');
1089 int len = (pt
1090 ? (size_t)(pt-dmxInput->name)
1091 : strlen(dmxInput->name));
1093 for (i = 0; i < dmxInput->numDevs; i++) {
1094 DeviceIntPtr pDevice = dmxInput->devs[i]->pDevice;
1095 if (pDevice) {
1096 dmxLog(dmxInfo, " %2d%c %-20.20s",
1097 pDevice->id,
1098 dmxInput->detached ? 'D' : ' ',
1099 pDevice->name);
1100 if (pDevice->key) dmxLogCont(dmxInfo, " key");
1101 if (pDevice->valuator) dmxLogCont(dmxInfo, " val");
1102 if (pDevice->button) dmxLogCont(dmxInfo, " btn");
1103 if (pDevice->focus) dmxLogCont(dmxInfo, " foc");
1104 if (pDevice->kbdfeed) dmxLogCont(dmxInfo, " fb/kbd");
1105 if (pDevice->ptrfeed) dmxLogCont(dmxInfo, " fb/ptr");
1106 if (pDevice->intfeed) dmxLogCont(dmxInfo, " fb/int");
1107 if (pDevice->stringfeed) dmxLogCont(dmxInfo, " fb/str");
1108 if (pDevice->bell) dmxLogCont(dmxInfo, " fb/bel");
1109 if (pDevice->leds) dmxLogCont(dmxInfo, " fb/led");
1110 if (!pDevice->key && !pDevice->valuator && !pDevice->button
1111 && !pDevice->focus && !pDevice->kbdfeed
1112 && !pDevice->ptrfeed && !pDevice->intfeed
1113 && !pDevice->stringfeed && !pDevice->bell
1114 && !pDevice->leds) dmxLogCont(dmxInfo, " (none)");
1116 dmxLogCont(dmxInfo, "\t[i%d/%*.*s",
1117 dmxInput->inputIdx, len, len, dmxInput->name);
1118 if (dmxInput->devs[i]->deviceId >= 0)
1119 dmxLogCont(dmxInfo, "/id%d", dmxInput->devs[i]->deviceId);
1120 if (dmxInput->devs[i]->deviceName)
1121 dmxLogCont(dmxInfo, "=%s", dmxInput->devs[i]->deviceName);
1122 dmxLogCont(dmxInfo, "] %s\n",
1123 dmxInput->devs[i]->isCore
1124 ? "core"
1125 : (dmxInput->devs[i]->sendsCore
1126 ? "extension (sends core events)"
1127 : "extension"));
1128 }
1129 }
1130 }
1131 }
1133 /** Detach an input */
1134 int dmxInputDetach(DMXInputInfo *dmxInput)
1135 {
1136 int i;
1138 if (dmxInput->detached) return BadAccess;
1140 for (i = 0; i < dmxInput->numDevs; i++) {
1141 DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
1142 dmxLogInput(dmxInput, "Detaching device id %d: %s%s\n",
1143 dmxLocal->pDevice->id,
1144 dmxLocal->pDevice->name,
1145 dmxLocal->isCore
1146 ? " [core]"
1147 : (dmxLocal->sendsCore
1148 ? " [sends core events]"
1149 : ""));
1150 DisableDevice(dmxLocal->pDevice, TRUE);
1151 }
1152 dmxInput->detached = True;
1153 dmxInputLogDevices();
1154 return 0;
1155 }
1157 /** Search for input associated with \a dmxScreen, and detach. */
1158 void dmxInputDetachAll(DMXScreenInfo *dmxScreen)
1159 {
1160 int i;
1162 for (i = 0; i < dmxNumInputs; i++) {
1163 DMXInputInfo *dmxInput = &dmxInputs[i];
1164 if (dmxInput->scrnIdx == dmxScreen->index) dmxInputDetach(dmxInput);
1165 }
1166 }
1168 /** Search for input associated with \a deviceId, and detach. */
1169 int dmxInputDetachId(int id)
1170 {
1171 DMXInputInfo *dmxInput = dmxInputLocateId(id);
1173 if (!dmxInput) return BadValue;
1175 return dmxInputDetach(dmxInput);
1176 }
1178 DMXInputInfo *dmxInputLocateId(int id)
1179 {
1180 int i, j;
1182 for (i = 0; i < dmxNumInputs; i++) {
1183 DMXInputInfo *dmxInput = &dmxInputs[i];
1184 for (j = 0; j < dmxInput->numDevs; j++) {
1185 DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j];
1186 if (dmxLocal->pDevice->id == id) return dmxInput;
1187 }
1188 }
1189 return NULL;
1190 }
1192 static int dmxInputAttachNew(DMXInputInfo *dmxInput, int *id)
1193 {
1194 dmxInputInit(dmxInput);
1195 InitAndStartDevices();
1196 if (id && dmxInput->devs) *id = dmxInput->devs[0]->pDevice->id;
1197 dmxInputLogDevices();
1198 return 0;
1199 }
1201 static int dmxInputAttachOld(DMXInputInfo *dmxInput, int *id)
1202 {
1203 int i;
1205 dmxInput->detached = False;
1206 for (i = 0; i < dmxInput->numDevs; i++) {
1207 DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
1208 if (id) *id = dmxLocal->pDevice->id;
1209 dmxLogInput(dmxInput,
1210 "Attaching device id %d: %s%s\n",
1211 dmxLocal->pDevice->id,
1212 dmxLocal->pDevice->name,
1213 dmxLocal->isCore
1214 ? " [core]"
1215 : (dmxLocal->sendsCore
1216 ? " [sends core events]"
1217 : ""));
1218 EnableDevice(dmxLocal->pDevice, TRUE);
1219 }
1220 dmxInputLogDevices();
1221 return 0;
1222 }
1224 int dmxInputAttachConsole(const char *name, int isCore, int *id)
1225 {
1226 DMXInputInfo *dmxInput;
1227 int i;
1229 for (i = 0; i < dmxNumInputs; i++) {
1230 dmxInput = &dmxInputs[i];
1231 if (dmxInput->scrnIdx == -1
1232 && dmxInput->detached
1233 && !strcmp(dmxInput->name, name)) {
1234 /* Found match */
1235 dmxLogInput(dmxInput, "Reattaching detached console input\n");
1236 return dmxInputAttachOld(dmxInput, id);
1237 }
1238 }
1240 /* No match found */
1241 dmxInput = dmxConfigAddInput(xstrdup(name), isCore);
1242 dmxInput->freename = TRUE;
1243 dmxLogInput(dmxInput, "Attaching new console input\n");
1244 return dmxInputAttachNew(dmxInput, id);
1245 }
1247 int dmxInputAttachBackend(int physicalScreen, int isCore, int *id)
1248 {
1249 DMXInputInfo *dmxInput;
1250 DMXScreenInfo *dmxScreen;
1251 int i;
1253 if (physicalScreen < 0 || physicalScreen >= dmxNumScreens) return BadValue;
1254 for (i = 0; i < dmxNumInputs; i++) {
1255 dmxInput = &dmxInputs[i];
1256 if (dmxInput->scrnIdx != -1 && dmxInput->scrnIdx == physicalScreen) {
1257 /* Found match */
1258 if (!dmxInput->detached) return BadAccess; /* Already attached */
1259 dmxScreen = &dmxScreens[physicalScreen];
1260 if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */
1261 dmxLogInput(dmxInput, "Reattaching detached backend input\n");
1262 return dmxInputAttachOld(dmxInput, id);
1263 }
1264 }
1265 /* No match found */
1266 dmxScreen = &dmxScreens[physicalScreen];
1267 if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */
1268 dmxInput = dmxConfigAddInput(dmxScreen->name, isCore);
1269 dmxLogInput(dmxInput, "Attaching new backend input\n");
1270 return dmxInputAttachNew(dmxInput, id);
1271 }