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