~ubuntu-branches/ubuntu/intrepid/xserver-xgl/intrepid

« back to all changes in this revision

Viewing changes to hw/dmx/input/dmxinputinit.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthew Garrett
  • Date: 2006-02-13 14:21:43 UTC
  • Revision ID: james.westby@ubuntu.com-20060213142143-mad6z9xzem7hzxz9
Tags: upstream-7.0.0
ImportĀ upstreamĀ versionĀ 7.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $XFree86$ */
 
2
/*
 
3
 * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
 
4
 *
 
5
 * All Rights Reserved.
 
6
 *
 
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:
 
14
 *
 
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.
 
18
 *
 
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
 
26
 * SOFTWARE.
 
27
 */
 
28
 
 
29
/*
 
30
 * Authors:
 
31
 *   Rickard E. (Rik) Faith <faith@redhat.com>
 
32
 *
 
33
 */
 
34
 
 
35
/** \file
 
36
 * This file provides generic input support.  Functions here set up
 
37
 * input and lead to the calling of low-level device drivers for
 
38
 * input. */
 
39
 
 
40
#ifdef HAVE_DMX_CONFIG_H
 
41
#include <dmx-config.h>
 
42
#endif
 
43
 
 
44
#define DMX_WINDOW_DEBUG 0
 
45
 
 
46
#include "dmxinputinit.h"
 
47
#include "dmxextension.h"       /* For dmxInputCount */
 
48
 
 
49
#include "dmxdummy.h"
 
50
#include "dmxbackend.h"
 
51
#include "dmxconsole.h"
 
52
#include "dmxcommon.h"
 
53
#include "dmxevents.h"
 
54
#include "dmxmotion.h"
 
55
#include "dmxeq.h"
 
56
#include "dmxprop.h"
 
57
#include "config/dmxconfig.h"
 
58
#include "dmxcursor.h"
 
59
 
 
60
#include "lnx-keyboard.h"
 
61
#include "lnx-ms.h"
 
62
#include "lnx-ps2.h"
 
63
#include "usb-keyboard.h"
 
64
#include "usb-mouse.h"
 
65
#include "usb-other.h"
 
66
#include "usb-common.h"
 
67
 
 
68
#include "dmxsigio.h"
 
69
#include "dmxarg.h"
 
70
 
 
71
#include "inputstr.h"
 
72
#include "input.h"
 
73
#include "mipointer.h"
 
74
#include "windowstr.h"
 
75
 
 
76
#ifdef XINPUT
 
77
#include <X11/extensions/XI.h>
 
78
#include <X11/extensions/XIproto.h>
 
79
#include "exevents.h"
 
80
#define EXTENSION_PROC_ARGS void *
 
81
#include "extinit.h"
 
82
#endif
 
83
 
 
84
/* From XI.h */
 
85
#ifndef Relative
 
86
#define Relative 0
 
87
#endif
 
88
#ifndef Absolute
 
89
#define Absolute 1
 
90
#endif
 
91
 
 
92
DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard;
 
93
 
 
94
static DMXLocalInputInfoRec DMXDummyMou = {
 
95
    "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
 
96
    NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo
 
97
};
 
98
 
 
99
static DMXLocalInputInfoRec DMXDummyKbd = {
 
100
    "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
 
101
    NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo
 
102
};
 
103
 
 
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,
 
109
    NULL, NULL, NULL,
 
110
    dmxBackendCollectEvents, dmxBackendProcessInput, dmxBackendFunctions, NULL,
 
111
    dmxCommonMouCtrl
 
112
};
 
113
 
 
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,
 
120
    NULL, NULL, NULL,
 
121
    NULL, NULL, NULL, NULL,
 
122
    NULL, dmxCommonKbdCtrl, dmxCommonKbdBell
 
123
};
 
124
 
 
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,
 
130
    NULL, NULL, NULL,
 
131
    dmxConsoleCollectEvents, NULL, dmxConsoleFunctions, dmxConsoleUpdateInfo,
 
132
    dmxCommonMouCtrl
 
133
};
 
134
 
 
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,
 
141
    NULL, NULL, NULL,
 
142
    NULL, NULL, NULL, NULL,
 
143
    NULL, dmxCommonKbdCtrl, dmxCommonKbdBell
 
144
};
 
145
 
 
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
 
151
};
 
