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

« back to all changes in this revision

Viewing changes to hw/dmx/input/dmxevents.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
 * Provide support and helper functions for enqueing events received by
 
37
 * the low-level input drivers. */
 
38
 
 
39
#ifdef HAVE_DMX_CONFIG_H
 
40
#include <dmx-config.h>
 
41
#endif
 
42
 
 
43
#define DMX_EVENTS_DEBUG 0
 
44
 
 
45
#include "dmxinputinit.h"
 
46
#include "dmxevents.h"
 
47
#include "dmxcb.h"
 
48
#include "dmxcommon.h"
 
49
#include "dmxcursor.h"
 
50
#include "dmxmotion.h"
 
51
#include "dmxeq.h"
 
52
#include "dmxsigio.h"
 
53
#include "dmxmap.h"
 
54
 
 
55
#include <X11/keysym.h>
 
56
#include "opaque.h"
 
57
#include "inputstr.h"
 
58
#include "mipointer.h"
 
59
 
 
60
#ifdef XINPUT
 
61
#include "XIstubs.h"
 
62
#endif
 
63
 
 
64
static int  dmxGlobalX, dmxGlobalY; /* Global cursor position */
 
65
static int  dmxGlobalInvalid;       /* Flag indicating dmxCoreMotion
 
66
                                     * should move the mouse anyway. */
 
67
 
 
68
#if DMX_EVENTS_DEBUG
 
69
#define DMXDBG0(f)               dmxLog(dmxDebug,f)
 
70
#define DMXDBG1(f,a)             dmxLog(dmxDebug,f,a)
 
71
#define DMXDBG2(f,a,b)           dmxLog(dmxDebug,f,a,b)
 
72
#define DMXDBG3(f,a,b,c)         dmxLog(dmxDebug,f,a,b,c)
 
73
#define DMXDBG4(f,a,b,c,d)       dmxLog(dmxDebug,f,a,b,c,d)
 
74
#define DMXDBG5(f,a,b,c,d,e)     dmxLog(dmxDebug,f,a,b,c,d,e)
 
75
#define DMXDBG6(f,a,b,c,d,e,g)   dmxLog(dmxDebug,f,a,b,c,d,e,g)
 
76
#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h)
 
77
#else
 
78
#define DMXDBG0(f)
 
79
#define DMXDBG1(f,a)
 
80
#define DMXDBG2(f,a,b)
 
81
#define DMXDBG3(f,a,b,c)
 
82
#define DMXDBG4(f,a,b,c,d)
 
83
#define DMXDBG5(f,a,b,c,d,e)
 
84
#define DMXDBG6(f,a,b,c,d,e,g)
 
85
#define DMXDBG7(f,a,b,c,d,e,g,h)
 
86
#endif
 
87
 
 
88
static int dmxApplyFunctions(DMXInputInfo *dmxInput, DMXFunctionType f)
 
89
{
 
90
    int i;
 
91
    int rc = 0;
 
92
 
 
93
    for (i = 0; i < dmxInput->numDevs; i+= dmxInput->devs[i]->binding)
 
94
        if (dmxInput->devs[i]->functions)
 
95
            rc += dmxInput->devs[i]->functions(dmxInput->devs[i]->private, f);
 
96
    return rc;
 
97
}
 
98
 
 
99
static int dmxCheckFunctionKeys(DMXLocalInputInfoPtr dmxLocal,
 
100
                                int type,
 
101
                                KeySym keySym)
 
102
{
 
103
    DMXInputInfo   *dmxInput = &dmxInputs[dmxLocal->inputIdx];
 
104
    unsigned short state = 0;
 
105
    
 
106
    if (dmxLocal->sendsCore)
 
107
        state = dmxLocalCoreKeyboard->pDevice->key->state;
 
108
    else if (dmxLocal->pDevice->key)
 
109
        state = dmxLocal->pDevice->key->state;
 
110
    
 
111
    DMXDBG3("dmxCheckFunctionKeys: keySym=0x%04x %s state=0x%04x\n",
 
112
            keySym, type == KeyPress ? "press" : "release", state);
 
113
 
 
114
    if ((state & (ControlMask|Mod1Mask)) != (ControlMask|Mod1Mask)) return 0;
 
115
 
 
116
    switch (keySym) {
 
117
    case XK_g:
 
118
        if (type == KeyPress)
 
119
            dmxApplyFunctions(dmxInput, DMX_FUNCTION_GRAB);
 
120
        return 1;
 
121
    case XK_f:
 
122
        if (type == KeyPress)
 
123
            dmxApplyFunctions(dmxInput, DMX_FUNCTION_FINE);
 
124
        return 1;
 
125
    case XK_q:
 
126
        if (type == KeyPress && dmxLocal->sendsCore)
 
127
            if (dmxApplyFunctions(dmxInput, DMX_FUNCTION_TERMINATE)) {
 
128
                dmxLog(dmxInfo, "User request for termination\n");
 
129
                dispatchException |= DE_TERMINATE;
 
130
            }
 
131
        return 1;
 
132
    }
 
133
    
 
134
    return 0;
 
135
}
 
