1/*
2 * Copyright © 2009 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25/**
26 * @file eventconvert.c
27 * This file contains event conversion routines from InternalEvent to the
28 * matching protocol events.
29 */
30
31#ifdef HAVE_DIX_CONFIG_H
32#include <dix-config.h>
33#endif
34
35#include <stdint.h>
36#include <X11/X.h>
37#include <X11/extensions/XIproto.h>
38#include <X11/extensions/XI2proto.h>
39#include <X11/extensions/XI.h>
40#include <X11/extensions/XI2.h>
41
42#include "dix.h"
43#include "inputstr.h"
44#include "misc.h"
45#include "eventstr.h"
46#include "exglobals.h"
47#include "eventconvert.h"
48#include "xiquerydevice.h"
49#include "xkbsrv.h"
50
51
52static int countValuators(DeviceEvent *ev, int *first);
53static int getValuatorEvents(DeviceEvent *ev, deviceValuator *xv);
54static int eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count);
55static int eventToDeviceChanged(DeviceChangedEvent *ev, xEvent **dcce);
56static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi);
57static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi);
58
59/* Do not use, read comments below */
60BOOL EventIsKeyRepeat(xEvent *event);
61
62/**
63 * Hack to allow detectable autorepeat for core and XI1 events.
64 * The sequence number is unused until we send to the client and can be
65 * misused to store data. More or less, anyway.
66 *
67 * Do not use this. It may change any time without warning, eat your babies
68 * and piss on your cat.
69 */
70static void
71EventSetKeyRepeatFlag(xEvent *event, BOOL on)
72{
73    event->u.u.sequenceNumber = on;
74}
75
76/**
77 * Check if the event was marked as a repeat event before.
78 * NOTE: This is a nasty hack and should NOT be used by anyone else but
79 * TryClientEvents.
80 */
81BOOL
82EventIsKeyRepeat(xEvent *event)
83{
84    return !!event->u.u.sequenceNumber;
85}
86
87/**
88 * Convert the given event to the respective core event.
89 *
90 * Return values:
91 * Success ... core contains the matching core event.
92 * BadValue .. One or more values in the internal event are invalid.
93 * BadMatch .. The event has no core equivalent.
94 *
95 * @param[in] event The event to convert into a core event.
96 * @param[in] core The memory location to store the core event at.
97 * @return Success or the matching error code.
98 */
99int
100EventToCore(InternalEvent *event, xEvent *core)
101{
102    switch(event->any.type)
103    {
104        case ET_Motion:
105            {
106                DeviceEvent *e = &event->device_event;
107                /* Don't create core motion event if neither x nor y are
108                 * present */
109                if (!BitIsOn(e->valuators.mask, 0) &&
110                    !BitIsOn(e->valuators.mask, 1))
111                    return BadMatch;
112            }
113            /* fallthrough */
114        case ET_ButtonPress:
115        case ET_ButtonRelease:
116        case ET_KeyPress:
117        case ET_KeyRelease:
118            {
119                DeviceEvent *e = &event->device_event;
120
121                if (e->detail.key > 0xFF)
122                    return BadMatch;
123
124                memset(core, 0, sizeof(xEvent));
125                core->u.u.type = e->type - ET_KeyPress + KeyPress;
126                core->u.u.detail = e->detail.key & 0xFF;
127                core->u.keyButtonPointer.time = e->time;
128                core->u.keyButtonPointer.rootX = e->root_x;
129                core->u.keyButtonPointer.rootY = e->root_y;
130                core->u.keyButtonPointer.state = e->corestate;
131                core->u.keyButtonPointer.root = e->root;
132                EventSetKeyRepeatFlag(core, (e->type == ET_KeyPress && e->key_repeat));
133            }
134            break;
135        case ET_ProximityIn:
136        case ET_ProximityOut:
137        case ET_RawKeyPress:
138        case ET_RawKeyRelease:
139        case ET_RawButtonPress:
140        case ET_RawButtonRelease:
141        case ET_RawMotion:
142            return BadMatch;
143        default:
144            /* XXX: */
145            ErrorF("[dix] EventToCore: Not implemented yet \n");
146            return BadImplementation;
147    }
148    return Success;
149}
150
151/**
152 * Convert the given event to the respective XI 1.x event and store it in
153 * xi. xi is allocated on demand and must be freed by the caller.
154 * count returns the number of events in xi. If count is 1, and the type of
155 * xi is GenericEvent, then xi may be larger than 32 bytes.
156 *
157 * Return values:
158 * Success ... core contains the matching core event.
159 * BadValue .. One or more values in the internal event are invalid.
160 * BadMatch .. The event has no XI equivalent.
161 *
162 * @param[in] ev The event to convert into an XI 1 event.
163 * @param[out] xi Future memory location for the XI event.
164 * @param[out] count Number of elements in xi.
165 *
166 * @return Success or the error code.
167 */
168int
169EventToXI(InternalEvent *ev, xEvent **xi, int *count)
170{
171    switch (ev->any.type)
172    {
173        case ET_Motion:
174        case ET_ButtonPress:
175        case ET_ButtonRelease:
176        case ET_KeyPress:
177        case ET_KeyRelease:
178        case ET_ProximityIn:
179        case ET_ProximityOut:
180            return eventToKeyButtonPointer(&ev->device_event, xi, count);
181        case ET_DeviceChanged:
182        case ET_RawKeyPress:
183        case ET_RawKeyRelease:
184        case ET_RawButtonPress:
185        case ET_RawButtonRelease:
186        case ET_RawMotion:
187            *count = 0;
188            *xi = NULL;
189            return BadMatch;
190        default:
191            break;
192    }
193
194    ErrorF("[dix] EventToXI: Not implemented for %d \n", ev->any.type);
195    return BadImplementation;
196}
197
198/**
199 * Convert the given event to the respective XI 2.x event and store it in xi.
200 * xi is allocated on demand and must be freed by the caller.
201 *
202 * Return values:
203 * Success ... core contains the matching core event.
204 * BadValue .. One or more values in the internal event are invalid.
205 * BadMatch .. The event has no XI2 equivalent.
206 *
207 * @param[in] ev The event to convert into an XI2 event
208 * @param[out] xi Future memory location for the XI2 event.
209 *
210 * @return Success or the error code.
211 */
212int
213EventToXI2(InternalEvent *ev, xEvent **xi)
214{
215    switch (ev->any.type)
216    {
217        /* Enter/FocusIn are for grabs. We don't need an actual event, since
218         * the real events delivered are triggered elsewhere */
219        case ET_Enter:
220        case ET_FocusIn:
221            *xi = NULL;
222            return Success;
223        case ET_Motion:
224        case ET_ButtonPress:
225        case ET_ButtonRelease:
226        case ET_KeyPress:
227        case ET_KeyRelease:
228            return eventToDeviceEvent(&ev->device_event, xi);
229        case ET_ProximityIn:
230        case ET_ProximityOut:
231            *xi = NULL;
232            return BadMatch;
233        case ET_DeviceChanged:
234            return eventToDeviceChanged(&ev->changed_event, xi);
235        case ET_RawKeyPress:
236        case ET_RawKeyRelease:
237        case ET_RawButtonPress:
238        case ET_RawButtonRelease:
239        case ET_RawMotion:
240            return eventToRawEvent(&ev->raw_event, xi);
241        default:
242            break;
243    }
244
245    ErrorF("[dix] EventToXI2: Not implemented for %d \n", ev->any.type);
246    return BadImplementation;
247}
248
249static int
250eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count)
251{
252    int num_events;
253    int first; /* dummy */
254    deviceKeyButtonPointer *kbp;
255
256    /* Sorry, XI 1.x protocol restrictions. */
257    if (ev->detail.button > 0xFF || ev->deviceid >= 0x80)
258    {
259        *count = 0;
260        return Success;
261    }
262
263    num_events = (countValuators(ev, &first) + 5)/6; /* valuator ev */
264    if (num_events <= 0)
265    {
266        switch (ev->type)
267        {
268            case ET_KeyPress:
269            case ET_KeyRelease:
270            case ET_ButtonPress:
271            case ET_ButtonRelease:
272                /* no axes is ok */
273                break;
274            case ET_Motion:
275            case ET_ProximityIn:
276            case ET_ProximityOut:
277                *count = 0;
278                return BadMatch;
279        }
280    }
281
282    num_events++; /* the actual event event */
283
284    *xi = calloc(num_events, sizeof(xEvent));
285    if (!(*xi))
286    {
287        return BadAlloc;
288    }
289
290    kbp           = (deviceKeyButtonPointer*)(*xi);
291    kbp->detail   = ev->detail.button;
292    kbp->time     = ev->time;
293    kbp->root     = ev->root;
294    kbp->root_x   = ev->root_x;
295    kbp->root_y   = ev->root_y;
296    kbp->deviceid = ev->deviceid;
297    kbp->state    = ev->corestate;
298    EventSetKeyRepeatFlag((xEvent*)kbp,
299                          (ev->type == ET_KeyPress && ev->key_repeat));
300
301    if (num_events > 1)
302        kbp->deviceid |= MORE_EVENTS;
303
304    switch(ev->type)
305    {
306        case ET_Motion:        kbp->type = DeviceMotionNotify;  break;
307        case ET_ButtonPress:   kbp->type = DeviceButtonPress;   break;
308        case ET_ButtonRelease: kbp->type = DeviceButtonRelease; break;
309        case ET_KeyPress:      kbp->type = DeviceKeyPress;      break;
310        case ET_KeyRelease:    kbp->type = DeviceKeyRelease;    break;
311        case ET_ProximityIn:   kbp->type = ProximityIn;         break;
312        case ET_ProximityOut:  kbp->type = ProximityOut;        break;
313        default:
314            break;
315    }
316
317    if (num_events > 1)
318    {
319        getValuatorEvents(ev, (deviceValuator*)(kbp + 1));
320    }
321
322    *count = num_events;
323    return Success;
324}
325
326
327/**
328 * Set first to the first valuator in the event ev and return the number of
329 * valuators from first to the last set valuator.
330 */
331static int
332countValuators(DeviceEvent *ev, int *first)
333{
334    int first_valuator = -1, last_valuator = -1, num_valuators = 0;
335    int i;
336
337    for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
338    {
339        if (BitIsOn(ev->valuators.mask, i))
340        {
341            if (first_valuator == -1)
342                first_valuator = i;
343            last_valuator = i;
344        }
345    }
346
347    if (first_valuator != -1)
348    {
349        num_valuators = last_valuator - first_valuator + 1;
350        *first = first_valuator;
351    }
352
353    return num_valuators;
354}
355
356static int
357getValuatorEvents(DeviceEvent *ev, deviceValuator *xv)
358{
359    int i;
360    int state = 0;
361    int first_valuator, num_valuators;
362
363
364    num_valuators = countValuators(ev, &first_valuator);
365    if (num_valuators > 0)
366    {
367        DeviceIntPtr dev = NULL;
368        dixLookupDevice(&dev, ev->deviceid, serverClient, DixUseAccess);
369        /* State needs to be assembled BEFORE the device is updated. */
370        state = (dev && dev->key) ? XkbStateFieldFromRec(&dev->key->xkbInfo->state) : 0;
371        state |= (dev && dev->button) ? (dev->button->state) : 0;
372    }
373
374    for (i = 0; i < num_valuators; i += 6, xv++) {
375        INT32 *valuators = &xv->valuator0; // Treat all 6 vals as an array
376        int j;
377
378        xv->type = DeviceValuator;
379        xv->first_valuator = first_valuator + i;
380        xv->num_valuators = ((num_valuators - i) > 6) ? 6 : (num_valuators - i);
381        xv->deviceid = ev->deviceid;
382        xv->device_state = state;
383
384        /* Unset valuators in masked valuator events have the proper data values
385         * in the case of an absolute axis in between two set valuators. */
386        for (j = 0; j < xv->num_valuators; j++)
387            valuators[j] = ev->valuators.data[xv->first_valuator + j];
388
389        if (i + 6 < num_valuators)
390            xv->deviceid |= MORE_EVENTS;
391    }
392
393    return (num_valuators + 5) / 6;
394}
395
396
397static int
398appendKeyInfo(DeviceChangedEvent *dce, xXIKeyInfo* info)
399{
400    uint32_t *kc;
401    int i;
402
403    info->type = XIKeyClass;
404    info->num_keycodes = dce->keys.max_keycode - dce->keys.min_keycode + 1;
405    info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes;
406    info->sourceid = dce->sourceid;
407
408    kc = (uint32_t*)&info[1];
409    for (i = 0; i < info->num_keycodes; i++)
410        *kc++ = i + dce->keys.min_keycode;
411
412    return info->length * 4;
413}
414
415static int
416appendButtonInfo(DeviceChangedEvent *dce, xXIButtonInfo *info)
417{
418    unsigned char *bits;
419    int mask_len;
420
421    mask_len = bytes_to_int32(bits_to_bytes(dce->buttons.num_buttons));
422
423    info->type = XIButtonClass;
424    info->num_buttons = dce->buttons.num_buttons;
425    info->length = bytes_to_int32(sizeof(xXIButtonInfo)) +
426                   info->num_buttons + mask_len;
427    info->sourceid = dce->sourceid;
428
429    bits = (unsigned char*)&info[1];
430    memset(bits, 0, mask_len * 4);
431    /* FIXME: is_down? */
432
433    bits += mask_len * 4;
434    memcpy(bits, dce->buttons.names, dce->buttons.num_buttons * sizeof(Atom));
435
436    return info->length * 4;
437}
438
439static int
440appendValuatorInfo(DeviceChangedEvent *dce, xXIValuatorInfo *info, int axisnumber)
441{
442    info->type = XIValuatorClass;
443    info->length = sizeof(xXIValuatorInfo)/4;
444    info->label = dce->valuators[axisnumber].name;
445    info->min.integral = dce->valuators[axisnumber].min;
446    info->min.frac = 0;
447    info->max.integral = dce->valuators[axisnumber].max;
448    info->max.frac = 0;
449    /* FIXME: value */
450    info->value.integral = 0;
451    info->value.frac = 0;
452    info->resolution = dce->valuators[axisnumber].resolution;
453    info->number = axisnumber;
454    info->mode = dce->valuators[axisnumber].mode;
455    info->sourceid = dce->sourceid;
456
457    return info->length * 4;
458}
459
460static int
461eventToDeviceChanged(DeviceChangedEvent *dce, xEvent **xi)
462{
463    xXIDeviceChangedEvent *dcce;
464    int len = sizeof(xXIDeviceChangedEvent);
465    int nkeys;
466    char *ptr;
467
468    if (dce->buttons.num_buttons)
469    {
470        len += sizeof(xXIButtonInfo);
471        len += dce->buttons.num_buttons * sizeof(Atom); /* button names */
472        len += pad_to_int32(bits_to_bytes(dce->buttons.num_buttons));
473    }
474    if (dce->num_valuators)
475        len += sizeof(xXIValuatorInfo) * dce->num_valuators;
476
477    nkeys = (dce->keys.max_keycode > 0) ?
478                dce->keys.max_keycode - dce->keys.min_keycode + 1 : 0;
479    if (nkeys > 0)
480    {
481        len += sizeof(xXIKeyInfo);
482        len += sizeof(CARD32) * nkeys; /* keycodes */
483    }
484
485    dcce = calloc(1, len);
486    if (!dcce)
487    {
488        ErrorF("[Xi] BadAlloc in SendDeviceChangedEvent.\n");
489        return BadAlloc;
490    }
491
492    dcce->type         = GenericEvent;
493    dcce->extension    = IReqCode;
494    dcce->evtype       = XI_DeviceChanged;
495    dcce->time         = dce->time;
496    dcce->deviceid     = dce->deviceid;
497    dcce->sourceid     = dce->sourceid;
498    dcce->reason       = (dce->flags & DEVCHANGE_DEVICE_CHANGE) ? XIDeviceChange : XISlaveSwitch;
499    dcce->num_classes  = 0;
500    dcce->length = bytes_to_int32(len - sizeof(xEvent));
501
502    ptr = (char*)&dcce[1];
503    if (dce->buttons.num_buttons)
504    {
505        dcce->num_classes++;
506        ptr += appendButtonInfo(dce, (xXIButtonInfo*)ptr);
507    }
508
509    if (nkeys)
510    {
511        dcce->num_classes++;
512        ptr += appendKeyInfo(dce, (xXIKeyInfo*)ptr);
513    }
514
515    if (dce->num_valuators)
516    {
517        int i;
518
519        dcce->num_classes += dce->num_valuators;
520        for (i = 0; i < dce->num_valuators; i++)
521            ptr += appendValuatorInfo(dce, (xXIValuatorInfo*)ptr, i);
522    }
523
524    *xi = (xEvent*)dcce;
525
526    return Success;
527}
528
529static int count_bits(unsigned char* ptr, int len)
530{
531    int bits = 0;
532    unsigned int i;
533    unsigned char x;
534
535    for (i = 0; i < len; i++)
536    {
537        x = ptr[i];
538        while(x > 0)
539        {
540            bits += (x & 0x1);
541            x >>= 1;
542        }
543    }
544    return bits;
545}
546
547static int
548eventToDeviceEvent(DeviceEvent *ev, xEvent **xi)
549{
550    int len = sizeof(xXIDeviceEvent);
551    xXIDeviceEvent *xde;
552    int i, btlen, vallen;
553    char *ptr;
554    FP3232 *axisval;
555
556    /* FIXME: this should just send the buttons we have, not MAX_BUTTONs. Same
557     * with MAX_VALUATORS below */
558    /* btlen is in 4 byte units */
559    btlen = bytes_to_int32(bits_to_bytes(MAX_BUTTONS));
560    len += btlen * 4; /* buttonmask len */
561
562
563    vallen = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask)/sizeof(ev->valuators.mask[0]));
564    len += vallen * 2 * sizeof(uint32_t); /* axisvalues */
565    vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS));
566    len += vallen * 4; /* valuators mask */
567
568    *xi = calloc(1, len);
569    xde = (xXIDeviceEvent*)*xi;
570    xde->type           = GenericEvent;
571    xde->extension      = IReqCode;
572    xde->evtype         = GetXI2Type((InternalEvent*)ev);
573    xde->time           = ev->time;
574    xde->length         = bytes_to_int32(len - sizeof(xEvent));
575    xde->detail         = ev->detail.button;
576    xde->root           = ev->root;
577    xde->buttons_len    = btlen;
578    xde->valuators_len  = vallen;
579    xde->deviceid       = ev->deviceid;
580    xde->sourceid       = ev->sourceid;
581    xde->root_x         = FP1616(ev->root_x, ev->root_x_frac);
582    xde->root_y         = FP1616(ev->root_y, ev->root_y_frac);
583
584    if (ev->key_repeat)
585        xde->flags      |= XIKeyRepeat;
586
587    xde->mods.base_mods         = ev->mods.base;
588    xde->mods.latched_mods      = ev->mods.latched;
589    xde->mods.locked_mods       = ev->mods.locked;
590    xde->mods.effective_mods    = ev->mods.effective;
591
592    xde->group.base_group       = ev->group.base;
593    xde->group.latched_group    = ev->group.latched;
594    xde->group.locked_group     = ev->group.locked;
595    xde->group.effective_group  = ev->group.effective;
596
597    ptr = (char*)&xde[1];
598    for (i = 0; i < sizeof(ev->buttons) * 8; i++)
599    {
600        if (BitIsOn(ev->buttons, i))
601            SetBit(ptr, i);
602    }
603
604    ptr += xde->buttons_len * 4;
605    axisval = (FP3232*)(ptr + xde->valuators_len * 4);
606    for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
607    {
608        if (BitIsOn(ev->valuators.mask, i))
609        {
610            SetBit(ptr, i);
611            axisval->integral = ev->valuators.data[i];
612            axisval->frac = ev->valuators.data_frac[i];
613            axisval++;
614        }
615    }
616
617    return Success;
618}
619
620static int
621eventToRawEvent(RawDeviceEvent *ev, xEvent **xi)
622{
623    xXIRawEvent* raw;
624    int vallen, nvals;
625    int i, len = sizeof(xXIRawEvent);
626    char *ptr;
627    FP3232 *axisval;
628
629    nvals = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask));
630    len += nvals * sizeof(FP3232) * 2; /* 8 byte per valuator, once
631                                    raw, once processed */
632    vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS));
633    len += vallen * 4; /* valuators mask */
634
635    *xi = calloc(1, len);
636    raw = (xXIRawEvent*)*xi;
637    raw->type           = GenericEvent;
638    raw->extension      = IReqCode;
639    raw->evtype         = GetXI2Type((InternalEvent*)ev);
640    raw->time           = ev->time;
641    raw->length         = bytes_to_int32(len - sizeof(xEvent));
642    raw->detail         = ev->detail.button;
643    raw->deviceid       = ev->deviceid;
644    raw->valuators_len  = vallen;
645
646    ptr = (char*)&raw[1];
647    axisval = (FP3232*)(ptr + raw->valuators_len * 4);
648    for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
649    {
650        if (BitIsOn(ev->valuators.mask, i))
651        {
652            SetBit(ptr, i);
653            axisval->integral = ev->valuators.data[i];
654            axisval->frac = ev->valuators.data_frac[i];
655            (axisval + nvals)->integral = ev->valuators.data_raw[i];
656            (axisval + nvals)->frac = ev->valuators.data_raw_frac[i];
657            axisval++;
658        }
659    }
660
661    return Success;
662}
663
664/**
665 * Return the corresponding core type for the given event or 0 if no core
666 * equivalent exists.
667 */
668int
669GetCoreType(InternalEvent *event)
670{
671    int coretype = 0;
672    switch(event->any.type)
673    {
674        case ET_Motion:         coretype = MotionNotify;  break;
675        case ET_ButtonPress:    coretype = ButtonPress;   break;
676        case ET_ButtonRelease:  coretype = ButtonRelease; break;
677        case ET_KeyPress:       coretype = KeyPress;      break;
678        case ET_KeyRelease:     coretype = KeyRelease;    break;
679        default:
680            break;
681    }
682    return coretype;
683}
684
685/**
686 * Return the corresponding XI 1.x type for the given event or 0 if no
687 * equivalent exists.
688 */
689int
690GetXIType(InternalEvent *event)
691{
692    int xitype = 0;
693    switch(event->any.type)
694    {
695        case ET_Motion:         xitype = DeviceMotionNotify;  break;
696        case ET_ButtonPress:    xitype = DeviceButtonPress;   break;
697        case ET_ButtonRelease:  xitype = DeviceButtonRelease; break;
698        case ET_KeyPress:       xitype = DeviceKeyPress;      break;
699        case ET_KeyRelease:     xitype = DeviceKeyRelease;    break;
700        case ET_ProximityIn:    xitype = ProximityIn;         break;
701        case ET_ProximityOut:   xitype = ProximityOut;        break;
702        default:
703            break;
704    }
705    return xitype;
706}
707
708/**
709 * Return the corresponding XI 2.x type for the given event or 0 if no
710 * equivalent exists.
711 */
712int
713GetXI2Type(InternalEvent *event)
714{
715    int xi2type = 0;
716
717    switch(event->any.type)
718    {
719        case ET_Motion:         xi2type = XI_Motion;           break;
720        case ET_ButtonPress:    xi2type = XI_ButtonPress;      break;
721        case ET_ButtonRelease:  xi2type = XI_ButtonRelease;    break;
722        case ET_KeyPress:       xi2type = XI_KeyPress;         break;
723        case ET_KeyRelease:     xi2type = XI_KeyRelease;       break;
724        case ET_Enter:          xi2type = XI_Enter;            break;
725        case ET_Leave:          xi2type = XI_Leave;            break;
726        case ET_Hierarchy:      xi2type = XI_HierarchyChanged; break;
727        case ET_DeviceChanged:  xi2type = XI_DeviceChanged;    break;
728        case ET_RawKeyPress:    xi2type = XI_RawKeyPress;      break;
729        case ET_RawKeyRelease:  xi2type = XI_RawKeyRelease;    break;
730        case ET_RawButtonPress: xi2type = XI_RawButtonPress;   break;
731        case ET_RawButtonRelease: xi2type = XI_RawButtonRelease; break;
732        case ET_RawMotion:      xi2type = XI_RawMotion;        break;
733        case ET_FocusIn:        xi2type = XI_FocusIn;          break;
734        case ET_FocusOut:       xi2type = XI_FocusOut;         break;
735        default:
736            break;
737    }
738    return xi2type;
739}
740