152
 
 
153
 
 
154
static DMXLocalInputInfoRec DMXLocalDevices[] = {
 
155
                                /* Dummy drivers that can compile on any OS */
 
156
#ifdef __linux__
 
157
                                /* Linux-specific drivers */
 
158
    {
 
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
 
166
    },
 
167
    {
 
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,
 
173
        msLinuxRead
 
174
    },
 
175
    {
 
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,
 
181
        ps2LinuxRead
 
182
    },
 
183
#endif
 
184
#ifdef __linux__
 
185
                                /* USB drivers, currently only for
 
186
                                   Linux, but relatively easy to port to
 
187
                                   other OSs */
 
188
    {
 
189
        "usb-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
 
190
        usbCreatePrivate, usbDestroyPrivate,
 
191
        kbdUSBInit, NULL, NULL, kbdUSBGetInfo,
 
192
        kbdUSBOn, usbOff, NULL,
 
193
        NULL, NULL, NULL,
 
194
        kbdUSBRead, NULL, NULL, NULL,
 
195
        NULL, kbdUSBCtrl
 
196
    },
 
197
    {
 
198
        "usb-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
 
199
        usbCreatePrivate, usbDestroyPrivate,
 
200
        mouUSBInit, NULL, NULL, mouUSBGetInfo,
 
201
        mouUSBOn, usbOff, NULL,
 
202
        NULL, NULL, NULL,
 
203
        mouUSBRead
 
204
    },
 
205
    {
 
206
        "usb-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_LOCAL, 1,
 
207
        usbCreatePrivate, usbDestroyPrivate,
 
208
        othUSBInit, NULL, NULL, othUSBGetInfo,
 
209
        othUSBOn, usbOff, NULL,
 
210
        NULL, NULL, NULL,
 
211
        othUSBRead
 
212
    },
 
213
#endif
 
214
    {
 
215
        "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
 
216
        NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo
 
217
    },
 
218
    {
 
219
        "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
 
220
        NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo
 
221
    },
 
222
    { NULL }                    /* Must be last */
 
223
};
 
224
 
 
225
static void _dmxChangePointerControl(DMXLocalInputInfoPtr dmxLocal,
 
226
                                     PtrCtrl *ctrl)
 
227
{
 
228
    if (!dmxLocal) return;
 
229
    dmxLocal->mctrl = *ctrl;
 
230
    if (dmxLocal->mCtrl) dmxLocal->mCtrl(&dmxLocal->pDevice->public, ctrl);
 
231
}
 
232
 
 
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)
 
237
{
 
238
    GETDMXLOCALFROMPDEVICE;
 
239
    int i, j;
 
240
 
 
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);
 
248
        }
 
249
    } else {                    /* Do for this device only */
 
250
        _dmxChangePointerControl(dmxLocal, ctrl);
 
251
    }
 
252
}
 
253
 
 
254
static void _dmxKeyboardKbdCtrlProc(DMXLocalInputInfoPtr dmxLocal,
 
255
                                    KeybdCtrl *ctrl)
 
256
{
 
257
    dmxLocal->kctrl = *ctrl;
 
258
    if (dmxLocal->kCtrl) {
 
259
        dmxLocal->kCtrl(&dmxLocal->pDevice->public, ctrl);
 
260
#ifdef XKB
 
261
        if (!noXkbExtension && dmxLocal->pDevice->kbdfeed) {
 
262
            XkbEventCauseRec cause;
 
263
            XkbSetCauseUnknown(&cause);
 
264
            /* Generate XKB events, as necessary */
 
265
            XkbUpdateIndicators(dmxLocal->pDevice, XkbAllIndicatorsMask, False,
 
266
                                NULL, &cause);
 
267
        }
 
268
#endif
 
269
    }
 
270
}
 
271
 
 
272
 
 
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)
 
277
{
 
278
    GETDMXLOCALFROMPDEVICE;
 
279
    int i, j;
 
280
 
 
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);
 
288
        }
 
289
    } else {                    /* Do for this device only */
 
290
        _dmxKeyboardKbdCtrlProc(dmxLocal, ctrl);
 
291
    }
 
292
}
 
293
 
 
294
static void _dmxKeyboardBellProc(DMXLocalInputInfoPtr dmxLocal, int percent)
 
295
{
 
296
    if (dmxLocal->kBell) dmxLocal->kBell(&dmxLocal->pDevice->public,
 
297
                                         percent,
 
298
                                         dmxLocal->kctrl.bell,
 
299
                                         dmxLocal->kctrl.bell_pitch,
 
300
                                         dmxLocal->kctrl.bell_duration);
 
301
}
 
302
 
 
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)
 
307
{
 
308
    GETDMXLOCALFROMPDEVICE;
 
309
    int i, j;
 
310
 
 
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);
 
318
        }
 
319
    } else {                    /* Do for this device only */
 
320
        _dmxKeyboardBellProc(dmxLocal, percent);
 
321
    }
 
322
}
 
323
 
 
324
#ifdef XKB
 
325
static void dmxKeyboardFreeNames(XkbComponentNamesPtr names)
 
326
{
 
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);
 
333
}
 
334
#endif
 
335
 
 
336
 
 
337
static int dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo *info)
 
