Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. | |
3 | * | |
4 | * All Rights Reserved. | |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person obtaining | |
7 | * a copy of this software and associated documentation files (the | |
8 | * "Software"), to deal in the Software without restriction, including | |
9 | * without limitation on the rights to use, copy, modify, merge, | |
10 | * publish, distribute, sublicense, and/or sell copies of the Software, | |
11 | * and to permit persons to whom the Software is furnished to do so, | |
12 | * subject to the following conditions: | |
13 | * | |
14 | * The above copyright notice and this permission notice (including the | |
15 | * next paragraph) shall be included in all copies or substantial | |
16 | * portions of the Software. | |
17 | * | |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
21 | * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS | |
22 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
23 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
25 | * SOFTWARE. | |
26 | */ | |
27 | ||
28 | /* | |
29 | * Authors: | |
30 | * Rickard E. (Rik) Faith <faith@redhat.com> | |
31 | * | |
32 | */ | |
33 | ||
34 | /** \file | |
35 | * This file provides generic input support. Functions here set up | |
36 | * input and lead to the calling of low-level device drivers for | |
37 | * input. */ | |
38 | ||
39 | #ifdef HAVE_DMX_CONFIG_H | |
40 | #include <dmx-config.h> | |
41 | #endif | |
42 | ||
43 | #define DMX_WINDOW_DEBUG 0 | |
44 | ||
45 | #include "dmxinputinit.h" | |
46 | #include "dmxextension.h" /* For dmxInputCount */ | |
47 | ||
48 | #include "dmxdummy.h" | |
49 | #include "dmxbackend.h" | |
50 | #include "dmxconsole.h" | |
51 | #include "dmxcommon.h" | |
52 | #include "dmxevents.h" | |
53 | #include "dmxmotion.h" | |
54 | #include "dmxprop.h" | |
55 | #include "config/dmxconfig.h" | |
56 | #include "dmxcursor.h" | |
57 | ||
58 | #include "lnx-keyboard.h" | |
59 | #include "lnx-ms.h" | |
60 | #include "lnx-ps2.h" | |
61 | #include "usb-keyboard.h" | |
62 | #include "usb-mouse.h" | |
63 | #include "usb-other.h" | |
64 | #include "usb-common.h" | |
65 | ||
66 | #include "dmxsigio.h" | |
67 | #include "dmxarg.h" | |
68 | ||
69 | #include "inputstr.h" | |
70 | #include "input.h" | |
71 | #include "mipointer.h" | |
72 | #include "windowstr.h" | |
73 | #include "mi.h" | |
74 | #include "xkbsrv.h" | |
75 | ||
76 | #include <X11/extensions/XI.h> | |
77 | #include <X11/extensions/XIproto.h> | |
78 | #include "exevents.h" | |
79 | #include "extinit.h" | |
80 | ||
81 | DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard; | |
82 | ||
83 | static DMXLocalInputInfoRec DMXDummyMou = { | |
84 | "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, | |
85 | NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo | |
86 | }; | |
87 | ||
88 | static DMXLocalInputInfoRec DMXDummyKbd = { | |
89 | "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, | |
90 | NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo | |
91 | }; | |
92 | ||
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 | }; | |
102 | ||
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 | }; | |
113 | ||
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 | }; | |
123 | ||
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 | }; | |
134 | ||
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 | "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, | |
153 | msLinuxRead}, | |
154 | { | |
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, | |
160 | ps2LinuxRead}, | |
161 | #endif | |
162 | #ifdef __linux__ | |
163 | /* USB drivers, currently only for | |
164 | Linux, but relatively easy to port to | |
165 | other OSs */ | |
166 | { | |
167 | "usb-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, | |
168 | usbCreatePrivate, usbDestroyPrivate, | |
169 | kbdUSBInit, NULL, NULL, kbdUSBGetInfo, | |
170 | kbdUSBOn, usbOff, NULL, | |
171 | NULL, NULL, NULL, | |
172 | kbdUSBRead, NULL, NULL, NULL, | |
173 | NULL, kbdUSBCtrl}, | |
174 | { | |
175 | "usb-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, | |
176 | usbCreatePrivate, usbDestroyPrivate, | |
177 | mouUSBInit, NULL, NULL, mouUSBGetInfo, | |
178 | mouUSBOn, usbOff, NULL, | |
179 | NULL, NULL, NULL, | |
180 | mouUSBRead}, | |
181 | { | |
182 | "usb-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_LOCAL, 1, | |
183 | usbCreatePrivate, usbDestroyPrivate, | |
184 | othUSBInit, NULL, NULL, othUSBGetInfo, | |
185 | othUSBOn, usbOff, NULL, | |
186 | NULL, NULL, NULL, | |
187 | othUSBRead}, | |
188 | #endif | |
189 | { | |
190 | "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, | |
191 | NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo}, | |
192 | { | |
193 | "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, | |
194 | NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo}, | |
195 | {NULL} /* Must be last */ | |
196 | }; | |
197 | ||
198 | #if 11 /*BP*/ | |
199 | void | |
200 | DDXRingBell(int volume, int pitch, int duration) | |
201 | { | |
202 | /* NO-OP */ | |
203 | } | |
204 | ||
205 | /* taken from kdrive/src/kinput.c: */ | |
206 | static void | |
207 | dmxKbdCtrl(DeviceIntPtr pDevice, KeybdCtrl * ctrl) | |
208 | { | |
209 | #if 0 | |
210 | KdKeyboardInfo *ki; | |
211 | ||
212 | for (ki = kdKeyboards; ki; ki = ki->next) { | |
213 | if (ki->dixdev && ki->dixdev->id == pDevice->id) | |
214 | break; | |
215 | } | |
216 | ||
217 | if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver) | |
218 | return; | |
219 | ||
220 | KdSetLeds(ki, ctrl->leds); | |
221 | ki->bellPitch = ctrl->bell_pitch; | |
222 | ki->bellDuration = ctrl->bell_duration; | |
223 | #endif | |
224 | } | |
225 | ||
226 | /* taken from kdrive/src/kinput.c: */ | |
227 | static void | |
228 | dmxBell(int volume, DeviceIntPtr pDev, pointer arg, int something) | |
229 | { | |
230 | #if 0 | |
231 | KeybdCtrl *ctrl = arg; | |
232 | KdKeyboardInfo *ki = NULL; | |
233 | ||
234 | for (ki = kdKeyboards; ki; ki = ki->next) { | |
235 | if (ki->dixdev && ki->dixdev->id == pDev->id) | |
236 | break; | |
237 | } | |
238 | ||
239 | if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver) | |
240 | return; | |
241 | ||
242 | KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration); | |
243 | #endif | |
244 | } | |
245 | ||
246 | #endif /*BP*/ | |
247 | static void | |
248 | _dmxChangePointerControl(DMXLocalInputInfoPtr dmxLocal, PtrCtrl * ctrl) | |
249 | { | |
250 | if (!dmxLocal) | |
251 | return; | |
252 | dmxLocal->mctrl = *ctrl; | |
253 | if (dmxLocal->mCtrl) | |
254 | dmxLocal->mCtrl(&dmxLocal->pDevice->public, ctrl); | |
255 | } | |
256 | ||
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. */ | |
260 | void | |
261 | dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl * ctrl) | |
262 | { | |
263 | GETDMXLOCALFROMPDEVICE; | |
264 | int i, j; | |
265 | ||
266 | if (dmxLocal->sendsCore) { /* Do for all core devices */ | |
267 | for (i = 0; i < dmxNumInputs; i++) { | |
268 | DMXInputInfo *dmxInput = &dmxInputs[i]; | |
269 | ||
270 | if (dmxInput->detached) | |
271 | continue; | |
272 | for (j = 0; j < dmxInput->numDevs; j++) | |
273 | if (dmxInput->devs[j]->sendsCore) | |
274 | _dmxChangePointerControl(dmxInput->devs[j], ctrl); | |
275 | } | |
276 | } | |
277 | else { /* Do for this device only */ | |
278 | _dmxChangePointerControl(dmxLocal, ctrl); | |
279 | } | |
280 | } | |
281 | ||
282 | static void | |
283 | _dmxKeyboardKbdCtrlProc(DMXLocalInputInfoPtr dmxLocal, KeybdCtrl * ctrl) | |
284 | { | |
285 | dmxLocal->kctrl = *ctrl; | |
286 | if (dmxLocal->kCtrl) { | |
287 | dmxLocal->kCtrl(&dmxLocal->pDevice->public, ctrl); | |
288 | if (dmxLocal->pDevice->kbdfeed) { | |
289 | XkbEventCauseRec cause; | |
290 | ||
291 | XkbSetCauseUnknown(&cause); | |
292 | /* Generate XKB events, as necessary */ | |
293 | XkbUpdateIndicators(dmxLocal->pDevice, XkbAllIndicatorsMask, False, | |
294 | NULL, &cause); | |
295 | } | |
296 | } | |
297 | } | |
298 | ||
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. */ | |
302 | void | |
303 | dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl * ctrl) | |
304 | { | |
305 | GETDMXLOCALFROMPDEVICE; | |
306 | int i, j; | |
307 | ||
308 | if (dmxLocal->sendsCore) { /* Do for all core devices */ | |
309 | for (i = 0; i < dmxNumInputs; i++) { | |
310 | DMXInputInfo *dmxInput = &dmxInputs[i]; | |
311 | ||
312 | if (dmxInput->detached) | |
313 | continue; | |
314 | for (j = 0; j < dmxInput->numDevs; j++) | |
315 | if (dmxInput->devs[j]->sendsCore) | |
316 | _dmxKeyboardKbdCtrlProc(dmxInput->devs[j], ctrl); | |
317 | } | |
318 | } | |
319 | else { /* Do for this device only */ | |
320 | _dmxKeyboardKbdCtrlProc(dmxLocal, ctrl); | |
321 | } | |
322 | } | |
323 | ||
324 | static void | |
325 | _dmxKeyboardBellProc(DMXLocalInputInfoPtr dmxLocal, int percent) | |
326 | { | |
327 | if (dmxLocal->kBell) | |
328 | dmxLocal->kBell(&dmxLocal->pDevice->public, | |
329 | percent, | |
330 | dmxLocal->kctrl.bell, | |
331 | dmxLocal->kctrl.bell_pitch, | |
332 | dmxLocal->kctrl.bell_duration); | |
333 | } | |
334 | ||
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. */ | |
337 | void | |
338 | dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice, | |
339 | pointer ctrl, int unknown) | |
340 | { | |
341 | GETDMXLOCALFROMPDEVICE; | |
342 | int i, j; | |
343 | ||
344 | if (dmxLocal->sendsCore) { /* Do for all core devices */ | |
345 | for (i = 0; i < dmxNumInputs; i++) { | |
346 | DMXInputInfo *dmxInput = &dmxInputs[i]; | |
347 | ||
348 | if (dmxInput->detached) | |
349 | continue; | |
350 | for (j = 0; j < dmxInput->numDevs; j++) | |
351 | if (dmxInput->devs[j]->sendsCore) | |
352 | _dmxKeyboardBellProc(dmxInput->devs[j], percent); | |
353 | } | |
354 | } | |
355 | else { /* Do for this device only */ | |
356 | _dmxKeyboardBellProc(dmxLocal, percent); | |
357 | } | |
358 | } | |
359 | ||
360 | static void | |
361 | dmxKeyboardFreeNames(XkbComponentNamesPtr names) | |
362 | { | |
363 | if (names->keycodes) | |
364 | XFree(names->keycodes); | |
365 | if (names->types) | |
366 | XFree(names->types); | |
367 | if (names->compat) | |
368 | XFree(names->compat); | |
369 | if (names->symbols) | |
370 | XFree(names->symbols); | |
371 | if (names->geometry) | |
372 | XFree(names->geometry); | |
373 | } | |
374 | ||
375 | static int | |
376 | dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo * info) | |
377 | { | |
378 | GETDMXINPUTFROMPDEVICE; | |
379 | XkbRMLVOSet rmlvo; | |
380 | ||
381 | rmlvo.rules = dmxConfigGetXkbRules(); | |
382 | rmlvo.model = dmxConfigGetXkbModel(); | |
383 | rmlvo.layout = dmxConfigGetXkbLayout(); | |
384 | rmlvo.variant = dmxConfigGetXkbVariant(); | |
385 | rmlvo.options = dmxConfigGetXkbOptions(); | |
386 | ||
387 | XkbSetRulesDflts(&rmlvo); | |
388 | if (!info->force && (dmxInput->keycodes | |
389 | || dmxInput->symbols || dmxInput->geometry)) { | |
390 | if (info->freenames) | |
391 | dmxKeyboardFreeNames(&info->names); | |
392 | info->freenames = 0; | |
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; | |
398 | ||
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"); | |
406 | } | |
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"); | |
415 | } | |
416 | else { | |
417 | dmxLogInput(dmxInput, "XKEYBOARD: Defaults: %s %s %s %s %s\n", | |
418 | dmxConfigGetXkbRules(), | |
419 | dmxConfigGetXkbLayout(), | |
420 | dmxConfigGetXkbModel(), dmxConfigGetXkbVariant() | |
421 | ? dmxConfigGetXkbVariant() : "", dmxConfigGetXkbOptions() | |
422 | ? dmxConfigGetXkbOptions() : ""); | |
423 | } | |
424 | InitKeyboardDeviceStruct(pDevice, &rmlvo, | |
425 | dmxKeyboardBellProc, dmxKeyboardKbdCtrlProc); | |
426 | ||
427 | if (info->freenames) | |
428 | dmxKeyboardFreeNames(&info->names); | |
429 | ||
430 | return Success; | |
431 | } | |
432 | ||
433 | static int | |
434 | dmxDeviceOnOff(DeviceIntPtr pDevice, int what) | |
435 | { | |
436 | GETDMXINPUTFROMPDEVICE; | |
437 | int fd; | |
438 | DMXLocalInitInfo info; | |
439 | int i; | |
440 | Atom btn_labels[MAX_BUTTONS] = { 0 }; /* FIXME */ | |
441 | Atom axis_labels[MAX_VALUATORS] = { 0 }; /* FIXME */ | |
442 | ||
443 | if (dmxInput->detached) | |
444 | return Success; | |
445 | ||
446 | memset(&info, 0, sizeof(info)); | |
447 | switch (what) { | |
448 | case DEVICE_INIT: | |
449 | if (dmxLocal->init) | |
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); | |
455 | break; | |
456 | } | |
457 | if (info.keyClass) { | |
458 | XkbRMLVOSet rmlvo; | |
459 | ||
460 | rmlvo.rules = dmxConfigGetXkbRules(); | |
461 | rmlvo.model = dmxConfigGetXkbModel(); | |
462 | rmlvo.layout = dmxConfigGetXkbLayout(); | |
463 | rmlvo.variant = dmxConfigGetXkbVariant(); | |
464 | rmlvo.options = dmxConfigGetXkbOptions(); | |
465 | ||
466 | InitKeyboardDeviceStruct(pDevice, &rmlvo, dmxBell, dmxKbdCtrl); | |
467 | } | |
468 | if (info.buttonClass) { | |
469 | InitButtonClassDeviceStruct(pDevice, info.numButtons, | |
470 | btn_labels, info.map); | |
471 | } | |
472 | if (info.valuatorClass) { | |
473 | if (info.numRelAxes && dmxLocal->sendsCore) { | |
474 | InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, | |
475 | axis_labels, | |
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], | |
480 | info.res[i], | |
481 | info.minres[i], info.maxres[i], | |
482 | Relative); | |
483 | } | |
484 | else if (info.numRelAxes) { | |
485 | InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, | |
486 | axis_labels, | |
487 | dmxPointerGetMotionBufferSize(), | |
488 | Relative); | |
489 | for (i = 0; i < info.numRelAxes; i++) | |
490 | InitValuatorAxisStruct(pDevice, i, axis_labels[i], | |
491 | info.minval[i], | |
492 | info.maxval[i], info.res[i], | |
493 | info.minres[i], info.maxres[i], | |
494 | Relative); | |
495 | } | |
496 | else if (info.numAbsAxes) { | |
497 | InitValuatorClassDeviceStruct(pDevice, info.numAbsAxes, | |
498 | axis_labels, | |
499 | dmxPointerGetMotionBufferSize(), | |
500 | Absolute); | |
501 | for (i = 0; i < info.numAbsAxes; i++) | |
502 | InitValuatorAxisStruct(pDevice, i, | |
503 | axis_labels[i], | |
504 | info.minval[i], info.maxval[i], | |
505 | info.res[i], info.minres[i], | |
506 | info.maxres[i], Absolute); | |
507 | } | |
508 | } | |
509 | if (info.focusClass) | |
510 | InitFocusClassDeviceStruct(pDevice); | |
511 | if (info.proximityClass) | |
512 | InitProximityClassDeviceStruct(pDevice); | |
513 | if (info.ptrFeedbackClass) | |
514 | InitPtrFeedbackClassDeviceStruct(pDevice, dmxChangePointerControl); | |
515 | if (info.intFeedbackClass || info.strFeedbackClass) | |
516 | dmxLog(dmxWarning, | |
517 | "Integer and string feedback not supported for %s\n", | |
518 | pDevice->name); | |
519 | if (!info.keyboard && (info.ledFeedbackClass || info.belFeedbackClass)) | |
520 | dmxLog(dmxWarning, | |
521 | "Led and bel feedback not supported for non-keyboard %s\n", | |
522 | pDevice->name); | |
523 | break; | |
524 | case DEVICE_ON: | |
525 | if (!pDev->on) { | |
526 | if (dmxLocal->on && (fd = dmxLocal->on(pDev)) >= 0) | |
527 | dmxSigioRegister(dmxInput, fd); | |
528 | pDev->on = TRUE; | |
529 | } | |
530 | break; | |
531 | case DEVICE_OFF: | |
532 | case DEVICE_CLOSE: | |
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). */ | |
536 | if (pDev->on) { | |
537 | dmxSigioUnregister(dmxInput); | |
538 | if (dmxLocal->off) | |
539 | dmxLocal->off(pDev); | |
540 | pDev->on = FALSE; | |
541 | } | |
542 | break; | |
543 | } | |
544 | if (info.keySyms.map && info.freemap) { | |
545 | XFree(info.keySyms.map); | |
546 | info.keySyms.map = NULL; | |
547 | } | |
548 | if (info.xkb) | |
549 | XkbFreeKeyboard(info.xkb, 0, True); | |
550 | return Success; | |
551 | } | |
552 | ||
553 | static void | |
554 | dmxProcessInputEvents(DMXInputInfo * dmxInput) | |
555 | { | |
556 | int i; | |
557 | ||
558 | mieqProcessInputEvents(); | |
559 | #if 00 /*BP*/ | |
560 | miPointerUpdate(); | |
561 | #endif | |
562 | if (dmxInput->detached) | |
563 | return; | |
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); | |
567 | } | |
568 | ||
569 | #if 11 /*BP*/ | |
570 | mieqProcessInputEvents(); | |
571 | #endif | |
572 | } | |
573 | ||
574 | static void | |
575 | dmxUpdateWindowInformation(DMXInputInfo * dmxInput, | |
576 | DMXUpdateType type, WindowPtr pWindow) | |
577 | { | |
578 | int i; | |
579 | ||
580 | #ifdef PANORAMIX | |
581 | if (!noPanoramiXExtension && pWindow && | |
582 | pWindow->parent != screenInfo.screens[0]->root) | |
583 | return; | |
584 | #endif | |
585 | #if DMX_WINDOW_DEBUG | |
586 | { | |
587 | const char *name = "Unknown"; | |
588 | ||
589 | switch (type) { | |
590 | case DMX_UPDATE_REALIZE: | |
591 | name = "Realize"; | |
592 | break; | |
593 | case DMX_UPDATE_UNREALIZE: | |
594 | name = "Unrealize"; | |
595 | break; | |
596 | case DMX_UPDATE_RESTACK: | |
597 | name = "Restack"; | |
598 | break; | |
599 | case DMX_UPDATE_COPY: | |
600 | name = "Copy"; | |
601 | break; | |
602 | case DMX_UPDATE_RESIZE: | |
603 | name = "Resize"; | |
604 | break; | |
605 | case DMX_UPDATE_REPARENT: | |
606 | name = "Repaint"; | |
607 | break; | |
608 | } | |
609 | dmxLog(dmxDebug, "Window %p changed: %s\n", pWindow, name); | |
610 | } | |
611 | #endif | |
612 | ||
613 | if (dmxInput->detached) | |
614 | return; | |
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, | |
618 | type, pWindow); | |
619 | } | |
620 | ||
621 | static void | |
622 | dmxCollectAll(DMXInputInfo * dmxInput) | |
623 | { | |
624 | int i; | |
625 | ||
626 | if (dmxInput->detached) | |
627 | return; | |
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); | |
633 | } | |
634 | ||
635 | static void | |
636 | dmxBlockHandler(pointer blockData, OSTimePtr pTimeout, pointer pReadMask) | |
637 | { | |
638 | DMXInputInfo *dmxInput = &dmxInputs[(uintptr_t) blockData]; | |
639 | static unsigned long generation = 0; | |
640 | ||
641 | if (generation != serverGeneration) { | |
642 | generation = serverGeneration; | |
643 | dmxCollectAll(dmxInput); | |
644 | } | |
645 | } | |
646 | ||
647 | static void | |
648 | dmxSwitchReturn(pointer p) | |
649 | { | |
650 | DMXInputInfo *dmxInput = p; | |
651 | int i; | |
652 | ||
653 | dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched); | |
654 | ||
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; | |
662 | } | |
663 | ||
664 | static void | |
665 | dmxWakeupHandler(pointer blockData, int result, pointer pReadMask) | |
666 | { | |
667 | DMXInputInfo *dmxInput = &dmxInputs[(uintptr_t) blockData]; | |
668 | int i; | |
669 | ||
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 */ | |
685 | } | |
686 | } | |
687 | } | |
688 | dmxCollectAll(dmxInput); | |
689 | } | |
690 | ||
691 | static char * | |
692 | dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal) | |
693 | { | |
694 | static int k = 0; | |
695 | static int m = 0; | |
696 | static int o = 0; | |
697 | static unsigned long dmxGeneration = 0; | |
698 | ||
699 | #define LEN 32 | |
700 | char *buf = malloc(LEN); | |
701 | ||
702 | if (dmxGeneration != serverGeneration) { | |
703 | k = m = o = 0; | |
704 | dmxGeneration = serverGeneration; | |
705 | } | |
706 | ||
707 | switch (dmxLocal->type) { | |
708 | case DMX_LOCAL_KEYBOARD: | |
709 | snprintf(buf, LEN, "Keyboard%d", k++); | |
710 | break; | |
711 | case DMX_LOCAL_MOUSE: | |
712 | snprintf(buf, LEN, "Mouse%d", m++); | |
713 | break; | |
714 | default: | |
715 | snprintf(buf, LEN, "Other%d", o++); | |
716 | break; | |
717 | } | |
718 | ||
719 | return buf; | |
720 | } | |
721 | ||
722 | static DeviceIntPtr | |
723 | dmxAddDevice(DMXLocalInputInfoPtr dmxLocal) | |
724 | { | |
725 | DeviceIntPtr pDevice; | |
726 | Atom atom; | |
727 | const char *name = NULL; | |
728 | char *devname; | |
729 | DMXInputInfo *dmxInput; | |
730 | ||
731 | if (!dmxLocal) | |
732 | return NULL; | |
733 | dmxInput = &dmxInputs[dmxLocal->inputIdx]; | |
734 | ||
735 | if (dmxLocal->sendsCore) { | |
736 | if (dmxLocal->type == DMX_LOCAL_KEYBOARD && !dmxLocalCoreKeyboard) { | |
737 | dmxLocal->isCore = 1; | |
738 | dmxLocalCoreKeyboard = dmxLocal; | |
739 | name = "keyboard"; | |
740 | } | |
741 | if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) { | |
742 | dmxLocal->isCore = 1; | |
743 | dmxLocalCorePointer = dmxLocal; | |
744 | name = "pointer"; | |
745 | } | |
746 | } | |
747 | ||
748 | if (!name) { | |
749 | name = "extension"; | |
750 | } | |
751 | ||
752 | if (!name) | |
753 | dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name); | |
754 | ||
755 | pDevice = AddInputDevice(serverClient, dmxDeviceOnOff, TRUE); | |
756 | if (!pDevice) { | |
757 | dmxLog(dmxError, "Too many devices -- cannot add device %s\n", | |
758 | dmxLocal->name); | |
759 | return NULL; | |
760 | } | |
761 | pDevice->public.devicePrivate = dmxLocal; | |
762 | dmxLocal->pDevice = pDevice; | |
763 | ||
764 | devname = dmxMakeUniqueDeviceName(dmxLocal); | |
765 | atom = MakeAtom((char *) devname, strlen(devname), TRUE); | |
766 | pDevice->type = atom; | |
767 | pDevice->name = devname; | |
768 | ||
769 | if (dmxLocal->isCore && dmxLocal->type == DMX_LOCAL_MOUSE) { | |
770 | #if 00 /*BP*/ | |
771 | miRegisterPointerDevice(screenInfo.screens[0], pDevice); | |
772 | #else | |
773 | /* Nothing? dmxDeviceOnOff() should get called to init, right? */ | |
774 | #endif | |
775 | } | |
776 | ||
777 | if (dmxLocal->create_private) | |
778 | dmxLocal->private = dmxLocal->create_private(pDevice); | |
779 | ||
780 | dmxLogInput(dmxInput, "Added %s as %s device called %s%s\n", | |
781 | dmxLocal->name, name, devname, | |
782 | dmxLocal->isCore | |
783 | ? " [core]" | |
784 | : (dmxLocal->sendsCore ? " [sends core events]" : "")); | |
785 | ||
786 | return pDevice; | |
787 | } | |
788 | ||
789 | static DMXLocalInputInfoPtr | |
790 | dmxLookupLocal(const char *name) | |
791 | { | |
792 | DMXLocalInputInfoPtr pt; | |
793 | ||
794 | for (pt = &DMXLocalDevices[0]; pt->name; ++pt) | |
795 | if (!strcmp(pt->name, name)) | |
796 | return pt; /* search for device name */ | |
797 | return NULL; | |
798 | } | |
799 | ||
800 | /** Copy the local input information from \a s into a new \a devs slot | |
801 | * in \a dmxInput. */ | |
802 | DMXLocalInputInfoPtr | |
803 | dmxInputCopyLocal(DMXInputInfo * dmxInput, DMXLocalInputInfoPtr s) | |
804 | { | |
805 | DMXLocalInputInfoPtr dmxLocal = malloc(sizeof(*dmxLocal)); | |
806 | ||
807 | if (!dmxLocal) | |
808 | dmxLog(dmxFatal, "DMXLocalInputInfoPtr: out of memory\n"); | |
809 | ||
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; | |
815 | ||
816 | ++dmxInput->numDevs; | |
817 | dmxInput->devs = realloc(dmxInput->devs, | |
818 | dmxInput->numDevs * sizeof(*dmxInput->devs)); | |
819 | dmxInput->devs[dmxInput->numDevs - 1] = dmxLocal; | |
820 | ||
821 | return dmxLocal; | |
822 | } | |
823 | ||
824 | static void | |
825 | dmxPopulateLocal(DMXInputInfo * dmxInput, dmxArg a) | |
826 | { | |
827 | int i; | |
828 | int help = 0; | |
829 | DMXLocalInputInfoRec *pt; | |
830 | ||
831 | for (i = 1; i < dmxArgC(a); i++) { | |
832 | const char *name = dmxArgV(a, i); | |
833 | ||
834 | if ((pt = dmxLookupLocal(name))) { | |
835 | dmxInputCopyLocal(dmxInput, pt); | |
836 | } | |
837 | else { | |
838 | if (strlen(name)) | |
839 | dmxLog(dmxWarning, "Could not find a driver called %s\n", name); | |
840 | ++help; | |
841 | } | |
842 | } | |
843 | if (help) { | |
844 | dmxLog(dmxInfo, "Available local device drivers:\n"); | |
845 | for (pt = &DMXLocalDevices[0]; pt->name; ++pt) { | |
846 | const char *type; | |
847 | ||
848 | switch (pt->type) { | |
849 | case DMX_LOCAL_KEYBOARD: | |
850 | type = "keyboard"; | |
851 | break; | |
852 | case DMX_LOCAL_MOUSE: | |
853 | type = "pointer"; | |
854 | break; | |
855 | default: | |
856 | type = "unknown"; | |
857 | break; | |
858 | } | |
859 | dmxLog(dmxInfo, " %s (%s)\n", pt->name, type); | |
860 | } | |
861 | dmxLog(dmxFatal, "Must have valid local device driver\n"); | |
862 | } | |
863 | } | |
864 | ||
865 | int | |
866 | dmxInputExtensionErrorHandler(Display * dsp, _Xconst char *name, | |
867 | _Xconst char *reason) | |
868 | { | |
869 | return 0; | |
870 | } | |
871 | ||
872 | static void | |
873 | dmxInputScanForExtensions(DMXInputInfo * dmxInput, int doXI) | |
874 | { | |
875 | XExtensionVersion *ext; | |
876 | XDeviceInfo *devices; | |
877 | Display *display; | |
878 | int num; | |
879 | int i, j; | |
880 | XextErrorHandler handler; | |
881 | ||
882 | if (!(display = XOpenDisplay(dmxInput->name))) | |
883 | return; | |
884 | ||
885 | /* Print out information about the XInput Extension. */ | |
886 | handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler); | |
887 | ext = XGetExtensionVersion(display, INAME); | |
888 | XSetExtensionErrorHandler(handler); | |
889 | ||
890 | if (!ext || ext == (XExtensionVersion *) NoSuchExtension) { | |
891 | dmxLogInput(dmxInput, "%s is not available\n", INAME); | |
892 | } | |
893 | else { | |
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); | |
898 | ||
899 | XFree(ext); | |
900 | ext = NULL; | |
901 | ||
902 | /* Print a list of all devices */ | |
903 | for (i = 0; i < num; i++) { | |
904 | const char *use = "Unknown"; | |
905 | ||
906 | switch (devices[i].use) { | |
907 | case IsXPointer: | |
908 | use = "XPointer"; | |
909 | break; | |
910 | case IsXKeyboard: | |
911 | use = "XKeyboard"; | |
912 | break; | |
913 | case IsXExtensionDevice: | |
914 | use = "XExtensionDevice"; | |
915 | break; | |
916 | case IsXExtensionPointer: | |
917 | use = "XExtensionPointer"; | |
918 | break; | |
919 | case IsXExtensionKeyboard: | |
920 | use = "XExtensionKeyboard"; | |
921 | break; | |
922 | } | |
923 | dmxLogInput(dmxInput, " %2d %-10.10s %-16.16s\n", | |
924 | devices[i].id, | |
925 | devices[i].name ? devices[i].name : "", use); | |
926 | } | |
927 | ||
928 | /* Search for extensions */ | |
929 | for (i = 0; i < num; i++) { | |
930 | switch (devices[i].use) { | |
931 | case IsXKeyboard: | |
932 | for (j = 0; j < dmxInput->numDevs; j++) { | |
933 | DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; | |
934 | ||
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) | |
939 | : NULL); | |
940 | } | |
941 | } | |
942 | break; | |
943 | case IsXPointer: | |
944 | for (j = 0; j < dmxInput->numDevs; j++) { | |
945 | DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; | |
946 | ||
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) | |
951 | : NULL); | |
952 | } | |
953 | } | |
954 | break; | |
955 | } | |
956 | } | |
957 | XFreeDeviceList(devices); | |
958 | } | |
959 | XCloseDisplay(display); | |
960 | } | |
961 | ||
962 | /** Re-initialize all the devices described in \a dmxInput. Called from | |
963 | #dmxAdjustCursorBoundaries before the cursor is redisplayed. */ | |
964 | void | |
965 | dmxInputReInit(DMXInputInfo * dmxInput) | |
966 | { | |
967 | int i; | |
968 | ||
969 | for (i = 0; i < dmxInput->numDevs; i++) { | |
970 | DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; | |
971 | ||
972 | if (dmxLocal->reinit) | |
973 | dmxLocal->reinit(&dmxLocal->pDevice->public); | |
974 | } | |
975 | } | |
976 | ||
977 | /** Re-initialize all the devices described in \a dmxInput. Called from | |
978 | #dmxAdjustCursorBoundaries after the cursor is redisplayed. */ | |
979 | void | |
980 | dmxInputLateReInit(DMXInputInfo * dmxInput) | |
981 | { | |
982 | int i; | |
983 | ||
984 | for (i = 0; i < dmxInput->numDevs; i++) { | |
985 | DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; | |
986 | ||
987 | if (dmxLocal->latereinit) | |
988 | dmxLocal->latereinit(&dmxLocal->pDevice->public); | |
989 | } | |
990 | } | |
991 | ||
992 | /** Initialize all of the devices described in \a dmxInput. */ | |
993 | void | |
994 | dmxInputInit(DMXInputInfo * dmxInput) | |
995 | { | |
996 | DeviceIntPtr pPointer = NULL, pKeyboard = NULL; | |
997 | dmxArg a; | |
998 | const char *name; | |
999 | int i; | |
1000 | int doXI = 1; /* Include by default */ | |
1001 | int forceConsole = 0; | |
1002 | int doWindows = 1; /* On by default */ | |
1003 | int hasXkb = 0; | |
1004 | ||
1005 | a = dmxArgParse(dmxInput->name); | |
1006 | ||
1007 | for (i = 1; i < dmxArgC(a); i++) { | |
1008 | switch (hasXkb) { | |
1009 | case 1: | |
1010 | dmxInput->keycodes = xstrdup(dmxArgV(a, i)); | |
1011 | ++hasXkb; | |
1012 | break; | |
1013 | case 2: | |
1014 | dmxInput->symbols = xstrdup(dmxArgV(a, i)); | |
1015 | ++hasXkb; | |
1016 | break; | |
1017 | case 3: | |
1018 | dmxInput->geometry = xstrdup(dmxArgV(a, i)); | |
1019 | hasXkb = 0; | |
1020 | break; | |
1021 | case 0: | |
1022 | if (!strcmp(dmxArgV(a, i), "noxi")) | |
1023 | doXI = 0; | |
1024 | else if (!strcmp(dmxArgV(a, i), "xi")) | |
1025 | doXI = 1; | |
1026 | else if (!strcmp(dmxArgV(a, i), "console")) | |
1027 | forceConsole = 1; | |
1028 | else if (!strcmp(dmxArgV(a, i), "noconsole")) | |
1029 | forceConsole = 0; | |
1030 | else if (!strcmp(dmxArgV(a, i), "windows")) | |
1031 | doWindows = 1; | |
1032 | else if (!strcmp(dmxArgV(a, i), "nowindows")) | |
1033 | doWindows = 0; | |
1034 | else if (!strcmp(dmxArgV(a, i), "xkb")) | |
1035 | hasXkb = 1; | |
1036 | else { | |
1037 | dmxLog(dmxFatal, "Unknown input argument: %s\n", dmxArgV(a, i)); | |
1038 | } | |
1039 | } | |
1040 | } | |
1041 | ||
1042 | name = dmxArgV(a, 0); | |
1043 | ||
1044 | if (!strcmp(name, "local")) { | |
1045 | dmxPopulateLocal(dmxInput, a); | |
1046 | } | |
1047 | else if (!strcmp(name, "dummy")) { | |
1048 | dmxInputCopyLocal(dmxInput, &DMXDummyMou); | |
1049 | dmxInputCopyLocal(dmxInput, &DMXDummyKbd); | |
1050 | dmxLogInput(dmxInput, "Using dummy input\n"); | |
1051 | } | |
1052 | else { | |
1053 | int found; | |
1054 | ||
1055 | for (found = 0, i = 0; i < dmxNumScreens; i++) { | |
1056 | if (dmxPropertySameDisplay(&dmxScreens[i], name)) { | |
1057 | if (dmxScreens[i].shared) | |
1058 | dmxLog(dmxFatal, | |
1059 | "Cannot take input from shared backend (%s)\n", | |
1060 | name); | |
1061 | if (!dmxInput->core) { | |
1062 | dmxLog(dmxWarning, | |
1063 | "Cannot use core devices on a backend (%s)" | |
1064 | " as XInput devices\n", name); | |
1065 | } | |
1066 | else { | |
1067 | char *pt; | |
1068 | ||
1069 | for (pt = (char *) dmxInput->name; pt && *pt; pt++) | |
1070 | if (*pt == ',') | |
1071 | *pt = '\0'; | |
1072 | dmxInputCopyLocal(dmxInput, &DMXBackendMou); | |
1073 | dmxInputCopyLocal(dmxInput, &DMXBackendKbd); | |
1074 | dmxInput->scrnIdx = i; | |
1075 | dmxLogInput(dmxInput, | |
1076 | "Using backend input from %s\n", name); | |
1077 | } | |
1078 | ++found; | |
1079 | break; | |
1080 | } | |
1081 | } | |
1082 | if (!found || forceConsole) { | |
1083 | char *pt; | |
1084 | ||
1085 | if (found) | |
1086 | dmxInput->console = TRUE; | |
1087 | for (pt = (char *) dmxInput->name; pt && *pt; pt++) | |
1088 | if (*pt == ',') | |
1089 | *pt = '\0'; | |
1090 | dmxInputCopyLocal(dmxInput, &DMXConsoleMou); | |
1091 | dmxInputCopyLocal(dmxInput, &DMXConsoleKbd); | |
1092 | if (doWindows) { | |
1093 | dmxInput->windows = TRUE; | |
1094 | dmxInput->updateWindowInfo = dmxUpdateWindowInformation; | |
1095 | } | |
1096 | dmxLogInput(dmxInput, | |
1097 | "Using console input from %s (%s windows)\n", | |
1098 | name, doWindows ? "with" : "without"); | |
1099 | } | |
1100 | } | |
1101 | ||
1102 | dmxArgFree(a); | |
1103 | ||
1104 | /* Locate extensions we may be interested in */ | |
1105 | dmxInputScanForExtensions(dmxInput, doXI); | |
1106 | ||
1107 | for (i = 0; i < dmxInput->numDevs; i++) { | |
1108 | DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; | |
1109 | ||
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; | |
1116 | } | |
1117 | } | |
1118 | ||
1119 | dmxInput->processInputEvents = dmxProcessInputEvents; | |
1120 | dmxInput->detached = False; | |
1121 | ||
1122 | RegisterBlockAndWakeupHandlers(dmxBlockHandler, dmxWakeupHandler, | |
1123 | (void *) (uintptr_t) dmxInput->inputIdx); | |
1124 | } | |
1125 | ||
1126 | static void | |
1127 | dmxInputFreeLocal(DMXLocalInputInfoRec * local) | |
1128 | { | |
1129 | if (!local) | |
1130 | return; | |
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; | |
1143 | free(local); | |
1144 | } | |
1145 | ||
1146 | /** Free all of the memory associated with \a dmxInput */ | |
1147 | void | |
1148 | dmxInputFree(DMXInputInfo * dmxInput) | |
1149 | { | |
1150 | int i; | |
1151 | ||
1152 | if (!dmxInput) | |
1153 | return; | |
1154 | ||
1155 | free(dmxInput->keycodes); | |
1156 | free(dmxInput->symbols); | |
1157 | free(dmxInput->geometry); | |
1158 | ||
1159 | for (i = 0; i < dmxInput->numDevs; i++) { | |
1160 | dmxInputFreeLocal(dmxInput->devs[i]); | |
1161 | dmxInput->devs[i] = NULL; | |
1162 | } | |
1163 | free(dmxInput->devs); | |
1164 | dmxInput->devs = NULL; | |
1165 | dmxInput->numDevs = 0; | |
1166 | if (dmxInput->freename) | |
1167 | free(dmxInput->name); | |
1168 | dmxInput->name = NULL; | |
1169 | } | |
1170 | ||
1171 | /** Log information about all of the known devices using #dmxLog(). */ | |
1172 | void | |
1173 | dmxInputLogDevices(void) | |
1174 | { | |
1175 | int i, j; | |
1176 | ||
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)); | |
1184 | ||
1185 | for (i = 0; i < dmxInput->numDevs; i++) { | |
1186 | DeviceIntPtr pDevice = dmxInput->devs[i]->pDevice; | |
1187 | ||
1188 | if (pDevice) { | |
1189 | dmxLog(dmxInfo, " %2d%c %-20.20s", | |
1190 | pDevice->id, | |
1191 | dmxInput->detached ? 'D' : ' ', pDevice->name); | |
1192 | if (pDevice->key) | |
1193 | dmxLogCont(dmxInfo, " key"); | |
1194 | if (pDevice->valuator) | |
1195 | dmxLogCont(dmxInfo, " val"); | |
1196 | if (pDevice->button) | |
1197 | dmxLogCont(dmxInfo, " btn"); | |
1198 | if (pDevice->focus) | |
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"); | |
1208 | if (pDevice->bell) | |
1209 | dmxLogCont(dmxInfo, " fb/bel"); | |
1210 | if (pDevice->leds) | |
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)"); | |
1217 | ||
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 | |
1226 | ? "core" | |
1227 | : (dmxInput->devs[i]->sendsCore | |
1228 | ? "extension (sends core events)" : "extension")); | |
1229 | } | |
1230 | } | |
1231 | } | |
1232 | } | |
1233 | ||
1234 | /** Detach an input */ | |
1235 | int | |
1236 | dmxInputDetach(DMXInputInfo * dmxInput) | |
1237 | { | |
1238 | int i; | |
1239 | ||
1240 | if (dmxInput->detached) | |
1241 | return BadAccess; | |
1242 | ||
1243 | for (i = 0; i < dmxInput->numDevs; i++) { | |
1244 | DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; | |
1245 | ||
1246 | dmxLogInput(dmxInput, "Detaching device id %d: %s%s\n", | |
1247 | dmxLocal->pDevice->id, | |
1248 | dmxLocal->pDevice->name, | |
1249 | dmxLocal->isCore | |
1250 | ? " [core]" | |
1251 | : (dmxLocal->sendsCore ? " [sends core events]" : "")); | |
1252 | DisableDevice(dmxLocal->pDevice, TRUE); | |
1253 | } | |
1254 | dmxInput->detached = True; | |
1255 | dmxInputLogDevices(); | |
1256 | return 0; | |
1257 | } | |
1258 | ||
1259 | /** Search for input associated with \a dmxScreen, and detach. */ | |
1260 | void | |
1261 | dmxInputDetachAll(DMXScreenInfo * dmxScreen) | |
1262 | { | |
1263 | int i; | |
1264 | ||
1265 | for (i = 0; i < dmxNumInputs; i++) { | |
1266 | DMXInputInfo *dmxInput = &dmxInputs[i]; | |
1267 | ||
1268 | if (dmxInput->scrnIdx == dmxScreen->index) | |
1269 | dmxInputDetach(dmxInput); | |
1270 | } | |
1271 | } | |
1272 | ||
1273 | /** Search for input associated with \a deviceId, and detach. */ | |
1274 | int | |
1275 | dmxInputDetachId(int id) | |
1276 | { | |
1277 | DMXInputInfo *dmxInput = dmxInputLocateId(id); | |
1278 | ||
1279 | if (!dmxInput) | |
1280 | return BadValue; | |
1281 | ||
1282 | return dmxInputDetach(dmxInput); | |
1283 | } | |
1284 | ||
1285 | DMXInputInfo * | |
1286 | dmxInputLocateId(int id) | |
1287 | { | |
1288 | int i, j; | |
1289 | ||
1290 | for (i = 0; i < dmxNumInputs; i++) { | |
1291 | DMXInputInfo *dmxInput = &dmxInputs[i]; | |
1292 | ||
1293 | for (j = 0; j < dmxInput->numDevs; j++) { | |
1294 | DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; | |
1295 | ||
1296 | if (dmxLocal->pDevice->id == id) | |
1297 | return dmxInput; | |
1298 | } | |
1299 | } | |
1300 | return NULL; | |
1301 | } | |
1302 | ||
1303 | static int | |
1304 | dmxInputAttachNew(DMXInputInfo * dmxInput, int *id) | |
1305 | { | |
1306 | dmxInputInit(dmxInput); | |
1307 | InitAndStartDevices(); | |
1308 | if (id && dmxInput->devs) | |
1309 | *id = dmxInput->devs[0]->pDevice->id; | |
1310 | dmxInputLogDevices(); | |
1311 | return 0; | |
1312 | } | |
1313 | ||
1314 | static int | |
1315 | dmxInputAttachOld(DMXInputInfo * dmxInput, int *id) | |
1316 | { | |
1317 | int i; | |
1318 | ||
1319 | dmxInput->detached = False; | |
1320 | for (i = 0; i < dmxInput->numDevs; i++) { | |
1321 | DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; | |
1322 | ||
1323 | if (id) | |
1324 | *id = dmxLocal->pDevice->id; | |
1325 | dmxLogInput(dmxInput, | |
1326 | "Attaching device id %d: %s%s\n", | |
1327 | dmxLocal->pDevice->id, | |
1328 | dmxLocal->pDevice->name, | |
1329 | dmxLocal->isCore | |
1330 | ? " [core]" | |
1331 | : (dmxLocal->sendsCore ? " [sends core events]" : "")); | |
1332 | EnableDevice(dmxLocal->pDevice, TRUE); | |
1333 | } | |
1334 | dmxInputLogDevices(); | |
1335 | return 0; | |
1336 | } | |
1337 | ||
1338 | int | |
1339 | dmxInputAttachConsole(const char *name, int isCore, int *id) | |
1340 | { | |
1341 | DMXInputInfo *dmxInput; | |
1342 | int i; | |
1343 | ||
1344 | for (i = 0; i < dmxNumInputs; i++) { | |
1345 | dmxInput = &dmxInputs[i]; | |
1346 | if (dmxInput->scrnIdx == -1 | |
1347 | && dmxInput->detached && !strcmp(dmxInput->name, name)) { | |
1348 | /* Found match */ | |
1349 | dmxLogInput(dmxInput, "Reattaching detached console input\n"); | |
1350 | return dmxInputAttachOld(dmxInput, id); | |
1351 | } | |
1352 | } | |
1353 | ||
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); | |
1359 | } | |
1360 | ||
1361 | int | |
1362 | dmxInputAttachBackend(int physicalScreen, int isCore, int *id) | |
1363 | { | |
1364 | DMXInputInfo *dmxInput; | |
1365 | DMXScreenInfo *dmxScreen; | |
1366 | int i; | |
1367 | ||
1368 | if (physicalScreen < 0 || physicalScreen >= dmxNumScreens) | |
1369 | return BadValue; | |
1370 | for (i = 0; i < dmxNumInputs; i++) { | |
1371 | dmxInput = &dmxInputs[i]; | |
1372 | if (dmxInput->scrnIdx != -1 && dmxInput->scrnIdx == physicalScreen) { | |
1373 | /* Found match */ | |
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); | |
1381 | } | |
1382 | } | |
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); | |
1390 | } |