136
 
 
137
#ifdef XINPUT
 
138
static void dmxEnqueueExtEvent(DMXLocalInputInfoPtr dmxLocal, xEvent *e,
 
139
                               DMXBlockType block)
 
140
{
 
141
    xEvent                 xE[2];
 
142
    deviceKeyButtonPointer *xev      = (deviceKeyButtonPointer *)xE;
 
143
    deviceValuator         *xv       = (deviceValuator *)xev+1;
 
144
    DeviceIntPtr           pDevice   = dmxLocal->pDevice;
 
145
    DMXInputInfo           *dmxInput = &dmxInputs[dmxLocal->inputIdx];
 
146
    int                    type      = e->u.u.type;
 
147
 
 
148
    switch (e->u.u.type) {
 
149
    case KeyPress:      type = DeviceKeyPress;      break;
 
150
    case KeyRelease:    type = DeviceKeyRelease;    break;
 
151
    case ButtonPress:   type = DeviceButtonPress;   break;
 
152
    case ButtonRelease: type = DeviceButtonRelease; break;
 
153
    case MotionNotify:
 
154
        dmxLog(dmxError,
 
155
               "dmxEnqueueExtEvent: MotionNotify not allowed here\n");
 
156
        return;
 
157
    default:
 
158
        if (e->u.u.type == ProximityIn || e->u.u.type == ProximityOut) break;
 
159
        dmxLogInput(dmxInput,
 
160
                    "dmxEnqueueExtEvent: Unhandled %s event (%d)\n",
 
161
                    e->u.u.type >= LASTEvent ? "extension" : "non-extension",
 
162
                    e->u.u.type);
 
163
        return;
 
164
    }
 
165
 
 
166
    xev->type          = type;
 
167
    xev->detail        = e->u.u.detail;
 
168
    xev->deviceid      = pDevice->id | MORE_EVENTS;
 
169
    xev->time          = e->u.keyButtonPointer.time;
 
170
 
 
171
    xv->type           = DeviceValuator;
 
172
    xv->deviceid       = pDevice->id;
 
173
    xv->num_valuators  = 0;
 
174
    xv->first_valuator = 0;
 
175
 
 
176
    if (block) dmxSigioBlock();
 
177
    dmxeqEnqueue(xE);
 
178
    if (block) dmxSigioUnblock();
 
179
}
 
180
#endif
 
181
 
 
182
DMXScreenInfo *dmxFindFirstScreen(int x, int y)
 
183
{
 
184
    int i;
 
185
 
 
186
    for (i = 0; i < dmxNumScreens; i++) {
 
187
        DMXScreenInfo *dmxScreen = &dmxScreens[i];
 
188
        if (dmxOnScreen(x, y, dmxScreen)) return dmxScreen;
 
189
    }
 
190
    return NULL;
 
191
}
 
192
 
 
193
void dmxCoreMotion(int x, int y, int delta, DMXBlockType block)
 