338
{
 
339
#ifdef XKB
 
340
    GETDMXINPUTFROMPDEVICE;
 
341
#else
 
342
    DevicePtr pDev = &pDevice->public;
 
343
#endif
 
344
 
 
345
#ifdef XKB
 
346
    if (noXkbExtension) {
 
347
#endif
 
348
        if (!InitKeyboardDeviceStruct(pDev, &info->keySyms, info->modMap,
 
349
                                      dmxKeyboardBellProc,
 
350
                                      dmxKeyboardKbdCtrlProc))
 
351
            return BadImplementation;
 
352
#ifdef XKB
 
353
    } else {
 
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;
 
364
            else
 
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;
 
371
        } else {
 
372
            if (!info->force && (dmxInput->keycodes
 
373
                                 || dmxInput->symbols
 
374
                                 || dmxInput->geometry)) {
 
375
                if (info->freenames) dmxKeyboardFreeNames(&info->names);
 
376
                info->freenames      = 0;
 
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;
 
382
                
 
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");
 
398
            } else {
 
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() : "");
 
407
            }
 
408
        }
 
409
        XkbInitKeyboardDeviceStruct(pDevice,
 
410
                                    &info->names,
 
411
                                    &info->keySyms,
 
412
                                    info->modMap,
 
413
                                    dmxKeyboardBellProc,
 
414
                                    dmxKeyboardKbdCtrlProc);
 
415
    }
 
416
    if (info->freenames) dmxKeyboardFreeNames(&info->names);
 
417
#endif
 
418
 
 
419
    return Success;
 
420
}
 
421
 
 
422
    
 
423
static int dmxDeviceOnOff(DeviceIntPtr pDevice, int what)
 
424
{
 
425
    GETDMXINPUTFROMPDEVICE;
 
426
    int              fd;
 
427
    DMXLocalInitInfo info;
 
428
#ifdef XINPUT
 
429
    int              i;
 
430
#endif
 
431
    
 
432
    if (!dmxLocal) return BadImplementation;
 
433
    if (dmxInput->detached) return Success;
 
434
 
 
435
    memset(&info, 0, sizeof(info));
 
436
    switch (what) {
 
437
    case DEVICE_INIT:
 
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);
 
442
            break;
 
443
        }
 
444
        if (info.keyClass) {
 
445
            InitKeyClassDeviceStruct(pDevice, &info.keySyms, info.modMap);
 
446
        }
 
447
        if (info.buttonClass) {
 
448
            InitButtonClassDeviceStruct(pDevice, info.numButtons, info.map);
 
449
        }
 
450
        if (info.valuatorClass) {
 
451
            if (info.numRelAxes && dmxLocal->sendsCore) {
 
452
                InitValuatorClassDeviceStruct(pDevice, info.numRelAxes,
 
453
                                              miPointerGetMotionEvents,
 
454
                                              miPointerGetMotionBufferSize(),
 
455
                                              Relative);
 
456
#ifdef XINPUT
 
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]);
 
461
#endif
 
462
            } else if (info.numRelAxes) {
 
463
                InitValuatorClassDeviceStruct(pDevice, info.numRelAxes,
 
464
                                              dmxPointerGetMotionEvents,
 
465
                                              dmxPointerGetMotionBufferSize(),
 
466
                                              Relative);
 
467
#ifdef XINPUT
 
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]);
 
472
#endif
 
473
            } else if (info.numAbsAxes) {
 
474
                InitValuatorClassDeviceStruct(pDevice, info.numAbsAxes,
 
475
                                              dmxPointerGetMotionEvents,
 
476
                                              dmxPointerGetMotionBufferSize(),
 
477
                                              Absolute);
 
478
#ifdef XINPUT
 
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],
 
483
                                           info.maxres[i+1]);
 
484
#endif
 
485
            }
 
486
        }
 
487
        if (info.focusClass)       InitFocusClassDeviceStruct(pDevice);
 
488
#ifdef XINPUT
 
489
        if (info.proximityClass)   InitProximityClassDeviceStruct(pDevice);
 
490
#endif
 
491
        if (info.ptrFeedbackClass)
 
492
            InitPtrFeedbackClassDeviceStruct(pDevice, dmxChangePointerControl);
 
493
        if (info.kbdFeedbackClass)
 
494
            InitKbdFeedbackClassDeviceStruct(pDevice, dmxKeyboardBellProc,
 
495
                                             dmxKeyboardKbdCtrlProc);
 
496
        if (info.intFeedbackClass || info.strFeedbackClass)
 
497
            dmxLog(dmxWarning,
 
498
                   "Integer and string feedback not supported for %s\n",
 
499
                   pDevice->name);
 
500
        if (!info.keyboard && (info.ledFeedbackClass || info.belFeedbackClass))
 
501
            dmxLog(dmxWarning,
 
502
                   "Led and bel feedback not supported for non-keyboard %s\n",
 
503
                   pDevice->name);
 
504
        break;
 
505
    case DEVICE_ON:
 
506
        if (!pDev->on) {
 
507
            if (dmxLocal->on && (fd = dmxLocal->on(pDev)) >= 0)
 
508
                dmxSigioRegister(dmxInput, fd);
 
509
            pDev->on = TRUE;
 
510
        }
 
511
        break;
 
