3
* Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
7
* Permission is hereby granted, free of charge, to any person obtaining
8
* a copy of this software and associated documentation files (the
9
* "Software"), to deal in the Software without restriction, including
10
* without limitation on the rights to use, copy, modify, merge,
11
* publish, distribute, sublicense, and/or sell copies of the Software,
12
* and to permit persons to whom the Software is furnished to do so,
13
* subject to the following conditions:
15
* The above copyright notice and this permission notice (including the
16
* next paragraph) shall be included in all copies or substantial
17
* portions of the Software.
19
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
23
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
* Rickard E. (Rik) Faith <faith@redhat.com>
36
* This file provides generic input support. Functions here set up
37
* input and lead to the calling of low-level device drivers for
40
#ifdef HAVE_DMX_CONFIG_H
41
#include <dmx-config.h>
44
#define DMX_WINDOW_DEBUG 0
46
#include "dmxinputinit.h"
47
#include "dmxextension.h" /* For dmxInputCount */
50
#include "dmxbackend.h"
51
#include "dmxconsole.h"
52
#include "dmxcommon.h"
53
#include "dmxevents.h"
54
#include "dmxmotion.h"
57
#include "config/dmxconfig.h"
58
#include "dmxcursor.h"
60
#include "lnx-keyboard.h"
63
#include "usb-keyboard.h"
64
#include "usb-mouse.h"
65
#include "usb-other.h"
66
#include "usb-common.h"
73
#include "mipointer.h"
74
#include "windowstr.h"
77
#include <X11/extensions/XI.h>
78
#include <X11/extensions/XIproto.h>
80
#define EXTENSION_PROC_ARGS void *
92
DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard;
94
static DMXLocalInputInfoRec DMXDummyMou = {
95
"dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
96
NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo
99
static DMXLocalInputInfoRec DMXDummyKbd = {
100
"dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
101
NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo
104
static DMXLocalInputInfoRec DMXBackendMou = {
105
"backend-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_BACKEND, 2,
106
dmxBackendCreatePrivate, dmxBackendDestroyPrivate,
107
dmxBackendInit, NULL, dmxBackendLateReInit, dmxBackendMouGetInfo,
108
dmxCommonMouOn, dmxCommonMouOff, dmxBackendUpdatePosition,
110
dmxBackendCollectEvents, dmxBackendProcessInput, dmxBackendFunctions, NULL,
114
static DMXLocalInputInfoRec DMXBackendKbd = {
115
"backend-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_BACKEND,
116
1, /* With backend-mou or console-mou */
117
dmxCommonCopyPrivate, NULL,
118
dmxBackendInit, NULL, NULL, dmxBackendKbdGetInfo,
119
dmxCommonKbdOn, dmxCommonKbdOff, NULL,
121
NULL, NULL, NULL, NULL,
122
NULL, dmxCommonKbdCtrl, dmxCommonKbdBell
125
static DMXLocalInputInfoRec DMXConsoleMou = {
126
"console-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_CONSOLE, 2,
127
dmxConsoleCreatePrivate, dmxConsoleDestroyPrivate,
128
dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleMouGetInfo,
129
dmxCommonMouOn, dmxCommonMouOff, dmxConsoleUpdatePosition,
131
dmxConsoleCollectEvents, NULL, dmxConsoleFunctions, dmxConsoleUpdateInfo,
135
static DMXLocalInputInfoRec DMXConsoleKbd = {
136
"console-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_CONSOLE,
137
1, /* With backend-mou or console-mou */
138
dmxCommonCopyPrivate, NULL,
139
dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleKbdGetInfo,
140
dmxCommonKbdOn, dmxCommonKbdOff, NULL,
142
NULL, NULL, NULL, NULL,
143
NULL, dmxCommonKbdCtrl, dmxCommonKbdBell
146
static DMXLocalInputInfoRec DMXCommonOth = {
147
"common-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_COMMON, 1,
148
dmxCommonCopyPrivate, NULL,
149
NULL, NULL, NULL, dmxCommonOthGetInfo,
150
dmxCommonOthOn, dmxCommonOthOff
154
static DMXLocalInputInfoRec DMXLocalDevices[] = {
155
/* Dummy drivers that can compile on any OS */
157
/* Linux-specific drivers */
159
"kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
160
kbdLinuxCreatePrivate, kbdLinuxDestroyPrivate,
161
kbdLinuxInit, NULL, NULL, kbdLinuxGetInfo,
162
kbdLinuxOn, kbdLinuxOff, NULL,
163
kbdLinuxVTPreSwitch, kbdLinuxVTPostSwitch, kbdLinuxVTSwitch,
164
kbdLinuxRead, NULL, NULL, NULL,
165
NULL, kbdLinuxCtrl, kbdLinuxBell
168
"ms", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
169
msLinuxCreatePrivate, msLinuxDestroyPrivate,
170
msLinuxInit, NULL, NULL, msLinuxGetInfo,
171
msLinuxOn, msLinuxOff, NULL,
172
msLinuxVTPreSwitch, msLinuxVTPostSwitch, NULL,
176
"ps2", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
177
ps2LinuxCreatePrivate, ps2LinuxDestroyPrivate,
178
ps2LinuxInit, NULL, NULL, ps2LinuxGetInfo,
179
ps2LinuxOn, ps2LinuxOff, NULL,
180
ps2LinuxVTPreSwitch, ps2LinuxVTPostSwitch, NULL,
185
/* USB drivers, currently only for
186
Linux, but relatively easy to port to
189
"usb-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
190
usbCreatePrivate, usbDestroyPrivate,
191
kbdUSBInit, NULL, NULL, kbdUSBGetInfo,
192
kbdUSBOn, usbOff, NULL,
194
kbdUSBRead, NULL, NULL, NULL,
198
"usb-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
199
usbCreatePrivate, usbDestroyPrivate,
200
mouUSBInit, NULL, NULL, mouUSBGetInfo,
201
mouUSBOn, usbOff, NULL,
206
"usb-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_LOCAL, 1,
207
usbCreatePrivate, usbDestroyPrivate,
208
othUSBInit, NULL, NULL, othUSBGetInfo,
209
othUSBOn, usbOff, NULL,
215
"dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
216
NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo
219
"dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
220
NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo
222
{ NULL } /* Must be last */
225
static void _dmxChangePointerControl(DMXLocalInputInfoPtr dmxLocal,
228
if (!dmxLocal) return;
229
dmxLocal->mctrl = *ctrl;
230
if (dmxLocal->mCtrl) dmxLocal->mCtrl(&dmxLocal->pDevice->public, ctrl);
233
/** Change the pointer control information for the \a pDevice. If the
234
* device sends core events, then also change the control information
235
* for all of the pointer devices that send core events. */
236
void dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl *ctrl)
238
GETDMXLOCALFROMPDEVICE;
241
if (dmxLocal->sendsCore) { /* Do for all core devices */
242
for (i = 0; i < dmxNumInputs; i++) {
243
DMXInputInfo *dmxInput = &dmxInputs[i];
244
if (dmxInput->detached) continue;
245
for (j = 0; j < dmxInput->numDevs; j++)
246
if (dmxInput->devs[j]->sendsCore)
247
_dmxChangePointerControl(dmxInput->devs[j], ctrl);
249
} else { /* Do for this device only */
250
_dmxChangePointerControl(dmxLocal, ctrl);
254
static void _dmxKeyboardKbdCtrlProc(DMXLocalInputInfoPtr dmxLocal,
257
dmxLocal->kctrl = *ctrl;
258
if (dmxLocal->kCtrl) {
259
dmxLocal->kCtrl(&dmxLocal->pDevice->public, ctrl);
261
if (!noXkbExtension && dmxLocal->pDevice->kbdfeed) {
262
XkbEventCauseRec cause;
263
XkbSetCauseUnknown(&cause);
264
/* Generate XKB events, as necessary */
265
XkbUpdateIndicators(dmxLocal->pDevice, XkbAllIndicatorsMask, False,
273
/** Change the keyboard control information for the \a pDevice. If the
274
* device sends core events, then also change the control information
275
* for all of the keyboard devices that send core events. */
276
void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl)
278
GETDMXLOCALFROMPDEVICE;
281
if (dmxLocal->sendsCore) { /* Do for all core devices */
282
for (i = 0; i < dmxNumInputs; i++) {
283
DMXInputInfo *dmxInput = &dmxInputs[i];
284
if (dmxInput->detached) continue;
285
for (j = 0; j < dmxInput->numDevs; j++)
286
if (dmxInput->devs[j]->sendsCore)
287
_dmxKeyboardKbdCtrlProc(dmxInput->devs[j], ctrl);
289
} else { /* Do for this device only */
290
_dmxKeyboardKbdCtrlProc(dmxLocal, ctrl);
294
static void _dmxKeyboardBellProc(DMXLocalInputInfoPtr dmxLocal, int percent)
296
if (dmxLocal->kBell) dmxLocal->kBell(&dmxLocal->pDevice->public,
298
dmxLocal->kctrl.bell,
299
dmxLocal->kctrl.bell_pitch,
300
dmxLocal->kctrl.bell_duration);
303
/** Sound the bell on the device. If the device send core events, then
304
* sound the bell on all of the devices that send core events. */
305
void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice,
306
pointer ctrl, int unknown)
308
GETDMXLOCALFROMPDEVICE;
311
if (dmxLocal->sendsCore) { /* Do for all core devices */
312
for (i = 0; i < dmxNumInputs; i++) {
313
DMXInputInfo *dmxInput = &dmxInputs[i];
314
if (dmxInput->detached) continue;
315
for (j = 0; j < dmxInput->numDevs; j++)
316
if (dmxInput->devs[j]->sendsCore)
317
_dmxKeyboardBellProc(dmxInput->devs[j], percent);
319
} else { /* Do for this device only */
320
_dmxKeyboardBellProc(dmxLocal, percent);
325
static void dmxKeyboardFreeNames(XkbComponentNamesPtr names)
327
if (names->keymap) XFree(names->keymap);
328
if (names->keycodes) XFree(names->keycodes);
329
if (names->types) XFree(names->types);
330
if (names->compat) XFree(names->compat);
331
if (names->symbols) XFree(names->symbols);
332
if (names->geometry) XFree(names->geometry);
337
static int dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo *info)
340
GETDMXINPUTFROMPDEVICE;
342
DevicePtr pDev = &pDevice->public;
346
if (noXkbExtension) {
348
if (!InitKeyboardDeviceStruct(pDev, &info->keySyms, info->modMap,
350
dmxKeyboardKbdCtrlProc))
351
return BadImplementation;
354
XkbSetRulesDflts(dmxConfigGetXkbRules(),
355
dmxConfigGetXkbModel(),
356
dmxConfigGetXkbLayout(),
357
dmxConfigGetXkbVariant(),
358
dmxConfigGetXkbOptions());
359
if (XkbInitialMap) { /* Set with -xkbmap */
360
dmxLogInput(dmxInput,
361
"XKEYBOARD: From command line: %s\n", XkbInitialMap);
362
if ((info->names.keymap = strchr(XkbInitialMap, '/')))
363
++info->names.keymap;
365
info->names.keymap = XkbInitialMap;
366
info->names.keycodes = NULL;
367
info->names.types = NULL;
368
info->names.compat = NULL;
369
info->names.symbols = NULL;
370
info->names.geometry = NULL;
372
if (!info->force && (dmxInput->keycodes
374
|| dmxInput->geometry)) {
375
if (info->freenames) dmxKeyboardFreeNames(&info->names);
377
info->names.keycodes = dmxInput->keycodes;
378
info->names.types = NULL;
379
info->names.compat = NULL;
380
info->names.symbols = dmxInput->symbols;
381
info->names.geometry = dmxInput->geometry;
383
dmxLogInput(dmxInput, "XKEYBOARD: From command line: %s",
384
info->names.keycodes);
385
if (info->names.symbols && *info->names.symbols)
386
dmxLogInputCont(dmxInput, " %s", info->names.symbols);
387
if (info->names.geometry && *info->names.geometry)
388
dmxLogInputCont(dmxInput, " %s", info->names.geometry);
389
dmxLogInputCont(dmxInput, "\n");
390
} else if (info->names.keycodes) {
391
dmxLogInput(dmxInput, "XKEYBOARD: From device: %s",
392
info->names.keycodes);
393
if (info->names.symbols && *info->names.symbols)
394
dmxLogInputCont(dmxInput, " %s", info->names.symbols);
395
if (info->names.geometry && *info->names.geometry)
396
dmxLogInputCont(dmxInput, " %s", info->names.geometry);
397
dmxLogInputCont(dmxInput, "\n");
399
dmxLogInput(dmxInput, "XKEYBOARD: Defaults: %s %s %s %s %s\n",
400
dmxConfigGetXkbRules(),
401
dmxConfigGetXkbLayout(),
402
dmxConfigGetXkbModel(),
403
dmxConfigGetXkbVariant()
404
? dmxConfigGetXkbVariant() : "",
405
dmxConfigGetXkbOptions()
406
? dmxConfigGetXkbOptions() : "");
409
XkbInitKeyboardDeviceStruct(pDevice,
414
dmxKeyboardKbdCtrlProc);
416
if (info->freenames) dmxKeyboardFreeNames(&info->names);
423
static int dmxDeviceOnOff(DeviceIntPtr pDevice, int what)
425
GETDMXINPUTFROMPDEVICE;
427
DMXLocalInitInfo info;
432
if (!dmxLocal) return BadImplementation;
433
if (dmxInput->detached) return Success;
435
memset(&info, 0, sizeof(info));
438
if (dmxLocal->init) dmxLocal->init(pDev);
439
if (dmxLocal->get_info) dmxLocal->get_info(pDev, &info);
440
if (info.keyboard) { /* XKEYBOARD makes this a special case */
441
dmxKeyboardOn(pDevice, &info);
445
InitKeyClassDeviceStruct(pDevice, &info.keySyms, info.modMap);
447
if (info.buttonClass) {
448
InitButtonClassDeviceStruct(pDevice, info.numButtons, info.map);
450
if (info.valuatorClass) {
451
if (info.numRelAxes && dmxLocal->sendsCore) {
452
InitValuatorClassDeviceStruct(pDevice, info.numRelAxes,
453
miPointerGetMotionEvents,
454
miPointerGetMotionBufferSize(),
457
for (i = 0; i < info.numRelAxes; i++)
458
InitValuatorAxisStruct(pDevice, i, info.minval[0],
459
info.maxval[0], info.res[0],
460
info.minres[0], info.maxres[0]);
462
} else if (info.numRelAxes) {
463
InitValuatorClassDeviceStruct(pDevice, info.numRelAxes,
464
dmxPointerGetMotionEvents,
465
dmxPointerGetMotionBufferSize(),
468
for (i = 0; i < info.numRelAxes; i++)
469
InitValuatorAxisStruct(pDevice, i, info.minval[0],
470
info.maxval[0], info.res[0],
471
info.minres[0], info.maxres[0]);
473
} else if (info.numAbsAxes) {
474
InitValuatorClassDeviceStruct(pDevice, info.numAbsAxes,
475
dmxPointerGetMotionEvents,
476
dmxPointerGetMotionBufferSize(),
479
for (i = 0; i < info.numAbsAxes; i++)
480
InitValuatorAxisStruct(pDevice, i+info.numRelAxes,
481
info.minval[i+1], info.maxval[i+1],
482
info.res[i+1], info.minres[i+1],
487
if (info.focusClass) InitFocusClassDeviceStruct(pDevice);
489
if (info.proximityClass) InitProximityClassDeviceStruct(pDevice);
491
if (info.ptrFeedbackClass)
492
InitPtrFeedbackClassDeviceStruct(pDevice, dmxChangePointerControl);
493
if (info.kbdFeedbackClass)
494
InitKbdFeedbackClassDeviceStruct(pDevice, dmxKeyboardBellProc,
495
dmxKeyboardKbdCtrlProc);
496
if (info.intFeedbackClass || info.strFeedbackClass)
498
"Integer and string feedback not supported for %s\n",
500
if (!info.keyboard && (info.ledFeedbackClass || info.belFeedbackClass))
502
"Led and bel feedback not supported for non-keyboard %s\n",
507
if (dmxLocal->on && (fd = dmxLocal->on(pDev)) >= 0)
508
dmxSigioRegister(dmxInput, fd);
514
/* This can get called twice consecutively: once for a
515
* detached screen (DEVICE_OFF), and then again at server
516
* generation time (DEVICE_CLOSE). */
518
dmxSigioUnregister(dmxInput);
519
if (dmxLocal->off) dmxLocal->off(pDev);
524
if (info.keySyms.map && info.freemap) {
525
XFree(info.keySyms.map);
526
info.keySyms.map = NULL;
529
if (info.xkb) XkbFreeKeyboard(info.xkb, 0, True);
534
static void dmxProcessInputEvents(DMXInputInfo *dmxInput)
538
dmxeqProcessInputEvents();
540
if (dmxInput->detached) return;
541
for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding)
542
if (dmxInput->devs[i]->process_input)
543
dmxInput->devs[i]->process_input(dmxInput->devs[i]->private);
546
static void dmxUpdateWindowInformation(DMXInputInfo *dmxInput,
553
if (!noPanoramiXExtension && pWindow && pWindow->parent != WindowTable[0])
558
const char *name = "Unknown";
560
case DMX_UPDATE_REALIZE: name = "Realize"; break;
561
case DMX_UPDATE_UNREALIZE: name = "Unrealize"; break;
562
case DMX_UPDATE_RESTACK: name = "Restack"; break;
563
case DMX_UPDATE_COPY: name = "Copy"; break;
564
case DMX_UPDATE_RESIZE: name = "Resize"; break;
565
case DMX_UPDATE_REPARENT: name = "Repaint"; break;
567
dmxLog(dmxDebug, "Window %p changed: %s\n", pWindow, name);
571
if (dmxInput->detached) return;
572
for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding)
573
if (dmxInput->devs[i]->update_info)
574
dmxInput->devs[i]->update_info(dmxInput->devs[i]->private,
578
static void dmxCollectAll(DMXInputInfo *dmxInput)
582
if (dmxInput->detached) return;
583
for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding)
584
if (dmxInput->devs[i]->collect_events)
585
dmxInput->devs[i]->collect_events(&dmxInput->devs[i]
589
dmxCheckSpecialKeys, DMX_BLOCK);
592
static void dmxBlockHandler(pointer blockData, OSTimePtr pTimeout,
595
DMXInputInfo *dmxInput = &dmxInputs[(int)blockData];
596
static unsigned long generation = 0;
598
if (generation != serverGeneration) {
599
generation = serverGeneration;
600
dmxCollectAll(dmxInput);
604
static void dmxSwitchReturn(pointer p)
606
DMXInputInfo *dmxInput = p;
609
dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched);
611
if (!dmxInput->vt_switched)
612
dmxLog(dmxFatal, "dmxSwitchReturn called, but not switched\n");
613
dmxSigioEnableInput();
614
for (i = 0; i < dmxInput->numDevs; i++)
615
if (dmxInput->devs[i]->vt_post_switch)
616
dmxInput->devs[i]->vt_post_switch(dmxInput->devs[i]->private);
617
dmxInput->vt_switched = 0;
620
static void dmxWakeupHandler(pointer blockData, int result, pointer pReadMask)
622
DMXInputInfo *dmxInput = &dmxInputs[(int)blockData];
625
if (dmxInput->vt_switch_pending) {
626
dmxLog(dmxInfo, "Switching to VT %d\n", dmxInput->vt_switch_pending);
627
for (i = 0; i < dmxInput->numDevs; i++)
628
if (dmxInput->devs[i]->vt_pre_switch)
629
dmxInput->devs[i]->vt_pre_switch(dmxInput->devs[i]->private);
630
dmxInput->vt_switched = dmxInput->vt_switch_pending;
631
dmxInput->vt_switch_pending = 0;
632
for (i = 0; i < dmxInput->numDevs; i++) {
633
if (dmxInput->devs[i]->vt_switch) {
634
dmxSigioDisableInput();
635
if (!dmxInput->devs[i]->vt_switch(dmxInput->devs[i]->private,
636
dmxInput->vt_switched,
639
dmxSwitchReturn(dmxInput);
640
break; /* Only call one vt_switch routine */
644
dmxCollectAll(dmxInput);
647
static char *dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal)
652
static unsigned long dmxGeneration = 0;
654
char * buf = xalloc(LEN);
656
if (dmxGeneration != serverGeneration) {
658
dmxGeneration = serverGeneration;
661
switch (dmxLocal->type) {
662
case DMX_LOCAL_KEYBOARD: XmuSnprintf(buf, LEN, "Keyboard%d", k++); break;
663
case DMX_LOCAL_MOUSE: XmuSnprintf(buf, LEN, "Mouse%d", m++); break;
664
default: XmuSnprintf(buf, LEN, "Other%d", o++); break;
670
static DeviceIntPtr dmxAddDevice(DMXLocalInputInfoPtr dmxLocal)
672
DeviceIntPtr pDevice;
674
const char *name = NULL;
675
void (*registerProcPtr)(DeviceIntPtr) = NULL;
677
DMXInputInfo *dmxInput;
679
if (!dmxLocal) return NULL;
680
dmxInput = &dmxInputs[dmxLocal->inputIdx];
682
if (dmxLocal->sendsCore) {
683
if (dmxLocal->type == DMX_LOCAL_KEYBOARD && !dmxLocalCoreKeyboard) {
684
dmxLocal->isCore = 1;
685
dmxLocalCoreKeyboard = dmxLocal;
687
registerProcPtr = _RegisterKeyboardDevice;
689
if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) {
690
dmxLocal->isCore = 1;
691
dmxLocalCorePointer = dmxLocal;
693
registerProcPtr = _RegisterPointerDevice;
700
registerProcPtr = RegisterOtherDevice;
705
"Server not build with XINPUT support (cannot add %s)\n",
709
if (!name || !registerProcPtr)
710
dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name);
712
pDevice = AddInputDevice(dmxDeviceOnOff, TRUE);
714
dmxLog(dmxError, "Too many devices -- cannot add device %s\n",
718
pDevice->public.devicePrivate = dmxLocal;
719
dmxLocal->pDevice = pDevice;
721
devname = dmxMakeUniqueDeviceName(dmxLocal);
722
atom = MakeAtom((char *)devname, strlen(devname), TRUE);
723
pDevice->type = atom;
724
pDevice->name = devname;
726
registerProcPtr(pDevice);
728
if (dmxLocal->isCore && dmxLocal->type == DMX_LOCAL_MOUSE)
729
miRegisterPointerDevice(screenInfo.screens[0], pDevice);
731
if (dmxLocal->create_private)
732
dmxLocal->private = dmxLocal->create_private(pDevice);
734
dmxLogInput(dmxInput, "Added %s as %s device called %s%s\n",
735
dmxLocal->name, name, devname,
738
: (dmxLocal->sendsCore
739
? " [sends core events]"
745
static DMXLocalInputInfoPtr dmxLookupLocal(const char *name)
747
DMXLocalInputInfoPtr pt;
749
for (pt = &DMXLocalDevices[0]; pt->name; ++pt)
750
if (!strcmp(pt->name, name)) return pt; /* search for device name */
754
/** Copy the local input information from \a s into a new \a devs slot
756
DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput,
757
DMXLocalInputInfoPtr s)
759
DMXLocalInputInfoPtr dmxLocal = xalloc(sizeof(*dmxLocal));
762
dmxLog(dmxFatal, "DMXLocalInputInfoPtr: out of memory\n");
764
memcpy(dmxLocal, s, sizeof(*dmxLocal));
765
dmxLocal->inputIdx = dmxInput->inputIdx;
766
dmxLocal->sendsCore = dmxInput->core;
767
dmxLocal->savedSendsCore = dmxInput->core;
768
dmxLocal->deviceId = -1;
771
dmxInput->devs = xrealloc(dmxInput->devs,
772
dmxInput->numDevs * sizeof(*dmxInput->devs));
773
dmxInput->devs[dmxInput->numDevs-1] = dmxLocal;
778
static void dmxPopulateLocal(DMXInputInfo *dmxInput, dmxArg a)
782
DMXLocalInputInfoRec *pt;
784
for (i = 1; i < dmxArgC(a); i++) {
785
const char *name = dmxArgV(a, i);
786
if ((pt = dmxLookupLocal(name))) {
787
dmxInputCopyLocal(dmxInput, pt);
791
"Could not find a driver called %s\n", name);
796
dmxLog(dmxInfo, "Available local device drivers:\n");
797
for (pt = &DMXLocalDevices[0]; pt->name; ++pt) {
800
case DMX_LOCAL_KEYBOARD: type = "keyboard"; break;
801
case DMX_LOCAL_MOUSE: type = "pointer"; break;
802
default: type = "unknown"; break;
804
dmxLog(dmxInfo, " %s (%s)\n", pt->name, type);
806
dmxLog(dmxFatal, "Must have valid local device driver\n");
810
int dmxInputExtensionErrorHandler(Display *dsp, char *name, char *reason)
815
static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI)
817
XExtensionVersion *ext;
818
XDeviceInfo *devices;
822
DMXLocalInputInfoPtr dmxLocal;
823
int (*handler)(Display *, char *, char *);
825
if (!(display = XOpenDisplay(dmxInput->name))) return;
827
/* Print out information about the XInput Extension. */
828
handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler);
829
ext = XGetExtensionVersion(display, INAME);
830
XSetExtensionErrorHandler(handler);
832
if (!ext || ext == (XExtensionVersion *)NoSuchExtension) {
833
dmxLogInput(dmxInput, "%s is not available\n", INAME);
835
dmxLogInput(dmxInput, "Locating devices on %s (%s version %d.%d)\n",
836
dmxInput->name, INAME,
837
ext->major_version, ext->minor_version);
838
devices = XListInputDevices(display, &num);
843
/* Print a list of all devices */
844
for (i = 0; i < num; i++) {
845
const char *use = "Unknown";
846
switch (devices[i].use) {
847
case IsXPointer: use = "XPointer"; break;
848
case IsXKeyboard: use = "XKeyboard"; break;
849
case IsXExtensionDevice: use = "XExtensionDevice"; break;
851
dmxLogInput(dmxInput, " %2d %-10.10s %-16.16s\n",
853
devices[i].name ? devices[i].name : "",
857
/* Search for extensions */
858
for (i = 0; i < num; i++) {
859
switch (devices[i].use) {
861
for (j = 0; j < dmxInput->numDevs; j++) {
862
DMXLocalInputInfoPtr dmxL = dmxInput->devs[j];
863
if (dmxL->type == DMX_LOCAL_KEYBOARD
864
&& dmxL->deviceId < 0) {
865
dmxL->deviceId = devices[i].id;
866
dmxL->deviceName = (devices[i].name
867
? xstrdup(devices[i].name)
873
for (j = 0; j < dmxInput->numDevs; j++) {
874
DMXLocalInputInfoPtr dmxL = dmxInput->devs[j];
875
if (dmxL->type == DMX_LOCAL_MOUSE && dmxL->deviceId < 0) {
876
dmxL->deviceId = devices[i].id;
877
dmxL->deviceName = (devices[i].name
878
? xstrdup(devices[i].name)
883
case IsXExtensionDevice:
885
if (!dmxInput->numDevs) {
887
"Cannot use remote (%s) XInput devices if"
888
" not also using core devices\n",
891
dmxLocal = dmxInputCopyLocal(dmxInput,
893
dmxLocal->isCore = FALSE;
894
dmxLocal->sendsCore = FALSE;
895
dmxLocal->deviceId = devices[i].id;
896
dmxLocal->deviceName = (devices[i].name
897
? xstrdup(devices[i].name)
904
XFreeDeviceList(devices);
906
XCloseDisplay(display);
909
/** Re-initialize all the devices described in \a dmxInput. Called from
910
#dmxReconfig before the cursor is redisplayed. */
911
void dmxInputReInit(DMXInputInfo *dmxInput)
915
for (i = 0; i < dmxInput->numDevs; i++) {
916
DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
917
if (dmxLocal->reinit)
918
dmxLocal->reinit(&dmxLocal->pDevice->public);
922
/** Re-initialize all the devices described in \a dmxInput. Called from
923
#dmxReconfig after the cursor is redisplayed. */
924
void dmxInputLateReInit(DMXInputInfo *dmxInput)
928
for (i = 0; i < dmxInput->numDevs; i++) {
929
DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
930
if (dmxLocal->latereinit)
931
dmxLocal->latereinit(&dmxLocal->pDevice->public);
935
/** Initialize all of the devices described in \a dmxInput. */
936
void dmxInputInit(DMXInputInfo *dmxInput)
938
DeviceIntPtr pPointer = NULL, pKeyboard = NULL;
942
int doXI = 1; /* Include by default */
943
int forceConsole = 0;
944
int doWindows = 1; /* On by default */
947
a = dmxArgParse(dmxInput->name);
949
for (i = 1; i < dmxArgC(a); i++) {
952
dmxInput->keycodes = xstrdup(dmxArgV(a, i));
956
dmxInput->symbols = xstrdup(dmxArgV(a, i));
960
dmxInput->geometry = xstrdup(dmxArgV(a, i));
964
if (!strcmp(dmxArgV(a, i), "noxi")) doXI = 0;
965
else if (!strcmp(dmxArgV(a, i), "xi")) doXI = 1;
966
else if (!strcmp(dmxArgV(a, i), "console")) forceConsole = 1;
967
else if (!strcmp(dmxArgV(a, i), "noconsole")) forceConsole = 0;
968
else if (!strcmp(dmxArgV(a, i), "windows")) doWindows = 1;
969
else if (!strcmp(dmxArgV(a, i), "nowindows")) doWindows = 0;
970
else if (!strcmp(dmxArgV(a, i), "xkb")) hasXkb = 1;
973
"Unknown input argument: %s\n", dmxArgV(a, i));
978
name = dmxArgV(a, 0);
980
if (!strcmp(name, "local")) {
981
dmxPopulateLocal(dmxInput, a);
982
} else if (!strcmp(name, "dummy")) {
983
dmxInputCopyLocal(dmxInput, &DMXDummyMou);
984
dmxInputCopyLocal(dmxInput, &DMXDummyKbd);
985
dmxLogInput(dmxInput, "Using dummy input\n");
989
for (found = 0, i = 0; i < dmxNumScreens; i++) {
990
if (dmxPropertySameDisplay(&dmxScreens[i], name)) {
991
if (dmxScreens[i].shared)
993
"Cannot take input from shared backend (%s)\n",
995
if (!dmxInput->core) {
997
"Cannot use core devices on a backend (%s)"
998
" as XInput devices\n", name);
1001
for (pt = (char *)dmxInput->name; pt && *pt; pt++)
1002
if (*pt == ',') *pt = '\0';
1003
dmxInputCopyLocal(dmxInput, &DMXBackendMou);
1004
dmxInputCopyLocal(dmxInput, &DMXBackendKbd);
1005
dmxInput->scrnIdx = i;
1006
dmxLogInput(dmxInput,
1007
"Using backend input from %s\n", name);
1013
if (!found || forceConsole) {
1015
if (found) dmxInput->console = TRUE;
1016
for (pt = (char *)dmxInput->name; pt && *pt; pt++)
1017
if (*pt == ',') *pt = '\0';
1018
dmxInputCopyLocal(dmxInput, &DMXConsoleMou);
1019
dmxInputCopyLocal(dmxInput, &DMXConsoleKbd);
1021
dmxInput->windows = TRUE;
1022
dmxInput->updateWindowInfo = dmxUpdateWindowInformation;
1024
dmxLogInput(dmxInput,
1025
"Using console input from %s (%s windows)\n",
1026
name, doWindows ? "with" : "without");
1032
/* Locate extensions we may be interested in */
1033
dmxInputScanForExtensions(dmxInput, doXI);
1035
for (i = 0; i < dmxInput->numDevs; i++) {
1036
DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
1038
if (!dmxLocal->isCore)
1040
"This server was not compiled to support the XInput"
1041
" extension, but %s is not a core device.\n",
1044
dmxLocal->pDevice = dmxAddDevice(dmxLocal);
1045
if (dmxLocal->isCore) {
1046
if (dmxLocal->type == DMX_LOCAL_MOUSE)
1047
pPointer = dmxLocal->pDevice;
1048
if (dmxLocal->type == DMX_LOCAL_KEYBOARD)
1049
pKeyboard = dmxLocal->pDevice;
1053
if (pPointer && pKeyboard) {
1054
if (dmxeqInit(&pKeyboard->public, &pPointer->public))
1055
dmxLogInput(dmxInput, "Using %s and %s as true core devices\n",
1056
pKeyboard->name, pPointer->name);
1059
dmxInput->processInputEvents = dmxProcessInputEvents;
1060
dmxInput->detached = False;
1062
RegisterBlockAndWakeupHandlers(dmxBlockHandler,
1064
(void *)dmxInput->inputIdx);
1067
static void dmxInputFreeLocal(DMXLocalInputInfoRec *local)
1070
if (local->isCore && local->type == DMX_LOCAL_MOUSE)
1071
dmxLocalCorePointer = NULL;
1072
if (local->isCore && local->type == DMX_LOCAL_KEYBOARD)
1073
dmxLocalCoreKeyboard = NULL;
1074
if (local->destroy_private) local->destroy_private(local->private);
1075
if (local->history) xfree(local->history);
1076
if (local->valuators) xfree(local->valuators);
1077
if (local->deviceName) xfree(local->deviceName);
1078
local->private = NULL;
1079
local->history = NULL;
1080
local->deviceName = NULL;
1084
/** Free all of the memory associated with \a dmxInput */
1085
void dmxInputFree(DMXInputInfo *dmxInput)
1089
if (!dmxInput) return;
1091
if (dmxInput->keycodes) xfree(dmxInput->keycodes);
1092
if (dmxInput->symbols) xfree(dmxInput->symbols);
1093
if (dmxInput->geometry) xfree(dmxInput->geometry);
1095
for (i = 0; i < dmxInput->numDevs; i++) {
1096
dmxInputFreeLocal(dmxInput->devs[i]);
1097
dmxInput->devs[i] = NULL;
1099
xfree(dmxInput->devs);
1100
dmxInput->devs = NULL;
1101
dmxInput->numDevs = 0;
1102
if (dmxInput->freename) xfree(dmxInput->name);
1103
dmxInput->name = NULL;
1106
/** Log information about all of the known devices using #dmxLog(). */
1107
void dmxInputLogDevices(void)
1111
dmxLog(dmxInfo, "%d devices:\n", dmxGetInputCount());
1112
dmxLog(dmxInfo, " Id Name Classes\n");
1113
for (j = 0; j < dmxNumInputs; j++) {
1114
DMXInputInfo *dmxInput = &dmxInputs[j];
1115
const char *pt = strchr(dmxInput->name, ',');
1117
? (size_t)(pt-dmxInput->name)
1118
: strlen(dmxInput->name));
1120
for (i = 0; i < dmxInput->numDevs; i++) {
1121
DeviceIntPtr pDevice = dmxInput->devs[i]->pDevice;
1123
dmxLog(dmxInfo, " %2d%c %-20.20s",
1125
dmxInput->detached ? 'D' : ' ',
1127
if (pDevice->key) dmxLogCont(dmxInfo, " key");
1128
if (pDevice->valuator) dmxLogCont(dmxInfo, " val");
1129
if (pDevice->button) dmxLogCont(dmxInfo, " btn");
1130
if (pDevice->focus) dmxLogCont(dmxInfo, " foc");
1131
if (pDevice->kbdfeed) dmxLogCont(dmxInfo, " fb/kbd");
1132
if (pDevice->ptrfeed) dmxLogCont(dmxInfo, " fb/ptr");
1133
if (pDevice->intfeed) dmxLogCont(dmxInfo, " fb/int");
1134
if (pDevice->stringfeed) dmxLogCont(dmxInfo, " fb/str");
1135
if (pDevice->bell) dmxLogCont(dmxInfo, " fb/bel");
1136
if (pDevice->leds) dmxLogCont(dmxInfo, " fb/led");
1137
if (!pDevice->key && !pDevice->valuator && !pDevice->button
1138
&& !pDevice->focus && !pDevice->kbdfeed
1139
&& !pDevice->ptrfeed && !pDevice->intfeed
1140
&& !pDevice->stringfeed && !pDevice->bell
1141
&& !pDevice->leds) dmxLogCont(dmxInfo, " (none)");
1143
dmxLogCont(dmxInfo, "\t[i%d/%*.*s",
1144
dmxInput->inputIdx, len, len, dmxInput->name);
1145
if (dmxInput->devs[i]->deviceId >= 0)
1146
dmxLogCont(dmxInfo, "/id%d", dmxInput->devs[i]->deviceId);
1147
if (dmxInput->devs[i]->deviceName)
1148
dmxLogCont(dmxInfo, "=%s", dmxInput->devs[i]->deviceName);
1149
dmxLogCont(dmxInfo, "] %s\n",
1150
dmxInput->devs[i]->isCore
1152
: (dmxInput->devs[i]->sendsCore
1153
? "extension (sends core events)"
1160
/** Detach an input */
1161
int dmxInputDetach(DMXInputInfo *dmxInput)
1165
if (dmxInput->detached) return BadAccess;
1167
for (i = 0; i < dmxInput->numDevs; i++) {
1168
DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
1169
dmxLogInput(dmxInput, "Detaching device id %d: %s%s\n",
1170
dmxLocal->pDevice->id,
1171
dmxLocal->pDevice->name,
1174
: (dmxLocal->sendsCore
1175
? " [sends core events]"
1177
DisableDevice(dmxLocal->pDevice);
1179
dmxInput->detached = True;
1180
dmxInputLogDevices();
1184
/** Search for input associated with \a dmxScreen, and detach. */
1185
void dmxInputDetachAll(DMXScreenInfo *dmxScreen)
1189
for (i = 0; i < dmxNumInputs; i++) {
1190
DMXInputInfo *dmxInput = &dmxInputs[i];
1191
if (dmxInput->scrnIdx == dmxScreen->index) dmxInputDetach(dmxInput);
1195
/** Search for input associated with \a deviceId, and detach. */
1196
int dmxInputDetachId(int id)
1198
DMXInputInfo *dmxInput = dmxInputLocateId(id);
1200
if (!dmxInput) return BadValue;
1202
return dmxInputDetach(dmxInput);
1205
DMXInputInfo *dmxInputLocateId(int id)
1209
for (i = 0; i < dmxNumInputs; i++) {
1210
DMXInputInfo *dmxInput = &dmxInputs[i];
1211
for (j = 0; j < dmxInput->numDevs; j++) {
1212
DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j];
1213
if (dmxLocal->pDevice->id == id) return dmxInput;
1219
static int dmxInputAttachNew(DMXInputInfo *dmxInput, int *id)
1221
dmxInputInit(dmxInput);
1222
InitAndStartDevices();
1223
if (id && dmxInput->devs) *id = dmxInput->devs[0]->pDevice->id;
1224
dmxInputLogDevices();
1228
static int dmxInputAttachOld(DMXInputInfo *dmxInput, int *id)
1232
dmxInput->detached = False;
1233
for (i = 0; i < dmxInput->numDevs; i++) {
1234
DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
1235
if (id) *id = dmxLocal->pDevice->id;
1236
dmxLogInput(dmxInput,
1237
"Attaching device id %d: %s%s\n",
1238
dmxLocal->pDevice->id,
1239
dmxLocal->pDevice->name,
1242
: (dmxLocal->sendsCore
1243
? " [sends core events]"
1245
EnableDevice(dmxLocal->pDevice);
1247
dmxInputLogDevices();
1251
int dmxInputAttachConsole(const char *name, int isCore, int *id)
1253
DMXInputInfo *dmxInput;
1256
for (i = 0; i < dmxNumInputs; i++) {
1257
dmxInput = &dmxInputs[i];
1258
if (dmxInput->scrnIdx == -1
1259
&& dmxInput->detached
1260
&& !strcmp(dmxInput->name, name)) {
1262
dmxLogInput(dmxInput, "Reattaching detached console input\n");
1263
return dmxInputAttachOld(dmxInput, id);
1267
/* No match found */
1268
dmxInput = dmxConfigAddInput(xstrdup(name), isCore);
1269
dmxInput->freename = TRUE;
1270
dmxLogInput(dmxInput, "Attaching new console input\n");
1271
return dmxInputAttachNew(dmxInput, id);
1274
int dmxInputAttachBackend(int physicalScreen, int isCore, int *id)
1276
DMXInputInfo *dmxInput;
1277
DMXScreenInfo *dmxScreen;
1280
if (physicalScreen < 0 || physicalScreen >= dmxNumScreens) return BadValue;
1281
for (i = 0; i < dmxNumInputs; i++) {
1282
dmxInput = &dmxInputs[i];
1283
if (dmxInput->scrnIdx != -1 && dmxInput->scrnIdx == physicalScreen) {
1285
if (!dmxInput->detached) return BadAccess; /* Already attached */
1286
dmxScreen = &dmxScreens[physicalScreen];
1287
if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */
1288
dmxLogInput(dmxInput, "Reattaching detached backend input\n");
1289
return dmxInputAttachOld(dmxInput, id);
1292
/* No match found */
1293
dmxScreen = &dmxScreens[physicalScreen];
1294
if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */
1295
dmxInput = dmxConfigAddInput(dmxScreen->name, isCore);
1296
dmxLogInput(dmxInput, "Attaching new backend input\n");
1297
return dmxInputAttachNew(dmxInput, id);