194
{
 
195
    DMXScreenInfo *dmxScreen;
 
196
    DMXInputInfo  *dmxInput;
 
197
    ScreenPtr     pScreen;
 
198
    int           localX;
 
199
    int           localY;
 
200
    int           i;
 
201
 
 
202
    if (!dmxGlobalInvalid && dmxGlobalX == x && dmxGlobalY == y) return;
 
203
    
 
204
    DMXDBG5("dmxCoreMotion(%d,%d,%d) dmxGlobalX=%d dmxGlobalY=%d\n",
 
205
            x, y, delta, dmxGlobalX, dmxGlobalY);
 
206
 
 
207
    dmxGlobalInvalid = 0;
 
208
    dmxGlobalX       = x;
 
209
    dmxGlobalY       = y;
 
210
 
 
211
    if (dmxGlobalX < 0)                dmxGlobalX = 0;
 
212
    if (dmxGlobalY < 0)                dmxGlobalY = 0;
 
213
    if (dmxGlobalX >= dmxGlobalWidth)  dmxGlobalX = dmxGlobalWidth  + delta -1;
 
214
    if (dmxGlobalY >= dmxGlobalHeight) dmxGlobalY = dmxGlobalHeight + delta -1;
 
215
    
 
216
    if ((dmxScreen = dmxFindFirstScreen(dmxGlobalX, dmxGlobalY))) {
 
217
        localX = dmxGlobalX - dmxScreen->rootXOrigin;
 
218
        localY = dmxGlobalY - dmxScreen->rootYOrigin;
 
219
        if ((pScreen = miPointerCurrentScreen())
 
220
            && pScreen->myNum == dmxScreen->index) {
 
221
                                /* Screen is old screen */
 
222
            if (block) dmxSigioBlock();
 
223
            miPointerAbsoluteCursor(localX, localY, GetTimeInMillis());
 
224
            if (block) dmxSigioUnblock();
 
225
        } else {
 
226
                                /* Screen is new */
 
227
            DMXDBG4("   New screen: old=%d new=%d localX=%d localY=%d\n",
 
228
                    pScreen->myNum, dmxScreen->index, localX, localY);
 
229
            if (block) dmxSigioBlock();
 
230
            dmxeqProcessInputEvents();
 
231
            miPointerSetNewScreen(dmxScreen->index, localX, localY);
 
232
            miPointerAbsoluteCursor(localX, localY, GetTimeInMillis());
 
233
            if (block) dmxSigioUnblock();
 
234
        }
 
235
        miPointerPosition(&localX, &localY);
 
236
 
 
237
        if ((pScreen = miPointerCurrentScreen())) {
 
238
            dmxGlobalX = localX + dmxScreens[pScreen->myNum].rootXOrigin;
 
239
            dmxGlobalY = localY + dmxScreens[pScreen->myNum].rootYOrigin;
 
240
            DMXDBG6("   Moved to dmxGlobalX=%d dmxGlobalY=%d"
 
241
                    " on screen index=%d/%d localX=%d localY=%d\n",
 
242
                    dmxGlobalX, dmxGlobalY,
 
243
                    dmxScreen ? dmxScreen->index : -1, pScreen->myNum,
 
244
                    localX, localY);
 
245
        }
 
246
    }
 
247
                                /* Send updates down to all core input
 
248
                                 * drivers */
 
249
    for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) {
 
250
        int j;
 
251
 
 
252
        for (j = 0; j < dmxInput->numDevs; j += dmxInput->devs[j]->binding)
 
253
            if (!dmxInput->detached
 
254
                && dmxInput->devs[j]->sendsCore
 
255
                && dmxInput->devs[j]->update_position)
 
256
                dmxInput->devs[j]->update_position(dmxInput->devs[j]->private,
 
257
                                                   dmxGlobalX, dmxGlobalY);
 
258
    }
 
259
    if (!dmxScreen) ProcessInputEvents();
 
260
}
 
261
 
 
262
#ifdef XINPUT
 
263
#define DMX_MAX_AXES 32         /* Max axes reported by this routine */
 
264
static void dmxExtMotion(DMXLocalInputInfoPtr dmxLocal,
 
265
                         int *v, int firstAxis, int axesCount,
 
266
                         DMXMotionType type, DMXBlockType block)
 