512
    case DEVICE_OFF:
 
513
    case DEVICE_CLOSE:
 
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). */
 
517
        if (pDev->on) {
 
518
            dmxSigioUnregister(dmxInput);
 
519
            if (dmxLocal->off) dmxLocal->off(pDev);
 
520
            pDev->on = FALSE;
 
521
        }
 
522
        break;
 
523
    }
 
524
    if (info.keySyms.map && info.freemap) {
 
525
        XFree(info.keySyms.map);
 
526
        info.keySyms.map = NULL;
 
527
    }
 
528
#ifdef XKB
 
529
    if (info.xkb) XkbFreeKeyboard(info.xkb, 0, True);
 
530
#endif
 
531
    return Success;
 
532
}
 
533
 
 
534
static void dmxProcessInputEvents(DMXInputInfo *dmxInput)
 
535
{
 
536
    int i;
 
537
 
 
538
    dmxeqProcessInputEvents();
 
539
    miPointerUpdate();
 
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);
 
544
}
 
545
 
 
546
static void dmxUpdateWindowInformation(DMXInputInfo *dmxInput,
 
547
                                       DMXUpdateType type,
 
548
                                       WindowPtr pWindow)
 
549
{
 
550
    int i;
 
551
 
 
552
#ifdef PANORAMIX
 
553
    if (!noPanoramiXExtension && pWindow && pWindow->parent != WindowTable[0])
 
554
        return;
 
555
#endif
 
556
#if DMX_WINDOW_DEBUG
 
557
    {
 
558
        const char *name = "Unknown";
 
559
        switch (type) {
 
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;
 
566
        }
 
567
        dmxLog(dmxDebug, "Window %p changed: %s\n", pWindow, name);
 
568
    }
 
569
#endif
 
570
 
 
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,
 
575
                                           type, pWindow);
 
576
}
 
577
 
 
578
static void dmxCollectAll(DMXInputInfo *dmxInput)
 
579
{
 
580
    int i;
 
581
 
 
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]
 
586
                                              ->pDevice->public,
 
587
                                              dmxMotion,
 
588
                                              dmxEnqueue,
 
589
                                              dmxCheckSpecialKeys, DMX_BLOCK);
 
590
}
 
591
 
 
592
static void dmxBlockHandler(pointer blockData, OSTimePtr pTimeout,
 
593
                            pointer pReadMask)
 
594
{
 
595
    DMXInputInfo    *dmxInput = &dmxInputs[(int)blockData];
 
596
    static unsigned long generation = 0;
 
597
    
 
598
    if (generation != serverGeneration) {
 
599
        generation = serverGeneration;
 
600
        dmxCollectAll(dmxInput);
 
601
    }
 
602
}
 
603
 
 
604
static void dmxSwitchReturn(pointer p)
 
605
{
 
606
    DMXInputInfo *dmxInput = p;
 
607
    int          i;
 
608
    
 
609
    dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched);
 
610
 
 
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;
 
618
}
 
619
 
 
620
static void dmxWakeupHandler(pointer blockData, int result, pointer pReadMask)
 
621
{
 
622
    DMXInputInfo *dmxInput = &dmxInputs[(int)blockData];
 
623
    int          i;
 
624
 
 
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,
 
637
                                                  dmxSwitchReturn,
 
638
                                                  dmxInput))
 
639
                    dmxSwitchReturn(dmxInput);
 
640
                break;          /* Only call one vt_switch routine */
 
641
            }
 
642
        }
 
643
    }
 
644
    dmxCollectAll(dmxInput);
 
645
}
 
646
 
 
647
static char *dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal)
 
648
{
 
649
    static int           k = 0;
 
650
    static int           m = 0;
 
651
    static int           o = 0;
 
652
    static unsigned long dmxGeneration = 0;
 
653
#define LEN  32
 
654
    char *               buf = xalloc(LEN);
 
655
 
 
656
    if (dmxGeneration != serverGeneration) {
 
657
        k = m = o     = 0;
 
658
        dmxGeneration = serverGeneration;
 
659
    }
 
660
 
 
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;
 
665
    }
 
666
 
 
667
    return buf;
 
668
}
 
669
 
 
670
static DeviceIntPtr dmxAddDevice(DMXLocalInputInfoPtr dmxLocal)
 
671
{
 
672
    DeviceIntPtr pDevice;
 
673
    Atom         atom;
 
674
    const char   *name = NULL;
 
675
    void         (*registerProcPtr)(DeviceIntPtr)   = NULL;
 
676
    char         *devname;
 
677
    DMXInputInfo *dmxInput;
 
678
 
 
679
    if (!dmxLocal) return NULL;
 
680
    dmxInput = &dmxInputs[dmxLocal->inputIdx];
 
681
 
 
682
    if (dmxLocal->sendsCore) {
 
683
        if (dmxLocal->type == DMX_LOCAL_KEYBOARD && !dmxLocalCoreKeyboard) {
 
684
            dmxLocal->isCore     = 1;
 
685
            dmxLocalCoreKeyboard = dmxLocal;
 
686
            name                 = "keyboard";
 
687
            registerProcPtr      = _RegisterKeyboardDevice;
 
688
        }
 
689
        if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) {
 
690
            dmxLocal->isCore     = 1;
 
691
            dmxLocalCorePointer  = dmxLocal;
 
692
            name                 = "pointer";
 
693
            registerProcPtr      = _RegisterPointerDevice;
 
694
        }
 
695
    }
 
