2 * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
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:
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.
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
30 * Rickard E. (Rik) Faith <faith@redhat.com>
35 * This file provides generic input support. Functions here set up
36 * input and lead to the calling of low-level device drivers for
39 #ifdef HAVE_DMX_CONFIG_H
40 #include <dmx-config.h>
43 #define DMX_WINDOW_DEBUG 0
45 #include "dmxinputinit.h"
46 #include "dmxextension.h" /* For dmxInputCount */
49 #include "dmxbackend.h"
50 #include "dmxconsole.h"
51 #include "dmxcommon.h"
52 #include "dmxevents.h"
53 #include "dmxmotion.h"
55 #include "config/dmxconfig.h"
56 #include "dmxcursor.h"
58 #include "lnx-keyboard.h"
61 #include "usb-keyboard.h"
62 #include "usb-mouse.h"
63 #include "usb-other.h"
64 #include "usb-common.h"
71 #include "mipointer.h"
72 #include "windowstr.h"
76 #include <X11/extensions/XI.h>
77 #include <X11/extensions/XIproto.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
88 static DMXLocalInputInfoRec DMXDummyKbd
= {
89 "dummy-kbd", DMX_LOCAL_KEYBOARD
, DMX_LOCAL_TYPE_LOCAL
, 1,
90 NULL
, NULL
, NULL
, NULL
, NULL
, dmxDummyKbdGetInfo
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
,
99 dmxBackendCollectEvents
, dmxBackendProcessInput
, dmxBackendFunctions
, NULL
,
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
,
110 NULL
, NULL
, NULL
, NULL
,
111 NULL
, dmxCommonKbdCtrl
, dmxCommonKbdBell
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
,
120 dmxConsoleCollectEvents
, NULL
, dmxConsoleFunctions
, dmxConsoleUpdateInfo
,
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
,
131 NULL
, NULL
, NULL
, NULL
,
132 NULL
, dmxCommonKbdCtrl
, dmxCommonKbdBell
135 static DMXLocalInputInfoRec DMXLocalDevices
[] = {
136 /* Dummy drivers that can compile on any OS */
138 /* Linux-specific drivers */
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
},
148 "ms", DMX_LOCAL_MOUSE
, DMX_LOCAL_TYPE_LOCAL
, 1,
149 msLinuxCreatePrivate
, msLinuxDestroyPrivate
,
150 msLinuxInit
, NULL
, NULL
, msLinuxGetInfo
,
151 msLinuxOn
, msLinuxOff
, NULL
,
152 msLinuxVTPreSwitch
, msLinuxVTPostSwitch
, NULL
,
155 "ps2", DMX_LOCAL_MOUSE
, DMX_LOCAL_TYPE_LOCAL
, 1,
156 ps2LinuxCreatePrivate
, ps2LinuxDestroyPrivate
,
157 ps2LinuxInit
, NULL
, NULL
, ps2LinuxGetInfo
,
158 ps2LinuxOn
, ps2LinuxOff
, NULL
,
159 ps2LinuxVTPreSwitch
, ps2LinuxVTPostSwitch
, NULL
,
163 /* USB drivers, currently only for
164 Linux, but relatively easy to port to
167 "usb-kbd", DMX_LOCAL_KEYBOARD
, DMX_LOCAL_TYPE_LOCAL
, 1,
168 usbCreatePrivate
, usbDestroyPrivate
,
169 kbdUSBInit
, NULL
, NULL
, kbdUSBGetInfo
,
170 kbdUSBOn
, usbOff
, NULL
,
172 kbdUSBRead
, NULL
, NULL
, NULL
,
175 "usb-mou", DMX_LOCAL_MOUSE
, DMX_LOCAL_TYPE_LOCAL
, 1,
176 usbCreatePrivate
, usbDestroyPrivate
,
177 mouUSBInit
, NULL
, NULL
, mouUSBGetInfo
,
178 mouUSBOn
, usbOff
, NULL
,
182 "usb-oth", DMX_LOCAL_OTHER
, DMX_LOCAL_TYPE_LOCAL
, 1,
183 usbCreatePrivate
, usbDestroyPrivate
,
184 othUSBInit
, NULL
, NULL
, othUSBGetInfo
,
185 othUSBOn
, usbOff
, NULL
,
190 "dummy-mou", DMX_LOCAL_MOUSE
, DMX_LOCAL_TYPE_LOCAL
, 1,
191 NULL
, NULL
, NULL
, NULL
, NULL
, dmxDummyMouGetInfo
},
193 "dummy-kbd", DMX_LOCAL_KEYBOARD
, DMX_LOCAL_TYPE_LOCAL
, 1,
194 NULL
, NULL
, NULL
, NULL
, NULL
, dmxDummyKbdGetInfo
},
195 {NULL
} /* Must be last */
200 DDXRingBell(int volume
, int pitch
, int duration
)
205 /* taken from kdrive/src/kinput.c: */
207 dmxKbdCtrl(DeviceIntPtr pDevice
, KeybdCtrl
* ctrl
)
212 for (ki
= kdKeyboards
; ki
; ki
= ki
->next
) {
213 if (ki
->dixdev
&& ki
->dixdev
->id
== pDevice
->id
)
217 if (!ki
|| !ki
->dixdev
|| ki
->dixdev
->id
!= pDevice
->id
|| !ki
->driver
)
220 KdSetLeds(ki
, ctrl
->leds
);
221 ki
->bellPitch
= ctrl
->bell_pitch
;
222 ki
->bellDuration
= ctrl
->bell_duration
;
226 /* taken from kdrive/src/kinput.c: */
228 dmxBell(int volume
, DeviceIntPtr pDev
, pointer arg
, int something
)
231 KeybdCtrl
*ctrl
= arg
;
232 KdKeyboardInfo
*ki
= NULL
;
234 for (ki
= kdKeyboards
; ki
; ki
= ki
->next
) {
235 if (ki
->dixdev
&& ki
->dixdev
->id
== pDev
->id
)
239 if (!ki
|| !ki
->dixdev
|| ki
->dixdev
->id
!= pDev
->id
|| !ki
->driver
)
242 KdRingBell(ki
, volume
, ctrl
->bell_pitch
, ctrl
->bell_duration
);
248 _dmxChangePointerControl(DMXLocalInputInfoPtr dmxLocal
, PtrCtrl
* ctrl
)
252 dmxLocal
->mctrl
= *ctrl
;
254 dmxLocal
->mCtrl(&dmxLocal
->pDevice
->public, ctrl
);
257 /** Change the pointer control information for the \a pDevice. If the
258 * device sends core events, then also change the control information
259 * for all of the pointer devices that send core events. */
261 dmxChangePointerControl(DeviceIntPtr pDevice
, PtrCtrl
* ctrl
)
263 GETDMXLOCALFROMPDEVICE
;
266 if (dmxLocal
->sendsCore
) { /* Do for all core devices */
267 for (i
= 0; i
< dmxNumInputs
; i
++) {
268 DMXInputInfo
*dmxInput
= &dmxInputs
[i
];
270 if (dmxInput
->detached
)
272 for (j
= 0; j
< dmxInput
->numDevs
; j
++)
273 if (dmxInput
->devs
[j
]->sendsCore
)
274 _dmxChangePointerControl(dmxInput
->devs
[j
], ctrl
);
277 else { /* Do for this device only */
278 _dmxChangePointerControl(dmxLocal
, ctrl
);
283 _dmxKeyboardKbdCtrlProc(DMXLocalInputInfoPtr dmxLocal
, KeybdCtrl
* ctrl
)
285 dmxLocal
->kctrl
= *ctrl
;
286 if (dmxLocal
->kCtrl
) {
287 dmxLocal
->kCtrl(&dmxLocal
->pDevice
->public, ctrl
);
288 if (dmxLocal
->pDevice
->kbdfeed
) {
289 XkbEventCauseRec cause
;
291 XkbSetCauseUnknown(&cause
);
292 /* Generate XKB events, as necessary */
293 XkbUpdateIndicators(dmxLocal
->pDevice
, XkbAllIndicatorsMask
, False
,
299 /** Change the keyboard control information for the \a pDevice. If the
300 * device sends core events, then also change the control information
301 * for all of the keyboard devices that send core events. */
303 dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice
, KeybdCtrl
* ctrl
)
305 GETDMXLOCALFROMPDEVICE
;
308 if (dmxLocal
->sendsCore
) { /* Do for all core devices */
309 for (i
= 0; i
< dmxNumInputs
; i
++) {
310 DMXInputInfo
*dmxInput
= &dmxInputs
[i
];
312 if (dmxInput
->detached
)
314 for (j
= 0; j
< dmxInput
->numDevs
; j
++)
315 if (dmxInput
->devs
[j
]->sendsCore
)
316 _dmxKeyboardKbdCtrlProc(dmxInput
->devs
[j
], ctrl
);
319 else { /* Do for this device only */
320 _dmxKeyboardKbdCtrlProc(dmxLocal
, ctrl
);
325 _dmxKeyboardBellProc(DMXLocalInputInfoPtr dmxLocal
, int percent
)
328 dmxLocal
->kBell(&dmxLocal
->pDevice
->public,
330 dmxLocal
->kctrl
.bell
,
331 dmxLocal
->kctrl
.bell_pitch
,
332 dmxLocal
->kctrl
.bell_duration
);
335 /** Sound the bell on the device. If the device send core events, then
336 * sound the bell on all of the devices that send core events. */
338 dmxKeyboardBellProc(int percent
, DeviceIntPtr pDevice
,
339 pointer ctrl
, int unknown
)
341 GETDMXLOCALFROMPDEVICE
;
344 if (dmxLocal
->sendsCore
) { /* Do for all core devices */
345 for (i
= 0; i
< dmxNumInputs
; i
++) {
346 DMXInputInfo
*dmxInput
= &dmxInputs
[i
];
348 if (dmxInput
->detached
)
350 for (j
= 0; j
< dmxInput
->numDevs
; j
++)
351 if (dmxInput
->devs
[j
]->sendsCore
)
352 _dmxKeyboardBellProc(dmxInput
->devs
[j
], percent
);
355 else { /* Do for this device only */
356 _dmxKeyboardBellProc(dmxLocal
, percent
);
361 dmxKeyboardFreeNames(XkbComponentNamesPtr names
)
364 XFree(names
->keycodes
);
368 XFree(names
->compat
);
370 XFree(names
->symbols
);
372 XFree(names
->geometry
);
376 dmxKeyboardOn(DeviceIntPtr pDevice
, DMXLocalInitInfo
* info
)
378 GETDMXINPUTFROMPDEVICE
;
381 rmlvo
.rules
= dmxConfigGetXkbRules();
382 rmlvo
.model
= dmxConfigGetXkbModel();
383 rmlvo
.layout
= dmxConfigGetXkbLayout();
384 rmlvo
.variant
= dmxConfigGetXkbVariant();
385 rmlvo
.options
= dmxConfigGetXkbOptions();
387 XkbSetRulesDflts(&rmlvo
);
388 if (!info
->force
&& (dmxInput
->keycodes
389 || dmxInput
->symbols
|| dmxInput
->geometry
)) {
391 dmxKeyboardFreeNames(&info
->names
);
393 info
->names
.keycodes
= dmxInput
->keycodes
;
394 info
->names
.types
= NULL
;
395 info
->names
.compat
= NULL
;
396 info
->names
.symbols
= dmxInput
->symbols
;
397 info
->names
.geometry
= dmxInput
->geometry
;
399 dmxLogInput(dmxInput
, "XKEYBOARD: From command line: %s",
400 info
->names
.keycodes
);
401 if (info
->names
.symbols
&& *info
->names
.symbols
)
402 dmxLogInputCont(dmxInput
, " %s", info
->names
.symbols
);
403 if (info
->names
.geometry
&& *info
->names
.geometry
)
404 dmxLogInputCont(dmxInput
, " %s", info
->names
.geometry
);
405 dmxLogInputCont(dmxInput
, "\n");
407 else if (info
->names
.keycodes
) {
408 dmxLogInput(dmxInput
, "XKEYBOARD: From device: %s",
409 info
->names
.keycodes
);
410 if (info
->names
.symbols
&& *info
->names
.symbols
)
411 dmxLogInputCont(dmxInput
, " %s", info
->names
.symbols
);
412 if (info
->names
.geometry
&& *info
->names
.geometry
)
413 dmxLogInputCont(dmxInput
, " %s", info
->names
.geometry
);
414 dmxLogInputCont(dmxInput
, "\n");
417 dmxLogInput(dmxInput
, "XKEYBOARD: Defaults: %s %s %s %s %s\n",
418 dmxConfigGetXkbRules(),
419 dmxConfigGetXkbLayout(),
420 dmxConfigGetXkbModel(), dmxConfigGetXkbVariant()
421 ? dmxConfigGetXkbVariant() : "", dmxConfigGetXkbOptions()
422 ? dmxConfigGetXkbOptions() : "");
424 InitKeyboardDeviceStruct(pDevice
, &rmlvo
,
425 dmxKeyboardBellProc
, dmxKeyboardKbdCtrlProc
);
428 dmxKeyboardFreeNames(&info
->names
);
434 dmxDeviceOnOff(DeviceIntPtr pDevice
, int what
)
436 GETDMXINPUTFROMPDEVICE
;
438 DMXLocalInitInfo info
;
440 Atom btn_labels
[MAX_BUTTONS
] = { 0 }; /* FIXME */
441 Atom axis_labels
[MAX_VALUATORS
] = { 0 }; /* FIXME */
443 if (dmxInput
->detached
)
446 memset(&info
, 0, sizeof(info
));
450 dmxLocal
->init(pDev
);
451 if (dmxLocal
->get_info
)
452 dmxLocal
->get_info(pDev
, &info
);
453 if (info
.keyboard
) { /* XKEYBOARD makes this a special case */
454 dmxKeyboardOn(pDevice
, &info
);
460 rmlvo
.rules
= dmxConfigGetXkbRules();
461 rmlvo
.model
= dmxConfigGetXkbModel();
462 rmlvo
.layout
= dmxConfigGetXkbLayout();
463 rmlvo
.variant
= dmxConfigGetXkbVariant();
464 rmlvo
.options
= dmxConfigGetXkbOptions();
466 InitKeyboardDeviceStruct(pDevice
, &rmlvo
, dmxBell
, dmxKbdCtrl
);
468 if (info
.buttonClass
) {
469 InitButtonClassDeviceStruct(pDevice
, info
.numButtons
,
470 btn_labels
, info
.map
);
472 if (info
.valuatorClass
) {
473 if (info
.numRelAxes
&& dmxLocal
->sendsCore
) {
474 InitValuatorClassDeviceStruct(pDevice
, info
.numRelAxes
,
476 GetMaximumEventsNum(), Relative
);
477 for (i
= 0; i
< info
.numRelAxes
; i
++)
478 InitValuatorAxisStruct(pDevice
, i
, axis_labels
[i
],
479 info
.minval
[i
], info
.maxval
[i
],
481 info
.minres
[i
], info
.maxres
[i
],
484 else if (info
.numRelAxes
) {
485 InitValuatorClassDeviceStruct(pDevice
, info
.numRelAxes
,
487 dmxPointerGetMotionBufferSize(),
489 for (i
= 0; i
< info
.numRelAxes
; i
++)
490 InitValuatorAxisStruct(pDevice
, i
, axis_labels
[i
],
492 info
.maxval
[i
], info
.res
[i
],
493 info
.minres
[i
], info
.maxres
[i
],
496 else if (info
.numAbsAxes
) {
497 InitValuatorClassDeviceStruct(pDevice
, info
.numAbsAxes
,
499 dmxPointerGetMotionBufferSize(),
501 for (i
= 0; i
< info
.numAbsAxes
; i
++)
502 InitValuatorAxisStruct(pDevice
, i
,
504 info
.minval
[i
], info
.maxval
[i
],
505 info
.res
[i
], info
.minres
[i
],
506 info
.maxres
[i
], Absolute
);
510 InitFocusClassDeviceStruct(pDevice
);
511 if (info
.proximityClass
)
512 InitProximityClassDeviceStruct(pDevice
);
513 if (info
.ptrFeedbackClass
)
514 InitPtrFeedbackClassDeviceStruct(pDevice
, dmxChangePointerControl
);
515 if (info
.intFeedbackClass
|| info
.strFeedbackClass
)
517 "Integer and string feedback not supported for %s\n",
519 if (!info
.keyboard
&& (info
.ledFeedbackClass
|| info
.belFeedbackClass
))
521 "Led and bel feedback not supported for non-keyboard %s\n",
526 if (dmxLocal
->on
&& (fd
= dmxLocal
->on(pDev
)) >= 0)
527 dmxSigioRegister(dmxInput
, fd
);
533 /* This can get called twice consecutively: once for a
534 * detached screen (DEVICE_OFF), and then again at server
535 * generation time (DEVICE_CLOSE). */
537 dmxSigioUnregister(dmxInput
);
544 if (info
.keySyms
.map
&& info
.freemap
) {
545 XFree(info
.keySyms
.map
);
546 info
.keySyms
.map
= NULL
;
549 XkbFreeKeyboard(info
.xkb
, 0, True
);
554 dmxProcessInputEvents(DMXInputInfo
* dmxInput
)
558 mieqProcessInputEvents();
562 if (dmxInput
->detached
)
564 for (i
= 0; i
< dmxInput
->numDevs
; i
+= dmxInput
->devs
[i
]->binding
)
565 if (dmxInput
->devs
[i
]->process_input
) {
566 dmxInput
->devs
[i
]->process_input(dmxInput
->devs
[i
]->private);
570 mieqProcessInputEvents();
575 dmxUpdateWindowInformation(DMXInputInfo
* dmxInput
,
576 DMXUpdateType type
, WindowPtr pWindow
)
581 if (!noPanoramiXExtension
&& pWindow
&&
582 pWindow
->parent
!= screenInfo
.screens
[0]->root
)
587 const char *name
= "Unknown";
590 case DMX_UPDATE_REALIZE
:
593 case DMX_UPDATE_UNREALIZE
:
596 case DMX_UPDATE_RESTACK
:
599 case DMX_UPDATE_COPY
:
602 case DMX_UPDATE_RESIZE
:
605 case DMX_UPDATE_REPARENT
:
609 dmxLog(dmxDebug
, "Window %p changed: %s\n", pWindow
, name
);
613 if (dmxInput
->detached
)
615 for (i
= 0; i
< dmxInput
->numDevs
; i
+= dmxInput
->devs
[i
]->binding
)
616 if (dmxInput
->devs
[i
]->update_info
)
617 dmxInput
->devs
[i
]->update_info(dmxInput
->devs
[i
]->private,
622 dmxCollectAll(DMXInputInfo
* dmxInput
)
626 if (dmxInput
->detached
)
628 for (i
= 0; i
< dmxInput
->numDevs
; i
+= dmxInput
->devs
[i
]->binding
)
629 if (dmxInput
->devs
[i
]->collect_events
)
630 dmxInput
->devs
[i
]->collect_events(&dmxInput
->devs
[i
]->pDevice
->
631 public, dmxMotion
, dmxEnqueue
,
632 dmxCheckSpecialKeys
, DMX_BLOCK
);
636 dmxBlockHandler(pointer blockData
, OSTimePtr pTimeout
, pointer pReadMask
)
638 DMXInputInfo
*dmxInput
= &dmxInputs
[(uintptr_t) blockData
];
639 static unsigned long generation
= 0;
641 if (generation
!= serverGeneration
) {
642 generation
= serverGeneration
;
643 dmxCollectAll(dmxInput
);
648 dmxSwitchReturn(pointer p
)
650 DMXInputInfo
*dmxInput
= p
;
653 dmxLog(dmxInfo
, "Returning from VT %d\n", dmxInput
->vt_switched
);
655 if (!dmxInput
->vt_switched
)
656 dmxLog(dmxFatal
, "dmxSwitchReturn called, but not switched\n");
657 dmxSigioEnableInput();
658 for (i
= 0; i
< dmxInput
->numDevs
; i
++)
659 if (dmxInput
->devs
[i
]->vt_post_switch
)
660 dmxInput
->devs
[i
]->vt_post_switch(dmxInput
->devs
[i
]->private);
661 dmxInput
->vt_switched
= 0;
665 dmxWakeupHandler(pointer blockData
, int result
, pointer pReadMask
)
667 DMXInputInfo
*dmxInput
= &dmxInputs
[(uintptr_t) blockData
];
670 if (dmxInput
->vt_switch_pending
) {
671 dmxLog(dmxInfo
, "Switching to VT %d\n", dmxInput
->vt_switch_pending
);
672 for (i
= 0; i
< dmxInput
->numDevs
; i
++)
673 if (dmxInput
->devs
[i
]->vt_pre_switch
)
674 dmxInput
->devs
[i
]->vt_pre_switch(dmxInput
->devs
[i
]->private);
675 dmxInput
->vt_switched
= dmxInput
->vt_switch_pending
;
676 dmxInput
->vt_switch_pending
= 0;
677 for (i
= 0; i
< dmxInput
->numDevs
; i
++) {
678 if (dmxInput
->devs
[i
]->vt_switch
) {
679 dmxSigioDisableInput();
680 if (!dmxInput
->devs
[i
]->vt_switch(dmxInput
->devs
[i
]->private,
681 dmxInput
->vt_switched
,
682 dmxSwitchReturn
, dmxInput
))
683 dmxSwitchReturn(dmxInput
);
684 break; /* Only call one vt_switch routine */
688 dmxCollectAll(dmxInput
);
692 dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal
)
697 static unsigned long dmxGeneration
= 0;
700 char *buf
= malloc(LEN
);
702 if (dmxGeneration
!= serverGeneration
) {
704 dmxGeneration
= serverGeneration
;
707 switch (dmxLocal
->type
) {
708 case DMX_LOCAL_KEYBOARD
:
709 snprintf(buf
, LEN
, "Keyboard%d", k
++);
711 case DMX_LOCAL_MOUSE
:
712 snprintf(buf
, LEN
, "Mouse%d", m
++);
715 snprintf(buf
, LEN
, "Other%d", o
++);
723 dmxAddDevice(DMXLocalInputInfoPtr dmxLocal
)
725 DeviceIntPtr pDevice
;
727 const char *name
= NULL
;
729 DMXInputInfo
*dmxInput
;
733 dmxInput
= &dmxInputs
[dmxLocal
->inputIdx
];
735 if (dmxLocal
->sendsCore
) {
736 if (dmxLocal
->type
== DMX_LOCAL_KEYBOARD
&& !dmxLocalCoreKeyboard
) {
737 dmxLocal
->isCore
= 1;
738 dmxLocalCoreKeyboard
= dmxLocal
;
741 if (dmxLocal
->type
== DMX_LOCAL_MOUSE
&& !dmxLocalCorePointer
) {
742 dmxLocal
->isCore
= 1;
743 dmxLocalCorePointer
= dmxLocal
;
753 dmxLog(dmxFatal
, "Cannot add device %s\n", dmxLocal
->name
);
755 pDevice
= AddInputDevice(serverClient
, dmxDeviceOnOff
, TRUE
);
757 dmxLog(dmxError
, "Too many devices -- cannot add device %s\n",
761 pDevice
->public.devicePrivate
= dmxLocal
;
762 dmxLocal
->pDevice
= pDevice
;
764 devname
= dmxMakeUniqueDeviceName(dmxLocal
);
765 atom
= MakeAtom((char *) devname
, strlen(devname
), TRUE
);
766 pDevice
->type
= atom
;
767 pDevice
->name
= devname
;
769 if (dmxLocal
->isCore
&& dmxLocal
->type
== DMX_LOCAL_MOUSE
) {
771 miRegisterPointerDevice(screenInfo
.screens
[0], pDevice
);
773 /* Nothing? dmxDeviceOnOff() should get called to init, right? */
777 if (dmxLocal
->create_private
)
778 dmxLocal
->private = dmxLocal
->create_private(pDevice
);
780 dmxLogInput(dmxInput
, "Added %s as %s device called %s%s\n",
781 dmxLocal
->name
, name
, devname
,
784 : (dmxLocal
->sendsCore
? " [sends core events]" : ""));
789 static DMXLocalInputInfoPtr
790 dmxLookupLocal(const char *name
)
792 DMXLocalInputInfoPtr pt
;
794 for (pt
= &DMXLocalDevices
[0]; pt
->name
; ++pt
)
795 if (!strcmp(pt
->name
, name
))
796 return pt
; /* search for device name */
800 /** Copy the local input information from \a s into a new \a devs slot
803 dmxInputCopyLocal(DMXInputInfo
* dmxInput
, DMXLocalInputInfoPtr s
)
805 DMXLocalInputInfoPtr dmxLocal
= malloc(sizeof(*dmxLocal
));
808 dmxLog(dmxFatal
, "DMXLocalInputInfoPtr: out of memory\n");
810 memcpy(dmxLocal
, s
, sizeof(*dmxLocal
));
811 dmxLocal
->inputIdx
= dmxInput
->inputIdx
;
812 dmxLocal
->sendsCore
= dmxInput
->core
;
813 dmxLocal
->savedSendsCore
= dmxInput
->core
;
814 dmxLocal
->deviceId
= -1;
817 dmxInput
->devs
= realloc(dmxInput
->devs
,
818 dmxInput
->numDevs
* sizeof(*dmxInput
->devs
));
819 dmxInput
->devs
[dmxInput
->numDevs
- 1] = dmxLocal
;
825 dmxPopulateLocal(DMXInputInfo
* dmxInput
, dmxArg a
)
829 DMXLocalInputInfoRec
*pt
;
831 for (i
= 1; i
< dmxArgC(a
); i
++) {
832 const char *name
= dmxArgV(a
, i
);
834 if ((pt
= dmxLookupLocal(name
))) {
835 dmxInputCopyLocal(dmxInput
, pt
);
839 dmxLog(dmxWarning
, "Could not find a driver called %s\n", name
);
844 dmxLog(dmxInfo
, "Available local device drivers:\n");
845 for (pt
= &DMXLocalDevices
[0]; pt
->name
; ++pt
) {
849 case DMX_LOCAL_KEYBOARD
:
852 case DMX_LOCAL_MOUSE
:
859 dmxLog(dmxInfo
, " %s (%s)\n", pt
->name
, type
);
861 dmxLog(dmxFatal
, "Must have valid local device driver\n");
866 dmxInputExtensionErrorHandler(Display
* dsp
, _Xconst
char *name
,
867 _Xconst
char *reason
)
873 dmxInputScanForExtensions(DMXInputInfo
* dmxInput
, int doXI
)
875 XExtensionVersion
*ext
;
876 XDeviceInfo
*devices
;
880 XextErrorHandler handler
;
882 if (!(display
= XOpenDisplay(dmxInput
->name
)))
885 /* Print out information about the XInput Extension. */
886 handler
= XSetExtensionErrorHandler(dmxInputExtensionErrorHandler
);
887 ext
= XGetExtensionVersion(display
, INAME
);
888 XSetExtensionErrorHandler(handler
);
890 if (!ext
|| ext
== (XExtensionVersion
*) NoSuchExtension
) {
891 dmxLogInput(dmxInput
, "%s is not available\n", INAME
);
894 dmxLogInput(dmxInput
, "Locating devices on %s (%s version %d.%d)\n",
895 dmxInput
->name
, INAME
,
896 ext
->major_version
, ext
->minor_version
);
897 devices
= XListInputDevices(display
, &num
);
902 /* Print a list of all devices */
903 for (i
= 0; i
< num
; i
++) {
904 const char *use
= "Unknown";
906 switch (devices
[i
].use
) {
913 case IsXExtensionDevice
:
914 use
= "XExtensionDevice";
916 case IsXExtensionPointer
:
917 use
= "XExtensionPointer";
919 case IsXExtensionKeyboard
:
920 use
= "XExtensionKeyboard";
923 dmxLogInput(dmxInput
, " %2d %-10.10s %-16.16s\n",
925 devices
[i
].name
? devices
[i
].name
: "", use
);
928 /* Search for extensions */
929 for (i
= 0; i
< num
; i
++) {
930 switch (devices
[i
].use
) {
932 for (j
= 0; j
< dmxInput
->numDevs
; j
++) {
933 DMXLocalInputInfoPtr dmxL
= dmxInput
->devs
[j
];
935 if (dmxL
->type
== DMX_LOCAL_KEYBOARD
&& dmxL
->deviceId
< 0) {
936 dmxL
->deviceId
= devices
[i
].id
;
937 dmxL
->deviceName
= (devices
[i
].name
938 ? strdup(devices
[i
].name
)
944 for (j
= 0; j
< dmxInput
->numDevs
; j
++) {
945 DMXLocalInputInfoPtr dmxL
= dmxInput
->devs
[j
];
947 if (dmxL
->type
== DMX_LOCAL_MOUSE
&& dmxL
->deviceId
< 0) {
948 dmxL
->deviceId
= devices
[i
].id
;
949 dmxL
->deviceName
= (devices
[i
].name
950 ? xstrdup(devices
[i
].name
)
957 XFreeDeviceList(devices
);
959 XCloseDisplay(display
);
962 /** Re-initialize all the devices described in \a dmxInput. Called from
963 #dmxAdjustCursorBoundaries before the cursor is redisplayed. */
965 dmxInputReInit(DMXInputInfo
* dmxInput
)
969 for (i
= 0; i
< dmxInput
->numDevs
; i
++) {
970 DMXLocalInputInfoPtr dmxLocal
= dmxInput
->devs
[i
];
972 if (dmxLocal
->reinit
)
973 dmxLocal
->reinit(&dmxLocal
->pDevice
->public);
977 /** Re-initialize all the devices described in \a dmxInput. Called from
978 #dmxAdjustCursorBoundaries after the cursor is redisplayed. */
980 dmxInputLateReInit(DMXInputInfo
* dmxInput
)
984 for (i
= 0; i
< dmxInput
->numDevs
; i
++) {
985 DMXLocalInputInfoPtr dmxLocal
= dmxInput
->devs
[i
];
987 if (dmxLocal
->latereinit
)
988 dmxLocal
->latereinit(&dmxLocal
->pDevice
->public);
992 /** Initialize all of the devices described in \a dmxInput. */
994 dmxInputInit(DMXInputInfo
* dmxInput
)
996 DeviceIntPtr pPointer
= NULL
, pKeyboard
= NULL
;
1000 int doXI
= 1; /* Include by default */
1001 int forceConsole
= 0;
1002 int doWindows
= 1; /* On by default */
1005 a
= dmxArgParse(dmxInput
->name
);
1007 for (i
= 1; i
< dmxArgC(a
); i
++) {
1010 dmxInput
->keycodes
= xstrdup(dmxArgV(a
, i
));
1014 dmxInput
->symbols
= xstrdup(dmxArgV(a
, i
));
1018 dmxInput
->geometry
= xstrdup(dmxArgV(a
, i
));
1022 if (!strcmp(dmxArgV(a
, i
), "noxi"))
1024 else if (!strcmp(dmxArgV(a
, i
), "xi"))
1026 else if (!strcmp(dmxArgV(a
, i
), "console"))
1028 else if (!strcmp(dmxArgV(a
, i
), "noconsole"))
1030 else if (!strcmp(dmxArgV(a
, i
), "windows"))
1032 else if (!strcmp(dmxArgV(a
, i
), "nowindows"))
1034 else if (!strcmp(dmxArgV(a
, i
), "xkb"))
1037 dmxLog(dmxFatal
, "Unknown input argument: %s\n", dmxArgV(a
, i
));
1042 name
= dmxArgV(a
, 0);
1044 if (!strcmp(name
, "local")) {
1045 dmxPopulateLocal(dmxInput
, a
);
1047 else if (!strcmp(name
, "dummy")) {
1048 dmxInputCopyLocal(dmxInput
, &DMXDummyMou
);
1049 dmxInputCopyLocal(dmxInput
, &DMXDummyKbd
);
1050 dmxLogInput(dmxInput
, "Using dummy input\n");
1055 for (found
= 0, i
= 0; i
< dmxNumScreens
; i
++) {
1056 if (dmxPropertySameDisplay(&dmxScreens
[i
], name
)) {
1057 if (dmxScreens
[i
].shared
)
1059 "Cannot take input from shared backend (%s)\n",
1061 if (!dmxInput
->core
) {
1063 "Cannot use core devices on a backend (%s)"
1064 " as XInput devices\n", name
);
1069 for (pt
= (char *) dmxInput
->name
; pt
&& *pt
; pt
++)
1072 dmxInputCopyLocal(dmxInput
, &DMXBackendMou
);
1073 dmxInputCopyLocal(dmxInput
, &DMXBackendKbd
);
1074 dmxInput
->scrnIdx
= i
;
1075 dmxLogInput(dmxInput
,
1076 "Using backend input from %s\n", name
);
1082 if (!found
|| forceConsole
) {
1086 dmxInput
->console
= TRUE
;
1087 for (pt
= (char *) dmxInput
->name
; pt
&& *pt
; pt
++)
1090 dmxInputCopyLocal(dmxInput
, &DMXConsoleMou
);
1091 dmxInputCopyLocal(dmxInput
, &DMXConsoleKbd
);
1093 dmxInput
->windows
= TRUE
;
1094 dmxInput
->updateWindowInfo
= dmxUpdateWindowInformation
;
1096 dmxLogInput(dmxInput
,
1097 "Using console input from %s (%s windows)\n",
1098 name
, doWindows
? "with" : "without");
1104 /* Locate extensions we may be interested in */
1105 dmxInputScanForExtensions(dmxInput
, doXI
);
1107 for (i
= 0; i
< dmxInput
->numDevs
; i
++) {
1108 DMXLocalInputInfoPtr dmxLocal
= dmxInput
->devs
[i
];
1110 dmxLocal
->pDevice
= dmxAddDevice(dmxLocal
);
1111 if (dmxLocal
->isCore
) {
1112 if (dmxLocal
->type
== DMX_LOCAL_MOUSE
)
1113 pPointer
= dmxLocal
->pDevice
;
1114 if (dmxLocal
->type
== DMX_LOCAL_KEYBOARD
)
1115 pKeyboard
= dmxLocal
->pDevice
;
1119 dmxInput
->processInputEvents
= dmxProcessInputEvents
;
1120 dmxInput
->detached
= False
;
1122 RegisterBlockAndWakeupHandlers(dmxBlockHandler
, dmxWakeupHandler
,
1123 (void *) (uintptr_t) dmxInput
->inputIdx
);
1127 dmxInputFreeLocal(DMXLocalInputInfoRec
* local
)
1131 if (local
->isCore
&& local
->type
== DMX_LOCAL_MOUSE
)
1132 dmxLocalCorePointer
= NULL
;
1133 if (local
->isCore
&& local
->type
== DMX_LOCAL_KEYBOARD
)
1134 dmxLocalCoreKeyboard
= NULL
;
1135 if (local
->destroy_private
)
1136 local
->destroy_private(local
->private);
1137 free(local
->history
);
1138 free(local
->valuators
);
1139 free(local
->deviceName
);
1140 local
->private = NULL
;
1141 local
->history
= NULL
;
1142 local
->deviceName
= NULL
;
1146 /** Free all of the memory associated with \a dmxInput */
1148 dmxInputFree(DMXInputInfo
* dmxInput
)
1155 free(dmxInput
->keycodes
);
1156 free(dmxInput
->symbols
);
1157 free(dmxInput
->geometry
);
1159 for (i
= 0; i
< dmxInput
->numDevs
; i
++) {
1160 dmxInputFreeLocal(dmxInput
->devs
[i
]);
1161 dmxInput
->devs
[i
] = NULL
;
1163 free(dmxInput
->devs
);
1164 dmxInput
->devs
= NULL
;
1165 dmxInput
->numDevs
= 0;
1166 if (dmxInput
->freename
)
1167 free(dmxInput
->name
);
1168 dmxInput
->name
= NULL
;
1171 /** Log information about all of the known devices using #dmxLog(). */
1173 dmxInputLogDevices(void)
1177 dmxLog(dmxInfo
, "%d devices:\n", dmxGetInputCount());
1178 dmxLog(dmxInfo
, " Id Name Classes\n");
1179 for (j
= 0; j
< dmxNumInputs
; j
++) {
1180 DMXInputInfo
*dmxInput
= &dmxInputs
[j
];
1181 const char *pt
= strchr(dmxInput
->name
, ',');
1182 int len
= (pt
? (size_t) (pt
- dmxInput
->name
)
1183 : strlen(dmxInput
->name
));
1185 for (i
= 0; i
< dmxInput
->numDevs
; i
++) {
1186 DeviceIntPtr pDevice
= dmxInput
->devs
[i
]->pDevice
;
1189 dmxLog(dmxInfo
, " %2d%c %-20.20s",
1191 dmxInput
->detached
? 'D' : ' ', pDevice
->name
);
1193 dmxLogCont(dmxInfo
, " key");
1194 if (pDevice
->valuator
)
1195 dmxLogCont(dmxInfo
, " val");
1196 if (pDevice
->button
)
1197 dmxLogCont(dmxInfo
, " btn");
1199 dmxLogCont(dmxInfo
, " foc");
1200 if (pDevice
->kbdfeed
)
1201 dmxLogCont(dmxInfo
, " fb/kbd");
1202 if (pDevice
->ptrfeed
)
1203 dmxLogCont(dmxInfo
, " fb/ptr");
1204 if (pDevice
->intfeed
)
1205 dmxLogCont(dmxInfo
, " fb/int");
1206 if (pDevice
->stringfeed
)
1207 dmxLogCont(dmxInfo
, " fb/str");
1209 dmxLogCont(dmxInfo
, " fb/bel");
1211 dmxLogCont(dmxInfo
, " fb/led");
1212 if (!pDevice
->key
&& !pDevice
->valuator
&& !pDevice
->button
1213 && !pDevice
->focus
&& !pDevice
->kbdfeed
1214 && !pDevice
->ptrfeed
&& !pDevice
->intfeed
1215 && !pDevice
->stringfeed
&& !pDevice
->bell
&& !pDevice
->leds
)
1216 dmxLogCont(dmxInfo
, " (none)");
1218 dmxLogCont(dmxInfo
, "\t[i%d/%*.*s",
1219 dmxInput
->inputIdx
, len
, len
, dmxInput
->name
);
1220 if (dmxInput
->devs
[i
]->deviceId
>= 0)
1221 dmxLogCont(dmxInfo
, "/id%d", dmxInput
->devs
[i
]->deviceId
);
1222 if (dmxInput
->devs
[i
]->deviceName
)
1223 dmxLogCont(dmxInfo
, "=%s", dmxInput
->devs
[i
]->deviceName
);
1224 dmxLogCont(dmxInfo
, "] %s\n",
1225 dmxInput
->devs
[i
]->isCore
1227 : (dmxInput
->devs
[i
]->sendsCore
1228 ? "extension (sends core events)" : "extension"));
1234 /** Detach an input */
1236 dmxInputDetach(DMXInputInfo
* dmxInput
)
1240 if (dmxInput
->detached
)
1243 for (i
= 0; i
< dmxInput
->numDevs
; i
++) {
1244 DMXLocalInputInfoPtr dmxLocal
= dmxInput
->devs
[i
];
1246 dmxLogInput(dmxInput
, "Detaching device id %d: %s%s\n",
1247 dmxLocal
->pDevice
->id
,
1248 dmxLocal
->pDevice
->name
,
1251 : (dmxLocal
->sendsCore
? " [sends core events]" : ""));
1252 DisableDevice(dmxLocal
->pDevice
, TRUE
);
1254 dmxInput
->detached
= True
;
1255 dmxInputLogDevices();
1259 /** Search for input associated with \a dmxScreen, and detach. */
1261 dmxInputDetachAll(DMXScreenInfo
* dmxScreen
)
1265 for (i
= 0; i
< dmxNumInputs
; i
++) {
1266 DMXInputInfo
*dmxInput
= &dmxInputs
[i
];
1268 if (dmxInput
->scrnIdx
== dmxScreen
->index
)
1269 dmxInputDetach(dmxInput
);
1273 /** Search for input associated with \a deviceId, and detach. */
1275 dmxInputDetachId(int id
)
1277 DMXInputInfo
*dmxInput
= dmxInputLocateId(id
);
1282 return dmxInputDetach(dmxInput
);
1286 dmxInputLocateId(int id
)
1290 for (i
= 0; i
< dmxNumInputs
; i
++) {
1291 DMXInputInfo
*dmxInput
= &dmxInputs
[i
];
1293 for (j
= 0; j
< dmxInput
->numDevs
; j
++) {
1294 DMXLocalInputInfoPtr dmxLocal
= dmxInput
->devs
[j
];
1296 if (dmxLocal
->pDevice
->id
== id
)
1304 dmxInputAttachNew(DMXInputInfo
* dmxInput
, int *id
)
1306 dmxInputInit(dmxInput
);
1307 InitAndStartDevices();
1308 if (id
&& dmxInput
->devs
)
1309 *id
= dmxInput
->devs
[0]->pDevice
->id
;
1310 dmxInputLogDevices();
1315 dmxInputAttachOld(DMXInputInfo
* dmxInput
, int *id
)
1319 dmxInput
->detached
= False
;
1320 for (i
= 0; i
< dmxInput
->numDevs
; i
++) {
1321 DMXLocalInputInfoPtr dmxLocal
= dmxInput
->devs
[i
];
1324 *id
= dmxLocal
->pDevice
->id
;
1325 dmxLogInput(dmxInput
,
1326 "Attaching device id %d: %s%s\n",
1327 dmxLocal
->pDevice
->id
,
1328 dmxLocal
->pDevice
->name
,
1331 : (dmxLocal
->sendsCore
? " [sends core events]" : ""));
1332 EnableDevice(dmxLocal
->pDevice
, TRUE
);
1334 dmxInputLogDevices();
1339 dmxInputAttachConsole(const char *name
, int isCore
, int *id
)
1341 DMXInputInfo
*dmxInput
;
1344 for (i
= 0; i
< dmxNumInputs
; i
++) {
1345 dmxInput
= &dmxInputs
[i
];
1346 if (dmxInput
->scrnIdx
== -1
1347 && dmxInput
->detached
&& !strcmp(dmxInput
->name
, name
)) {
1349 dmxLogInput(dmxInput
, "Reattaching detached console input\n");
1350 return dmxInputAttachOld(dmxInput
, id
);
1354 /* No match found */
1355 dmxInput
= dmxConfigAddInput(xstrdup(name
), isCore
);
1356 dmxInput
->freename
= TRUE
;
1357 dmxLogInput(dmxInput
, "Attaching new console input\n");
1358 return dmxInputAttachNew(dmxInput
, id
);
1362 dmxInputAttachBackend(int physicalScreen
, int isCore
, int *id
)
1364 DMXInputInfo
*dmxInput
;
1365 DMXScreenInfo
*dmxScreen
;
1368 if (physicalScreen
< 0 || physicalScreen
>= dmxNumScreens
)
1370 for (i
= 0; i
< dmxNumInputs
; i
++) {
1371 dmxInput
= &dmxInputs
[i
];
1372 if (dmxInput
->scrnIdx
!= -1 && dmxInput
->scrnIdx
== physicalScreen
) {
1374 if (!dmxInput
->detached
)
1375 return BadAccess
; /* Already attached */
1376 dmxScreen
= &dmxScreens
[physicalScreen
];
1377 if (!dmxScreen
->beDisplay
)
1378 return BadAccess
; /* Screen detached */
1379 dmxLogInput(dmxInput
, "Reattaching detached backend input\n");
1380 return dmxInputAttachOld(dmxInput
, id
);
1383 /* No match found */
1384 dmxScreen
= &dmxScreens
[physicalScreen
];
1385 if (!dmxScreen
->beDisplay
)
1386 return BadAccess
; /* Screen detached */
1387 dmxInput
= dmxConfigAddInput(dmxScreen
->name
, isCore
);
1388 dmxLogInput(dmxInput
, "Attaching new backend input\n");
1389 return dmxInputAttachNew(dmxInput
, id
);