267
{
 
268
    DeviceIntPtr           pDevice = dmxLocal->pDevice;
 
269
    xEvent                 xE[2 * DMX_MAX_AXES/6];
 
270
    deviceKeyButtonPointer *xev    = (deviceKeyButtonPointer *)xE;
 
271
    deviceValuator         *xv     = (deviceValuator *)xev+1;
 
272
    int                    thisX   = 0;
 
273
    int                    thisY   = 0;
 
274
    int                    i;
 
275
    int                    count;
 
276
 
 
277
    memset(xE, 0, sizeof(xE));
 
278
 
 
279
    if (axesCount > DMX_MAX_AXES) axesCount = DMX_MAX_AXES;
 
280
 
 
281
    if (!pDevice->valuator->mode && axesCount == 2) {
 
282
                                /* The dmx console is a relative mode
 
283
                                 * device that sometimes reports
 
284
                                 * absolute motion.  It only has two
 
285
                                 * axes. */
 
286
        if (type == DMX_RELATIVE) {
 
287
            thisX = -v[0];
 
288
            thisY = -v[1];
 
289
            dmxLocal->lastX += thisX;
 
290
            dmxLocal->lastY += thisY;
 
291
            if (dmxLocal->update_position)
 
292
                dmxLocal->update_position(dmxLocal->private,
 
293
                                          dmxLocal->lastX, dmxLocal->lastY);
 
294
        } else {                    /* Convert to relative */
 
295
            if (dmxLocal->lastX || dmxLocal->lastY) {
 
296
                thisX = v[0] - dmxLocal->lastX;
 
297
                thisY = v[1] - dmxLocal->lastY;
 
298
            }
 
299
            dmxLocal->lastX = v[0];
 
300
            dmxLocal->lastY = v[1];
 
301
        }
 
302
        v[0] = thisX;
 
303
        v[1] = thisY;
 
304
    }
 
305
 
 
306
    if (axesCount <= 6) {
 
307
                                /* Optimize for the common case when
 
308
                                 * only 1 or 2 axes change. */
 
309
            xev->time          = GetTimeInMillis();
 
310
            xev->type          = DeviceMotionNotify;
 
311
            xev->detail        = 0;
 
312
            xev->deviceid      = pDevice->id | MORE_EVENTS;
 
313
            
 
314
            xv->type           = DeviceValuator;
 
315
            xv->deviceid       = pDevice->id;
 
316
            xv->num_valuators  = axesCount;
 
317
            xv->first_valuator = firstAxis;
 
318
            switch (xv->num_valuators) {
 
319
            case 6: xv->valuator5 = v[5];
 
320
            case 5: xv->valuator4 = v[4];
 
321
            case 4: xv->valuator3 = v[3];
 
322
            case 3: xv->valuator2 = v[2];
 
323
            case 2: xv->valuator1 = v[1];
 
324
            case 1: xv->valuator0 = v[0];
 
325
            }
 
326
            count              = 2;
 
327
    } else {
 
328
        for (i = 0, count = 0; i < axesCount; i += 6) {
 
329
            xev->time          = GetTimeInMillis();
 
330
            xev->type          = DeviceMotionNotify;
 
331
            xev->detail        = 0;
 
332
            xev->deviceid      = pDevice->id | MORE_EVENTS;
 
333
            xev               += 2;
 
334
            
 
335
            xv->type           = DeviceValuator;
 
336
            xv->deviceid       = pDevice->id;
 
337
            xv->num_valuators  = (i+6 >= axesCount ? axesCount - i : 6);
 
338
            xv->first_valuator = firstAxis + i;
 
339
            switch (xv->num_valuators) {
 
340
            case 6: xv->valuator5 = v[i+5];
 
341
            case 5: xv->valuator4 = v[i+4];
 
342
            case 4: xv->valuator3 = v[i+3];
 
343
            case 3: xv->valuator2 = v[i+2];
 
344
            case 2: xv->valuator1 = v[i+1];
 
345
            case 1: xv->valuator0 = v[i+0];
 
346
            }
 
347
            xv                += 2;
 
348
            count             += 2;
 
349
        }
 
350
    }
 
351
 
 
352
    if (block) dmxSigioBlock();
 
353
    dmxPointerPutMotionEvent(pDevice, firstAxis, axesCount, v, xev->time);
 
354
    dmxeqEnqueue(xE);
 
355
    if (block) dmxSigioUnblock();
 
356
}
 
357
 
 
358
static int dmxTranslateAndEnqueueExtEvent(DMXLocalInputInfoPtr dmxLocal,
 
359
                                          XEvent *e, DMXBlockType block)
 