696
 
 
697
#ifdef XINPUT
 
698
    if (!name) {
 
699
        name            = "extension";
 
700
        registerProcPtr = RegisterOtherDevice;
 
701
    }
 
702
#else
 
703
    if (!name)
 
704
        dmxLog(dmxFatal,
 
705
               "Server not build with XINPUT support (cannot add %s)\n",
 
706
               dmxLocal->name);
 
707
#endif
 
708
 
 
709
    if (!name || !registerProcPtr)
 
710
        dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name);
 
711
 
 
712
    pDevice                       = AddInputDevice(dmxDeviceOnOff, TRUE);
 
713
    if (!pDevice) {
 
714
        dmxLog(dmxError, "Too many devices -- cannot add device %s\n",
 
715
               dmxLocal->name);
 
716
        return NULL;
 
717
    }
 
718
    pDevice->public.devicePrivate = dmxLocal;
 
719
    dmxLocal->pDevice             = pDevice;
 
720
 
 
721
    devname       = dmxMakeUniqueDeviceName(dmxLocal);
 
722
    atom          = MakeAtom((char *)devname, strlen(devname), TRUE);
 
723
    pDevice->type = atom;
 
724
    pDevice->name = devname;
 
725
 
 
726
    registerProcPtr(pDevice);
 
727
 
 
728
    if (dmxLocal->isCore && dmxLocal->type == DMX_LOCAL_MOUSE)
 
729
        miRegisterPointerDevice(screenInfo.screens[0], pDevice);
 
730
 
 
731
    if (dmxLocal->create_private)
 
732
        dmxLocal->private = dmxLocal->create_private(pDevice);
 
733
 
 
734
    dmxLogInput(dmxInput, "Added %s as %s device called %s%s\n",
 
735
                dmxLocal->name, name, devname,
 
736
                dmxLocal->isCore
 
737
                ? " [core]"
 
738
                : (dmxLocal->sendsCore
 
739
                   ? " [sends core events]"
 
740
                   : ""));
 
741
 
 
742
    return pDevice;
 
743
}
 
744
 
 
745
static DMXLocalInputInfoPtr dmxLookupLocal(const char *name)
 
746
{
 
747
    DMXLocalInputInfoPtr pt;
 
748
    
 
749
    for (pt = &DMXLocalDevices[0]; pt->name; ++pt)
 
750
        if (!strcmp(pt->name, name)) return pt; /* search for device name */
 
751
    return NULL;
 
752
}
 
753
 
 
754
/** Copy the local input information from \a s into a new \a devs slot
 
755
 * in \a dmxInput. */
 
756
DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput,
 
757
                                       DMXLocalInputInfoPtr s)
 
758
{
 
759
    DMXLocalInputInfoPtr dmxLocal = xalloc(sizeof(*dmxLocal));
 
760
    
 
761
    if (!dmxLocal)
 
762
        dmxLog(dmxFatal, "DMXLocalInputInfoPtr: out of memory\n");
 
763
 
 
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;
 
769
 
 
770
    ++dmxInput->numDevs;
 
771
    dmxInput->devs = xrealloc(dmxInput->devs,
 
772
                              dmxInput->numDevs * sizeof(*dmxInput->devs));
 
773
    dmxInput->devs[dmxInput->numDevs-1] = dmxLocal;
 
774
    
 
775
    return dmxLocal;
 
776
}
 
777
 
 
778
static void dmxPopulateLocal(DMXInputInfo *dmxInput, dmxArg a)
 
779
{
 
780
    int                  i;
 
781
    int                  help = 0;
 
782
    DMXLocalInputInfoRec *pt;
 
783
 
 
784
    for (i = 1; i < dmxArgC(a); i++) {
 
785
        const char *name = dmxArgV(a, i);
 
786
        if ((pt = dmxLookupLocal(name))) {
 
787
            dmxInputCopyLocal(dmxInput, pt);
 
788
        } else {
 
789
            if (strlen(name))
 
790
                dmxLog(dmxWarning,
 
791
                       "Could not find a driver called %s\n", name);
 
792
            ++help;
 
793
        }
 
794
    }
 
795
    if (help) {
 
796
        dmxLog(dmxInfo, "Available local device drivers:\n");
 
797
        for (pt = &DMXLocalDevices[0]; pt->name; ++pt) {
 
798
            const char *type;
 
799
            switch (pt->type) {
 
800
            case DMX_LOCAL_KEYBOARD: type = "keyboard"; break;
 
801
            case DMX_LOCAL_MOUSE:    type = "pointer";  break;
 
802
            default:                 type = "unknown";  break;
 
803
            }
 
804
            dmxLog(dmxInfo, "   %s (%s)\n", pt->name, type);
 
805
        }
 
806
        dmxLog(dmxFatal, "Must have valid local device driver\n");
 
807
    }
 
808
}
 
809
 
 
810
int dmxInputExtensionErrorHandler(Display *dsp, char *name, char *reason)
 
811
{
 
812
    return 0;
 
813
}
 
814
 
 
815
static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI)
 
816
{
 
817
    XExtensionVersion    *ext;
 
818
    XDeviceInfo          *devices;
 
819
    Display              *display;
 
820
    int                  num;
 
821
    int                  i, j;
 
822
    DMXLocalInputInfoPtr dmxLocal;
 
823
    int                  (*handler)(Display *, char *, char *);
 
824
 
 
825
    if (!(display = XOpenDisplay(dmxInput->name))) return;
 
826
    
 
827
    /* Print out information about the XInput Extension. */
 
828
    handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler);
 
829
    ext     = XGetExtensionVersion(display, INAME);
 
830
    XSetExtensionErrorHandler(handler);
 
831
    
 
832
    if (!ext || ext == (XExtensionVersion *)NoSuchExtension) {
 
833
        dmxLogInput(dmxInput, "%s is not available\n", INAME);
 
834
    } else {
 
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);
 
839
 
 
840
        XFree(ext);
 
841
        ext = NULL;
 
842
 
 
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;
 
850
            }
 
851
            dmxLogInput(dmxInput, "  %2d %-10.10s %-16.16s\n",
 
852
                        devices[i].id,
 
853
                        devices[i].name ? devices[i].name : "",
 
854
                        use);
 
855
        }
 
856
 
 
857
                                /* Search for extensions */
 
858
        for (i = 0; i < num; i++) {
 
859
            switch (devices[i].use) {
 
860
            case IsXKeyboard:
 
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)
 
868
                                            : NULL);
 
869
                    }
 
870
                }
 
871
                break;
 
872
            case IsXPointer:
 
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)
 
879
                                            : NULL);
 
880
                    }
 
881
                }
 
882
                break;
 
883
            case IsXExtensionDevice:
 
884
                if (doXI) {
 
885
                    if (!dmxInput->numDevs) {
 
886
                        dmxLog(dmxWarning,
 
887
                               "Cannot use remote (%s) XInput devices if"
 
888
                               " not also using core devices\n",
 
889
                               dmxInput->name);
 
890
                    } else {
 
891
                        dmxLocal             = dmxInputCopyLocal(dmxInput,
 
892
                                                                &DMXCommonOth);
 
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)
 
898
                                                : NULL);
 
899
                    }
 
900
                }
 
901
                break;
 
902
            }
 
903
        }
 
904
        XFreeDeviceList(devices);
 
905
    }
 
906
    XCloseDisplay(display);
 
907
}
 
908
 
 
909
/** Re-initialize all the devices described in \a dmxInput.  Called from
 
910
    #dmxReconfig before the cursor is redisplayed. */ 
 
911
void dmxInputReInit(DMXInputInfo *dmxInput)
 
912
{
 
913
    int i;
 
914
 
 
915
    for (i = 0; i < dmxInput->numDevs; i++) {
 
916
        DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
 
917
        if (dmxLocal->reinit)
 
918
            dmxLocal->reinit(&dmxLocal->pDevice->public);
 
919
    }
 
920
}
 
921
 
 
922
/** Re-initialize all the devices described in \a dmxInput.  Called from
 
923
    #dmxReconfig after the cursor is redisplayed. */ 
 
924
void dmxInputLateReInit(DMXInputInfo *dmxInput)
 
925
{
 
926
    int i;
 
927
 
 
928
    for (i = 0; i < dmxInput->numDevs; i++) {
 
929
        DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
 
930
        if (dmxLocal->latereinit)
 
931
            dmxLocal->latereinit(&dmxLocal->pDevice->public);
 
932
    }
 
933
}
 
934
 
 
935
/** Initialize all of the devices described in \a dmxInput. */
 
936
void dmxInputInit(DMXInputInfo *dmxInput)
 