360
{
 
361
    xEvent                 xE[2];
 
362
    deviceKeyButtonPointer *xev    = (deviceKeyButtonPointer *)xE;
 
363
    deviceValuator         *xv     = (deviceValuator *)xev+1;
 
364
    int                    type;
 
365
    int                    event   = -1;
 
366
    XDeviceKeyEvent        *ke     = (XDeviceKeyEvent *)e;
 
367
    XDeviceMotionEvent     *me     = (XDeviceMotionEvent *)e;
 
368
 
 
369
    if (!e) return -1;          /* No extended event passed, cannot handle */
 
370
    
 
371
    if ((XID)dmxLocal->deviceId != ke->deviceid) {
 
372
                                /* Search for the correct dmxLocal,
 
373
                                 * since backend and console events are
 
374
                                 * picked up for the first device on
 
375
                                 * that X server. */
 
376
        int i;
 
377
        DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
 
378
        for (i = 0; i < dmxInput->numDevs; i++) {
 
379
            dmxLocal = dmxInput->devs[i];
 
380
            if ((XID)dmxLocal->deviceId == ke->deviceid) break;
 
381
        }
 
382
    }
 
383
 
 
384
    if ((XID)dmxLocal->deviceId != ke->deviceid
 
385
        || (type = dmxMapLookup(dmxLocal, e->type)) < 0)
 
386
        return -1;    /* No mapping, so this event is unhandled */
 
387
 
 
388
    switch (type) {
 
389
    case XI_DeviceValuator:          event = DeviceValuator;          break;
 
390
    case XI_DeviceKeyPress:          event = DeviceKeyPress;          break;
 
391
    case XI_DeviceKeyRelease:        event = DeviceKeyRelease;        break;
 
392
    case XI_DeviceButtonPress:       event = DeviceButtonPress;       break;
 
393
    case XI_DeviceButtonRelease:     event = DeviceButtonRelease;     break;
 
394
    case XI_DeviceMotionNotify:      event = DeviceMotionNotify;      break;
 
395
    case XI_DeviceFocusIn:           event = DeviceFocusIn;           break;
 
396
    case XI_DeviceFocusOut:          event = DeviceFocusOut;          break;
 
397
    case XI_ProximityIn:             event = ProximityIn;             break;
 
398
    case XI_ProximityOut:            event = ProximityOut;            break;
 
399
    case XI_DeviceStateNotify:       event = DeviceStateNotify;       break;
 
400
    case XI_DeviceMappingNotify:     event = DeviceMappingNotify;     break;
 
401
    case XI_ChangeDeviceNotify:      event = ChangeDeviceNotify;      break;
 
402
    case XI_DeviceKeystateNotify:    event = DeviceStateNotify;       break;
 
403
    case XI_DeviceButtonstateNotify: event = DeviceStateNotify;       break;
 
404
    }
 
405
 
 
406
    switch (type) {
 
407
    case XI_DeviceKeyPress: 
 
408
    case XI_DeviceKeyRelease:
 
409
    case XI_DeviceButtonPress:
 
410
    case XI_DeviceButtonRelease:
 
411
    case XI_ProximityIn:
 
412
    case XI_ProximityOut:
 
413
        xev->type          = event;
 
414
        xev->detail        = ke->keycode; /* same as ->button */
 
415
        xev->deviceid      = dmxLocal->pDevice->id | MORE_EVENTS;
 
416
        xev->time          = GetTimeInMillis();
 
417
 
 
418
        xv->type           = DeviceValuator;
 
419
        xv->deviceid       = dmxLocal->pDevice->id;
 
420
        xv->num_valuators  = ke->axes_count;
 
421
        xv->first_valuator = ke->first_axis;
 
422
        xv->valuator0      = ke->axis_data[0];
 
423
        xv->valuator1      = ke->axis_data[1];
 
424
        xv->valuator2      = ke->axis_data[2];
 
425
        xv->valuator3      = ke->axis_data[3];
 
426
        xv->valuator4      = ke->axis_data[4];
 
427
        xv->valuator5      = ke->axis_data[5];
 
428
 
 
429
        if (block) dmxSigioBlock();
 
430
        dmxeqEnqueue(xE);
 
431
        if (block) dmxSigioUnblock();
 
432
        break;
 
433
 
 
434
    case XI_DeviceMotionNotify:
 
435
        dmxExtMotion(dmxLocal, me->axis_data, me->first_axis, me->axes_count,
 
436
                     DMX_ABSOLUTE, block);
 
437
        break;
 
438
    case XI_DeviceFocusIn:
 
439
    case XI_DeviceFocusOut:
 
440
    case XI_DeviceStateNotify:
 
441
    case XI_DeviceMappingNotify:
 
442
    case XI_ChangeDeviceNotify:
 
443
    case XI_DeviceKeystateNotify:
 
444
    case XI_DeviceButtonstateNotify:
 
445
                                /* These are ignored, since DMX will
 
446
                                 * generate its own events of these
 
447
                                 * types, as necessary.
 
448
 
 
449
                                 * Perhaps ChangeDeviceNotify should
 
450
                                 * generate an error, because it is
 
451
                                 * unexpected? */
 
452
        break;
 
453
    case XI_DeviceValuator:
 
454
    default:
 
455
        dmxLog(dmxWarning,
 
456
               "XInput extension event (remote=%d -> zero-based=%d)"
 
457
               " not supported yet\n", e->type, type);
 
458
        return -1;
 
459
    }
 
460
    return 0;
 
461
}
 