937
{
 
938
    DeviceIntPtr         pPointer = NULL, pKeyboard = NULL;
 
939
    dmxArg               a;
 
940
    const char           *name;
 
941
    int                  i;
 
942
    int                  doXI               = 1; /* Include by default */
 
943
    int                  forceConsole       = 0;
 
944
    int                  doWindows          = 1; /* On by default */
 
945
    int                  hasXkb             = 0;
 
946
 
 
947
    a = dmxArgParse(dmxInput->name);
 
948
 
 
949
    for (i = 1; i < dmxArgC(a); i++) {
 
950
        switch (hasXkb) {
 
951
        case 1:
 
952
            dmxInput->keycodes = xstrdup(dmxArgV(a, i));
 
953
            ++hasXkb;
 
954
            break;
 
955
        case 2:
 
956
            dmxInput->symbols  = xstrdup(dmxArgV(a, i));
 
957
            ++hasXkb;
 
958
            break;
 
959
        case 3:
 
960
            dmxInput->geometry = xstrdup(dmxArgV(a, i));
 
961
            hasXkb = 0;
 
962
            break;
 
963
        case 0:
 
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;
 
971
            else {
 
972
                dmxLog(dmxFatal,
 
973
                       "Unknown input argument: %s\n", dmxArgV(a, i));
 
974
            }
 
975
        }
 
976
    }
 
977
 
 
978
    name = dmxArgV(a, 0);
 
979
 
 
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");
 
986
    } else {
 
987
        int found;
 
988
 
 
989
        for (found = 0, i = 0; i < dmxNumScreens; i++) {
 
990
            if (dmxPropertySameDisplay(&dmxScreens[i], name)) {
 
991
                if (dmxScreens[i].shared)
 
992
                    dmxLog(dmxFatal,
 
993
                           "Cannot take input from shared backend (%s)\n",
 
994
                           name);
 
995
                if (!dmxInput->core) {
 
996
                    dmxLog(dmxWarning,
 
997
                           "Cannot use core devices on a backend (%s)"
 
998
                           " as XInput devices\n", name);
 
999
                } else {
 
1000
                    char *pt;
 
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);
 
1008
                }
 
1009
                ++found;
 
1010
                break;
 
1011
            }
 
1012
        }
 
1013
        if (!found || forceConsole) {
 
1014
            char *pt;
 
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);
 
1020
            if (doWindows) {
 
1021
                dmxInput->windows          = TRUE;
 
1022
                dmxInput->updateWindowInfo = dmxUpdateWindowInformation;
 
1023
            }
 
1024
            dmxLogInput(dmxInput,
 
1025
                        "Using console input from %s (%s windows)\n",
 
1026
                        name, doWindows ? "with" : "without");
 
1027
        }
 
1028
    }
 
1029
 
 
1030
    dmxArgFree(a);
 
1031
 
 
1032
                                /* Locate extensions we may be interested in */
 
1033
    dmxInputScanForExtensions(dmxInput, doXI);
 
1034
    
 
1035
    for (i = 0; i < dmxInput->numDevs; i++) {
 
1036
        DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
 
1037
#ifndef XINPUT
 
1038
        if (!dmxLocal->isCore)
 
1039
            dmxLog(dmxFatal,
 
1040
                   "This server was not compiled to support the XInput"
 
1041
                   " extension, but %s is not a core device.\n",
 
1042
                   dmxLocal->name);
 
1043
#endif
 
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;
 
1050
        }
 
1051
    }
 
1052
    
 
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);
 
1057
    }
 
1058
 
 
1059
    dmxInput->processInputEvents    = dmxProcessInputEvents;
 
1060
    dmxInput->detached              = False;
 
1061
    
 
1062
    RegisterBlockAndWakeupHandlers(dmxBlockHandler,
 
1063
                                   dmxWakeupHandler,
 
1064
                                   (void *)dmxInput->inputIdx);
 
1065
}
 
1066
 
 
1067
static void dmxInputFreeLocal(DMXLocalInputInfoRec *local)
 
1068
{
 
1069
    if (!local) return;
 
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;
 
1081
    xfree(local);
 
1082
}
 
1083
 
 
1084
/** Free all of the memory associated with \a dmxInput */
 
1085
void dmxInputFree(DMXInputInfo *dmxInput)
 
1086
{
 
1087
    int i;
 
1088
    
 
1089
    if (!dmxInput) return;
 
1090
 
 
1091
    if (dmxInput->keycodes) xfree(dmxInput->keycodes);
 
1092
    if (dmxInput->symbols)  xfree(dmxInput->symbols);
 
1093
    if (dmxInput->geometry) xfree(dmxInput->geometry);
 
1094
 
 
1095
    for (i = 0; i < dmxInput->numDevs; i++) {
 
1096
        dmxInputFreeLocal(dmxInput->devs[i]);
 
1097
        dmxInput->devs[i] = NULL;
 
1098
    }
 
1099
    xfree(dmxInput->devs);
 
1100
    dmxInput->devs    = NULL;
 
1101
    dmxInput->numDevs = 0;
 
1102
    if (dmxInput->freename) xfree(dmxInput->name);
 
1103
    dmxInput->name    = NULL;
 
1104
}
 
1105
 
 
1106
/** Log information about all of the known devices using #dmxLog(). */
 
1107
void dmxInputLogDevices(void)
 
1108
{
 
1109
    int i, j;
 
1110
 
 
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, ',');
 
1116
        int          len = (pt
 
1117
                            ? (size_t)(pt-dmxInput->name)
 
1118
                            : strlen(dmxInput->name));
 
1119
 
 
1120
        for (i = 0; i < dmxInput->numDevs; i++) {
 
1121
            DeviceIntPtr pDevice = dmxInput->devs[i]->pDevice;
 
1122
            if (pDevice) {
 
1123
                dmxLog(dmxInfo, "  %2d%c %-20.20s",
 
1124
                       pDevice->id,
 
1125
                       dmxInput->detached ? 'D' : ' ',
 
1126
                       pDevice->name);
 
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)");
 
1142
                                                                 
 
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
 
1151
                           ? "core"
 
1152
                           : (dmxInput->devs[i]->sendsCore
 
1153
                              ? "extension (sends core events)"
 
1154
                              : "extension"));
 
1155
            }
 
1156
        }
 
1157
    }
 
1158
}
 
1159
 
 
1160
/** Detach an input */
 
1161
int dmxInputDetach(DMXInputInfo *dmxInput)
 
1162
{
 
1163
    int i;
 
1164
 
 
1165
    if (dmxInput->detached) return BadAccess;
 
1166
    
 
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,
 
1172
                    dmxLocal->isCore
 
1173
                    ? " [core]"
 
1174
                    : (dmxLocal->sendsCore
 
1175
                       ? " [sends core events]"
 
1176
                       : ""));
 
1177
        DisableDevice(dmxLocal->pDevice);
 
1178
    }
 
1179
    dmxInput->detached = True;
 
1180
    dmxInputLogDevices();
 
1181
    return 0;
 
1182
}
 
1183
 
 
1184
/** Search for input associated with \a dmxScreen, and detach. */
 
1185
void dmxInputDetachAll(DMXScreenInfo *dmxScreen)
 
1186
{
 
1187
    int i;
 
1188
 
 
1189
    for (i = 0; i < dmxNumInputs; i++) {
 
1190
        DMXInputInfo *dmxInput = &dmxInputs[i];
 
1191
        if (dmxInput->scrnIdx == dmxScreen->index) dmxInputDetach(dmxInput);
 
1192
    }
 
1193
}
 
1194
 
 
1195
/** Search for input associated with \a deviceId, and detach. */
 
1196
int dmxInputDetachId(int id)
 
1197
{
 
1198
    DMXInputInfo *dmxInput = dmxInputLocateId(id);
 
1199
 
 
1200
    if (!dmxInput) return BadValue;
 
1201
    
 
1202
    return dmxInputDetach(dmxInput);
 
1203
}
 
1204
 
 
1205
DMXInputInfo *dmxInputLocateId(int id)
 
1206
{
 
1207
    int i, j;
 
1208
    
 
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;
 
1214
        }
 
1215
    }
 
1216
    return NULL;
 
1217
}
 
1218
 
 
1219
static int dmxInputAttachNew(DMXInputInfo *dmxInput, int *id)
 
1220
{
 
1221
    dmxInputInit(dmxInput);
 
1222
    InitAndStartDevices();
 
1223
    if (id && dmxInput->devs) *id = dmxInput->devs[0]->pDevice->id;
 
1224
    dmxInputLogDevices();
 
1225
    return 0;
 
1226
}
 
1227
 
 
1228
static int dmxInputAttachOld(DMXInputInfo *dmxInput, int *id)
 
1229
{
 
1230
    int i;
 
1231
    
 
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,
 
1240
                    dmxLocal->isCore
 
1241
                    ? " [core]"
 
1242
                    : (dmxLocal->sendsCore
 
1243
                       ? " [sends core events]"
 
1244
                       : ""));
 
1245
        EnableDevice(dmxLocal->pDevice);
 
1246
    }
 
1247
    dmxInputLogDevices();
 
1248
    return 0;
 
1249
}
 
1250
 
 
1251
int dmxInputAttachConsole(const char *name, int isCore, int *id)
 
1252
{
 
1253
    DMXInputInfo  *dmxInput;
 
1254
    int           i;
 
1255
 
 
1256
    for (i = 0; i < dmxNumInputs; i++) {
 
1257
        dmxInput = &dmxInputs[i];
 
1258
        if (dmxInput->scrnIdx == -1
 
1259
            && dmxInput->detached
 
1260
            && !strcmp(dmxInput->name, name)) {
 
1261
                                /* Found match */
 
1262
            dmxLogInput(dmxInput, "Reattaching detached console input\n");
 
1263
            return dmxInputAttachOld(dmxInput, id);
 
1264
        }
 
1265
    }
 
1266
 
 
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);
 
1272
}
 
1273
 
 
1274
int dmxInputAttachBackend(int physicalScreen, int isCore, int *id)
 
1275
{
 
1276
    DMXInputInfo  *dmxInput;
 
1277
    DMXScreenInfo *dmxScreen;
 
1278
    int           i;
 
1279
    
 
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) {
 
1284
                                /* Found match */
 
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);
 
1290
        }
 
1291
    }
 
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);
 
1298
}