462
#endif
 
463
 
 
464
static int dmxGetButtonMapping(DMXLocalInputInfoPtr dmxLocal, int button)
 
465
{
 
466
    ButtonClassPtr b = dmxLocal->pDevice->button;
 
467
 
 
468
    if (button > b->numButtons) { /* This shouldn't happen. */
 
469
        dmxLog(dmxWarning, "Button %d pressed, but only %d buttons?!?\n",
 
470
               button, b->numButtons);
 
471
        return button;
 
472
    }
 
473
    return b->map[button];
 
474
}
 
475
 
 
476
/** Return DMX's notion of the pointer position in the global coordinate
 
477
 * space. */
 
478
void dmxGetGlobalPosition(int *x, int *y)
 
479
{
 
480
    *x = dmxGlobalX;
 
481
    *y = dmxGlobalY;
 
482
}
 
483
 
 
484
/** Invalidate the global position for #dmxCoreMotion. */
 
485
void dmxInvalidateGlobalPosition(void)
 
486
{
 
487
    dmxGlobalInvalid = 1;
 
488
}
 
489
 
 
490
/** Enqueue a motion event for \a pDev.  The \a v vector has length \a
 
491
 * axesCount, and contains values for each of the axes, starting at \a
 
492
 * firstAxes.
 
493
 *
 
494
 * The \a type of the motion may be \a DMX_RELATIVE, \a DMX_ABSOLUTE, or
 
495
 * \a DMX_ABSOLUTE_CONFINED (in the latter case, the pointer will not be
 
496
 * allowed to move outside the global boundaires).
 
497
 *
 
498
 * If \a block is set to \a DMX_BLOCK, then the SIGIO handler will be
 
499
 * blocked around calls to #dmxeqEnqueue(). */
 
500
void dmxMotion(DevicePtr pDev, int *v, int firstAxes, int axesCount,
 
501
               DMXMotionType type, DMXBlockType block)
 
502
{
 
503
#ifdef XINPUT
 
504
    GETDMXLOCALFROMPDEV;
 
505
 
 
506
    if (!dmxLocal->sendsCore) {
 
507
        dmxExtMotion(dmxLocal, v, firstAxes, axesCount, type, block);
 
508
        return;
 
509
    }
 
510
#endif
 
511
    if (axesCount == 2) switch (type) {
 
512
      case DMX_RELATIVE:          dmxCoreMotion(dmxGlobalX - v[0],
 
513
                                                dmxGlobalY - v[1],
 
514
                                                0, block);              break;
 
515
      case DMX_ABSOLUTE:          dmxCoreMotion(v[0], v[1], 0, block);  break;
 
516
      case DMX_ABSOLUTE_CONFINED: dmxCoreMotion(v[0], v[1], -1, block); break;
 
517
    }
 
518
}
 
519
 
 
520
static KeySym dmxKeyCodeToKeySym(DMXLocalInputInfoPtr dmxLocal,
 
521
                                 KeyCode keyCode)
 
522
{
 
523
    KeySymsPtr pKeySyms = NULL;
 
524
 
 
525
    if (!dmxLocal || !dmxLocal->pDevice || !dmxLocal->pDevice->key)
 
526
        return NoSymbol;
 
527
    pKeySyms = &dmxLocal->pDevice->key->curKeySyms;
 
528
    if (!pKeySyms) return NoSymbol;
 
529
    
 
530
    if (keyCode > pKeySyms->minKeyCode && keyCode <= pKeySyms->maxKeyCode) {
 
531
        DMXDBG2("dmxKeyCodeToKeySym: Translated keyCode=%d to keySym=0x%04x\n",
 
532
                keyCode,
 
533
                pKeySyms->map[(keyCode - pKeySyms->minKeyCode)
 
534
                              * pKeySyms->mapWidth]);
 
535
               
 
536
        return pKeySyms->map[(keyCode - pKeySyms->minKeyCode)
 
537
                             * pKeySyms->mapWidth];
 
538
    }
 
539
    return NoSymbol;
 
540
}
 
541
 
 
542
static KeyCode dmxKeySymToKeyCode(DMXLocalInputInfoPtr dmxLocal, KeySym keySym,
 
543
                                  int tryFirst)
 
544
{
 
545
    KeySymsPtr pKeySyms = &dmxLocal->pDevice->key->curKeySyms;
 
546
    int        i;
 
547
 
 
548
                                /* Optimize for similar maps */
 
549
    if (tryFirst >= pKeySyms->minKeyCode
 
550
        && tryFirst <= pKeySyms->maxKeyCode
 
551
        && pKeySyms->map[(tryFirst - pKeySyms->minKeyCode)
 
552
                         * pKeySyms->mapWidth] == keySym)
 
553
        return tryFirst;
 
554
 
 
555
    for (i = pKeySyms->minKeyCode; i <= pKeySyms->maxKeyCode; i++) {
 
556
        if (pKeySyms->map[(i - pKeySyms->minKeyCode)
 
557
                          * pKeySyms->mapWidth] == keySym) {
 
558
            DMXDBG3("dmxKeySymToKeyCode: Translated keySym=0x%04x to"
 
559
                    " keyCode=%d (reverses to core keySym=0x%04x)\n",
 
560
                    keySym, i, dmxKeyCodeToKeySym(dmxLocalCoreKeyboard,i));
 
561
            return i;
 
562
        }
 
563
    }
 
564
    return 0;
 
565
}
 
566
 
 
567
static int dmxFixup(DevicePtr pDev, int detail, KeySym keySym)
 
568
{
 
569
    GETDMXLOCALFROMPDEV;
 
570
    int keyCode;
 
571
    
 
572
    if (!dmxLocal->pDevice->key) {
 
573
        dmxLog(dmxWarning, "dmxFixup: not a keyboard device (%s)\n",
 
574
               dmxLocal->pDevice->name);
 
575
        return NoSymbol;
 
576
    }
 
577
    if (!keySym) keySym = dmxKeyCodeToKeySym(dmxLocal, detail);
 
578
    if (keySym == NoSymbol) return detail;
 
579
    keyCode = dmxKeySymToKeyCode(dmxLocalCoreKeyboard, keySym, detail);
 
580
 
 
581
    return keyCode ? keyCode : detail;
 
582
}
 
583
 
 
584
/** Enqueue a non-motion event from the \a pDev device with the
 
585
 * specified \a type and \a detail.  If the event is a KeyPress or
 
586
 * KeyRelease event, then the \a keySym is also specified.
 
587
 *
 
588
 * If \a block is set to \a DMX_BLOCK, then the SIGIO handler will be
 
589
 * blocked around calls to #dmxeqEnqueue(). */
 
590
    
 
591
void dmxEnqueue(DevicePtr pDev, int type, int detail, KeySym keySym,
 
592
                XEvent *e, DMXBlockType block)
 
593
{
 
594
    GETDMXINPUTFROMPDEV;
 
595
    xEvent xE;
 
596
 
 
597
    DMXDBG2("dmxEnqueue: Enqueuing type=%d detail=0x%0x\n", type, detail);
 
598
 
 
599
    switch (type) {
 
600
    case KeyPress:
 
601
    case KeyRelease:
 
602
        if (!keySym) keySym = dmxKeyCodeToKeySym(dmxLocal, detail);
 
603
        if (dmxCheckFunctionKeys(dmxLocal, type, keySym))
 
604
            return;
 
605
        if (dmxLocal->sendsCore && dmxLocal != dmxLocalCoreKeyboard)
 
606
            xE.u.u.detail = dmxFixup(pDev, detail, keySym);
 
607
        break;
 
608
    case ButtonPress:
 
609
    case ButtonRelease:
 
610
        detail = dmxGetButtonMapping(dmxLocal, detail);
 
611
        break;
 
612
    case MotionNotify:
 
613
        /* All MotionNotify events should be sent via dmxCoreMotion and
 
614
         * dmxExtMotion -- no input driver should build motion events by
 
615
         * hand. */
 
616
        dmxLog(dmxError, "dmxEnqueueXEvent: MotionNotify not allowed here\n");
 
617
        break;
 
618
                                /* Always ignore these events */
 
619
    case EnterNotify:
 
620
    case LeaveNotify:
 
621
    case KeymapNotify:
 
622
    case MappingNotify:         /* This is sent because we change the
 
623
                                 * modifier map on the backend/console
 
624
                                 * input device so that we have complete
 
625
                                 * control of the input device LEDs. */
 
626
        return;
 
627
    default:
 
628
#ifdef XINPUT
 
629
        if (type == ProximityIn || type == ProximityOut) {
 
630
            if (dmxLocal->sendsCore) return; /* Not a core event */
 
631
            break;
 
632
        }
 
633
#endif
 
634
        if (type >= LASTEvent) {
 
635
#ifdef XINPUT
 
636
            if (dmxTranslateAndEnqueueExtEvent(dmxLocal, e, block))
 
637
#endif
 
638
                dmxLogInput(dmxInput, "Unhandled extension event: %d\n", type);
 
639
        } else {
 
640
            dmxLogInput(dmxInput, "Unhandled event: %d (%s)\n",
 
641
                        type, dmxEventName(type));
 
642
        }
 
643
        return;
 
644
    }
 
645
 
 
646
    memset(&xE, 0, sizeof(xE));
 
647
    xE.u.u.type                = type;
 
648
    xE.u.u.detail              = detail;
 
649
    xE.u.keyButtonPointer.time = GetTimeInMillis();
 
650
 
 
651
#ifdef XINPUT
 
652
    if (!dmxLocal->sendsCore) dmxEnqueueExtEvent(dmxLocal, &xE, block);
 
653
    else
 
654
#endif
 
655
        dmxeqEnqueue(&xE);
 
656
}
 
657
 
 
658
/** A pointer to this routine is passed to low-level input drivers so
 
659
 * that all special keychecking is unified to this file.  This function
 
660
 * returns 0 if no special keys have been pressed.  If the user has
 
661
 * requested termination of the DMX server, -1 is returned.  If the user
 
662
 * has requested a switch to a VT, then the (1-based) number of that VT
 
663
 * is returned. */
 
664
int dmxCheckSpecialKeys(DevicePtr pDev, KeySym keySym)
 
665
{
 
666
    GETDMXINPUTFROMPDEV;
 
667
    int            vt    = 0;
 
668
    unsigned short state = 0;
 
669
 
 
670
    if (dmxLocal->sendsCore)
 
671
        state = dmxLocalCoreKeyboard->pDevice->key->state;
 
672
    else if (dmxLocal->pDevice->key)
 
673
        state = dmxLocal->pDevice->key->state;
 
674
 
 
675
    if (!dmxLocal->sendsCore) return 0; /* Only for core devices */
 
676
 
 
677
    DMXDBG2("dmxCheckSpecialKeys: keySym=0x%04x state=0x%04x\n", keySym,state);
 
678
    
 
679
    if ((state & (ControlMask|Mod1Mask)) != (ControlMask|Mod1Mask)) return 0;
 
680
    
 
681
    switch (keySym) {
 
682
    case XK_F1:
 
683
    case XK_F2:
 
684
    case XK_F3:
 
685
    case XK_F4:
 
686
    case XK_F5:
 
687
    case XK_F6:
 
688
    case XK_F7:
 
689
    case XK_F8:
 
690
    case XK_F9:
 
691
    case XK_F10:
 
692
        vt = keySym - XK_F1 + 1;
 
693
        break;
 
694
 
 
695
    case XK_F11:
 
696
    case XK_F12:
 
697
        vt = keySym - XK_F11 + 11;
 
698
        break;
 
699
 
 
700
    case XK_q:                  /* To avoid confusion  */
 
701
    case XK_BackSpace:
 
702
    case XK_Delete:
 
703
    case XK_KP_Delete:
 
704
        dmxLog(dmxInfo, "User request for termination\n");
 
705
        dispatchException |= DE_TERMINATE;
 
706
        return -1;              /* Terminate */
 
707
    }
 
708
 
 
709
    if (vt) {
 
710
        dmxLog(dmxInfo, "Request to switch to VT %d\n", vt);
 
711
        dmxInput->vt_switch_pending = vt;
 
712
        return vt;
 
713
    }
 
714
 
 
715
    return 0;                   /* Do nothing */
 
716
}