eventconvert.c revision 6747b715
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        case ET_ButtonPress:
106        case ET_ButtonRelease:
107        case ET_KeyPress:
108        case ET_KeyRelease:
109            {
110                DeviceEvent *e = &event->device_event;
111
112                if (e->detail.key > 0xFF)
113                    return BadMatch;
114
115                memset(core, 0, sizeof(xEvent));
116                core->u.u.type = e->type - ET_KeyPress + KeyPress;
117                core->u.u.detail = e->detail.key & 0xFF;
118                core->u.keyButtonPointer.time = e->time;
119                core->u.keyButtonPointer.rootX = e->root_x;
120                core->u.keyButtonPointer.rootY = e->root_y;
121                core->u.keyButtonPointer.state = e->corestate;
122                core->u.keyButtonPointer.root = e->root;
123                EventSetKeyRepeatFlag(core, (e->type == ET_KeyPress && e->key_repeat));
124            }
125            break;
126        case ET_ProximityIn:
127        case ET_ProximityOut:
128        case ET_RawKeyPress:
129        case ET_RawKeyRelease:
130        case ET_RawButtonPress:
131        case ET_RawButtonRelease:
132        case ET_RawMotion:
133            return BadMatch;
134        default:
135            /* XXX: */
136            ErrorF("[dix] EventToCore: Not implemented yet \n");
137            return BadImplementation;
138    }
139    return Success;
140}
141
142/**
143 * Convert the given event to the respective XI 1.x event and store it in
144 * xi. xi is allocated on demand and must be freed by the caller.
145 * count returns the number of events in xi. If count is 1, and the type of
146 * xi is GenericEvent, then xi may be larger than 32 bytes.
147 *
148 * Return values:
149 * Success ... core contains the matching core event.
150 * BadValue .. One or more values in the internal event are invalid.
151 * BadMatch .. The event has no XI equivalent.
152 *
153 * @param[in] ev The event to convert into an XI 1 event.
154 * @param[out] xi Future memory location for the XI event.
155 * @param[out] count Number of elements in xi.
156 *
157 * @return Success or the error code.
158 */
159int
160EventToXI(InternalEvent *ev, xEvent **xi, int *count)
161{
162    switch (ev->any.type)
163    {
164        case ET_Motion:
165        case ET_ButtonPress:
166        case ET_ButtonRelease:
167        case ET_KeyPress:
168        case ET_KeyRelease:
169        case ET_ProximityIn:
170        case ET_ProximityOut:
171            return eventToKeyButtonPointer(&ev->device_event, xi, count);
172        case ET_DeviceChanged:
173        case ET_RawKeyPress:
174        case ET_RawKeyRelease:
175        case ET_RawButtonPress:
176        case ET_RawButtonRelease:
177        case ET_RawMotion:
178            *count = 0;
179            *xi = NULL;
180            return BadMatch;
181        default:
182            break;
183    }
184
185    ErrorF("[dix] EventToXI: Not implemented for %d \n", ev->any.type);
186    return BadImplementation;
187}
188
189/**
190 * Convert the given event to the respective XI 2.x event and store it in xi.
191 * xi is allocated on demand and must be freed by the caller.
192 *
193 * Return values:
194 * Success ... core contains the matching core event.
195 * BadValue .. One or more values in the internal event are invalid.
196 * BadMatch .. The event has no XI2 equivalent.
197 *
198 * @param[in] ev The event to convert into an XI2 event
199 * @param[out] xi Future memory location for the XI2 event.
200 *
201 * @return Success or the error code.
202 */
203int
204EventToXI2(InternalEvent *ev, xEvent **xi)
205{
206    switch (ev->any.type)
207    {
208        /* Enter/FocusIn are for grabs. We don't need an actual event, since
209         * the real events delivered are triggered elsewhere */
210        case ET_Enter:
211        case ET_FocusIn:
212            *xi = NULL;
213            return Success;
214        case ET_Motion:
215        case ET_ButtonPress:
216        case ET_ButtonRelease:
217        case ET_KeyPress:
218        case ET_KeyRelease:
219            return eventToDeviceEvent(&ev->device_event, xi);
220        case ET_ProximityIn:
221        case ET_ProximityOut:
222            *xi = NULL;
223            return BadMatch;
224        case ET_DeviceChanged:
225            return eventToDeviceChanged(&ev->changed_event, xi);
226        case ET_RawKeyPress:
227        case ET_RawKeyRelease:
228        case ET_RawButtonPress:
229        case ET_RawButtonRelease:
230        case ET_RawMotion:
231            return eventToRawEvent(&ev->raw_event, xi);
232        default:
233            break;
234    }
235
236    ErrorF("[dix] EventToXI2: Not implemented for %d \n", ev->any.type);
237    return BadImplementation;
238}
239
240static int
241eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count)
242{
243    int num_events;
244    int first; /* dummy */
245    deviceKeyButtonPointer *kbp;
246
247    /* Sorry, XI 1.x protocol restrictions. */
248    if (ev->detail.button > 0xFF || ev->deviceid >= 0x80)
249    {
250        *count = 0;
251        return Success;
252    }
253
254    num_events = (countValuators(ev, &first) + 5)/6; /* valuator ev */
255    num_events++; /* the actual event event */
256
257    *xi = calloc(num_events, sizeof(xEvent));
258    if (!(*xi))
259    {
260        return BadAlloc;
261    }
262
263    kbp           = (deviceKeyButtonPointer*)(*xi);
264    kbp->detail   = ev->detail.button;
265    kbp->time     = ev->time;
266    kbp->root     = ev->root;
267    kbp->root_x   = ev->root_x;
268    kbp->root_y   = ev->root_y;
269    kbp->deviceid = ev->deviceid;
270    kbp->state    = ev->corestate;
271    EventSetKeyRepeatFlag((xEvent*)kbp,
272                          (ev->type == ET_KeyPress && ev->key_repeat));
273
274    if (num_events > 1)
275        kbp->deviceid |= MORE_EVENTS;
276
277    switch(ev->type)
278    {
279        case ET_Motion:        kbp->type = DeviceMotionNotify;  break;
280        case ET_ButtonPress:   kbp->type = DeviceButtonPress;   break;
281        case ET_ButtonRelease: kbp->type = DeviceButtonRelease; break;
282        case ET_KeyPress:      kbp->type = DeviceKeyPress;      break;
283        case ET_KeyRelease:    kbp->type = DeviceKeyRelease;    break;
284        case ET_ProximityIn:   kbp->type = ProximityIn;         break;
285        case ET_ProximityOut:  kbp->type = ProximityOut;        break;
286        default:
287            break;
288    }
289
290    if (num_events > 1)
291    {
292        getValuatorEvents(ev, (deviceValuator*)(kbp + 1));
293    }
294
295    *count = num_events;
296    return Success;
297}
298
299
300/**
301 * Set first to the first valuator in the event ev and return the number of
302 * valuators from first to the last set valuator.
303 */
304static int
305countValuators(DeviceEvent *ev, int *first)
306{
307    int first_valuator = -1, last_valuator = -1, num_valuators = 0;
308    int i;
309
310    for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
311    {
312        if (BitIsOn(ev->valuators.mask, i))
313        {
314            if (first_valuator == -1)
315                first_valuator = i;
316            last_valuator = i;
317        }
318    }
319
320    if (first_valuator != -1)
321    {
322        num_valuators = last_valuator - first_valuator + 1;
323        *first = first_valuator;
324    }
325
326    return num_valuators;
327}
328
329static int
330getValuatorEvents(DeviceEvent *ev, deviceValuator *xv)
331{
332    int i;
333    int state = 0;
334    int first_valuator, num_valuators;
335
336
337    num_valuators = countValuators(ev, &first_valuator);
338    if (num_valuators > 0)
339    {
340        DeviceIntPtr dev = NULL;
341        dixLookupDevice(&dev, ev->deviceid, serverClient, DixUseAccess);
342        /* State needs to be assembled BEFORE the device is updated. */
343        state = (dev && dev->key) ? XkbStateFieldFromRec(&dev->key->xkbInfo->state) : 0;
344        state |= (dev && dev->button) ? (dev->button->state) : 0;
345    }
346
347    /* FIXME: non-continuous valuator data in internal events*/
348    for (i = 0; i < num_valuators; i += 6, xv++) {
349        xv->type = DeviceValuator;
350        xv->first_valuator = first_valuator + i;
351        xv->num_valuators = ((num_valuators - i) > 6) ? 6 : (num_valuators - i);
352        xv->deviceid = ev->deviceid;
353        xv->device_state = state;
354        switch (xv->num_valuators) {
355        case 6:
356            xv->valuator5 = ev->valuators.data[xv->first_valuator + 5];
357        case 5:
358            xv->valuator4 = ev->valuators.data[xv->first_valuator + 4];
359        case 4:
360            xv->valuator3 = ev->valuators.data[xv->first_valuator + 3];
361        case 3:
362            xv->valuator2 = ev->valuators.data[xv->first_valuator + 2];
363        case 2:
364            xv->valuator1 = ev->valuators.data[xv->first_valuator + 1];
365        case 1:
366            xv->valuator0 = ev->valuators.data[xv->first_valuator + 0];
367        }
368
369        if (i + 6 < num_valuators)
370            xv->deviceid |= MORE_EVENTS;
371    }
372
373    return (num_valuators + 5) / 6;
374}
375
376
377static int
378appendKeyInfo(DeviceChangedEvent *dce, xXIKeyInfo* info)
379{
380    uint32_t *kc;
381    int i;
382
383    info->type = XIKeyClass;
384    info->num_keycodes = dce->keys.max_keycode - dce->keys.min_keycode + 1;
385    info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes;
386    info->sourceid = dce->sourceid;
387
388    kc = (uint32_t*)&info[1];
389    for (i = 0; i < info->num_keycodes; i++)
390        *kc++ = i + dce->keys.min_keycode;
391
392    return info->length * 4;
393}
394
395static int
396appendButtonInfo(DeviceChangedEvent *dce, xXIButtonInfo *info)
397{
398    unsigned char *bits;
399    int mask_len;
400
401    mask_len = bytes_to_int32(bits_to_bytes(dce->buttons.num_buttons));
402
403    info->type = XIButtonClass;
404    info->num_buttons = dce->buttons.num_buttons;
405    info->length = bytes_to_int32(sizeof(xXIButtonInfo)) +
406                   info->num_buttons + mask_len;
407    info->sourceid = dce->sourceid;
408
409    bits = (unsigned char*)&info[1];
410    memset(bits, 0, mask_len * 4);
411    /* FIXME: is_down? */
412
413    bits += mask_len * 4;
414    memcpy(bits, dce->buttons.names, dce->buttons.num_buttons * sizeof(Atom));
415
416    return info->length * 4;
417}
418
419static int
420appendValuatorInfo(DeviceChangedEvent *dce, xXIValuatorInfo *info, int axisnumber)
421{
422    info->type = XIValuatorClass;
423    info->length = sizeof(xXIValuatorInfo)/4;
424    info->label = dce->valuators[axisnumber].name;
425    info->min.integral = dce->valuators[axisnumber].min;
426    info->min.frac = 0;
427    info->max.integral = dce->valuators[axisnumber].max;
428    info->max.frac = 0;
429    /* FIXME: value */
430    info->value.integral = 0;
431    info->value.frac = 0;
432    info->resolution = dce->valuators[axisnumber].resolution;
433    info->number = axisnumber;
434    info->mode = dce->valuators[axisnumber].mode; /* Server doesn't have per-axis mode yet */
435    info->sourceid = dce->sourceid;
436
437    return info->length * 4;
438}
439
440static int
441eventToDeviceChanged(DeviceChangedEvent *dce, xEvent **xi)
442{
443    xXIDeviceChangedEvent *dcce;
444    int len = sizeof(xXIDeviceChangedEvent);
445    int nkeys;
446    char *ptr;
447
448    if (dce->buttons.num_buttons)
449    {
450        len += sizeof(xXIButtonInfo);
451        len += dce->buttons.num_buttons * sizeof(Atom); /* button names */
452        len += pad_to_int32(bits_to_bytes(dce->buttons.num_buttons));
453    }
454    if (dce->num_valuators)
455        len += sizeof(xXIValuatorInfo) * dce->num_valuators;
456
457    nkeys = (dce->keys.max_keycode > 0) ?
458                dce->keys.max_keycode - dce->keys.min_keycode + 1 : 0;
459    if (nkeys > 0)
460    {
461        len += sizeof(xXIKeyInfo);
462        len += sizeof(CARD32) * nkeys; /* keycodes */
463    }
464
465    dcce = calloc(1, len);
466    if (!dcce)
467    {
468        ErrorF("[Xi] BadAlloc in SendDeviceChangedEvent.\n");
469        return BadAlloc;
470    }
471
472    dcce->type         = GenericEvent;
473    dcce->extension    = IReqCode;
474    dcce->evtype       = XI_DeviceChanged;
475    dcce->time         = dce->time;
476    dcce->deviceid     = dce->deviceid;
477    dcce->sourceid     = dce->sourceid;
478    dcce->reason       = (dce->flags & DEVCHANGE_DEVICE_CHANGE) ? XIDeviceChange : XISlaveSwitch;
479    dcce->num_classes  = 0;
480    dcce->length = bytes_to_int32(len - sizeof(xEvent));
481
482    ptr = (char*)&dcce[1];
483    if (dce->buttons.num_buttons)
484    {
485        dcce->num_classes++;
486        ptr += appendButtonInfo(dce, (xXIButtonInfo*)ptr);
487    }
488
489    if (nkeys)
490    {
491        dcce->num_classes++;
492        ptr += appendKeyInfo(dce, (xXIKeyInfo*)ptr);
493    }
494
495    if (dce->num_valuators)
496    {
497        int i;
498
499        dcce->num_classes += dce->num_valuators;
500        for (i = 0; i < dce->num_valuators; i++)
501            ptr += appendValuatorInfo(dce, (xXIValuatorInfo*)ptr, i);
502    }
503
504    *xi = (xEvent*)dcce;
505
506    return Success;
507}
508
509static int count_bits(unsigned char* ptr, int len)
510{
511    int bits = 0;
512    unsigned int i;
513    unsigned char x;
514
515    for (i = 0; i < len; i++)
516    {
517        x = ptr[i];
518        while(x > 0)
519        {
520            bits += (x & 0x1);
521            x >>= 1;
522        }
523    }
524    return bits;
525}
526
527static int
528eventToDeviceEvent(DeviceEvent *ev, xEvent **xi)
529{
530    int len = sizeof(xXIDeviceEvent);
531    xXIDeviceEvent *xde;
532    int i, btlen, vallen;
533    char *ptr;
534    FP3232 *axisval;
535
536    /* FIXME: this should just send the buttons we have, not MAX_BUTTONs. Same
537     * with MAX_VALUATORS below */
538    /* btlen is in 4 byte units */
539    btlen = bytes_to_int32(bits_to_bytes(MAX_BUTTONS));
540    len += btlen * 4; /* buttonmask len */
541
542
543    vallen = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask)/sizeof(ev->valuators.mask[0]));
544    len += vallen * 2 * sizeof(uint32_t); /* axisvalues */
545    vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS));
546    len += vallen * 4; /* valuators mask */
547
548    *xi = calloc(1, len);
549    xde = (xXIDeviceEvent*)*xi;
550    xde->type           = GenericEvent;
551    xde->extension      = IReqCode;
552    xde->evtype         = GetXI2Type((InternalEvent*)ev);
553    xde->time           = ev->time;
554    xde->length         = bytes_to_int32(len - sizeof(xEvent));
555    xde->detail         = ev->detail.button;
556    xde->root           = ev->root;
557    xde->buttons_len    = btlen;
558    xde->valuators_len  = vallen;
559    xde->deviceid       = ev->deviceid;
560    xde->sourceid       = ev->sourceid;
561    xde->root_x         = FP1616(ev->root_x, ev->root_x_frac);
562    xde->root_y         = FP1616(ev->root_y, ev->root_y_frac);
563
564    if (ev->key_repeat)
565        xde->flags      |= XIKeyRepeat;
566
567    xde->mods.base_mods         = ev->mods.base;
568    xde->mods.latched_mods      = ev->mods.latched;
569    xde->mods.locked_mods       = ev->mods.locked;
570    xde->mods.effective_mods    = ev->mods.effective;
571
572    xde->group.base_group       = ev->group.base;
573    xde->group.latched_group    = ev->group.latched;
574    xde->group.locked_group     = ev->group.locked;
575    xde->group.effective_group  = ev->group.effective;
576
577    ptr = (char*)&xde[1];
578    for (i = 0; i < sizeof(ev->buttons) * 8; i++)
579    {
580        if (BitIsOn(ev->buttons, i))
581            SetBit(ptr, i);
582    }
583
584    ptr += xde->buttons_len * 4;
585    axisval = (FP3232*)(ptr + xde->valuators_len * 4);
586    for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
587    {
588        if (BitIsOn(ev->valuators.mask, i))
589        {
590            SetBit(ptr, i);
591            axisval->integral = ev->valuators.data[i];
592            axisval->frac = ev->valuators.data_frac[i];
593            axisval++;
594        }
595    }
596
597    return Success;
598}
599
600static int
601eventToRawEvent(RawDeviceEvent *ev, xEvent **xi)
602{
603    xXIRawEvent* raw;
604    int vallen, nvals;
605    int i, len = sizeof(xXIRawEvent);
606    char *ptr;
607    FP3232 *axisval;
608
609    nvals = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask));
610    len += nvals * sizeof(FP3232) * 2; /* 8 byte per valuator, once
611                                    raw, once processed */
612    vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS));
613    len += vallen * 4; /* valuators mask */
614
615    *xi = calloc(1, len);
616    raw = (xXIRawEvent*)*xi;
617    raw->type           = GenericEvent;
618    raw->extension      = IReqCode;
619    raw->evtype         = GetXI2Type((InternalEvent*)ev);
620    raw->time           = ev->time;
621    raw->length         = bytes_to_int32(len - sizeof(xEvent));
622    raw->detail         = ev->detail.button;
623    raw->deviceid       = ev->deviceid;
624    raw->valuators_len  = vallen;
625
626    ptr = (char*)&raw[1];
627    axisval = (FP3232*)(ptr + raw->valuators_len * 4);
628    for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
629    {
630        if (BitIsOn(ev->valuators.mask, i))
631        {
632            SetBit(ptr, i);
633            axisval->integral = ev->valuators.data[i];
634            axisval->frac = ev->valuators.data_frac[i];
635            (axisval + nvals)->integral = ev->valuators.data_raw[i];
636            (axisval + nvals)->frac = ev->valuators.data_raw_frac[i];
637            axisval++;
638        }
639    }
640
641    return Success;
642}
643
644/**
645 * Return the corresponding core type for the given event or 0 if no core
646 * equivalent exists.
647 */
648int
649GetCoreType(InternalEvent *event)
650{
651    int coretype = 0;
652    switch(event->any.type)
653    {
654        case ET_Motion:         coretype = MotionNotify;  break;
655        case ET_ButtonPress:    coretype = ButtonPress;   break;
656        case ET_ButtonRelease:  coretype = ButtonRelease; break;
657        case ET_KeyPress:       coretype = KeyPress;      break;
658        case ET_KeyRelease:     coretype = KeyRelease;    break;
659        default:
660            break;
661    }
662    return coretype;
663}
664
665/**
666 * Return the corresponding XI 1.x type for the given event or 0 if no
667 * equivalent exists.
668 */
669int
670GetXIType(InternalEvent *event)
671{
672    int xitype = 0;
673    switch(event->any.type)
674    {
675        case ET_Motion:         xitype = DeviceMotionNotify;  break;
676        case ET_ButtonPress:    xitype = DeviceButtonPress;   break;
677        case ET_ButtonRelease:  xitype = DeviceButtonRelease; break;
678        case ET_KeyPress:       xitype = DeviceKeyPress;      break;
679        case ET_KeyRelease:     xitype = DeviceKeyRelease;    break;
680        case ET_ProximityIn:    xitype = ProximityIn;         break;
681        case ET_ProximityOut:   xitype = ProximityOut;        break;
682        default:
683            break;
684    }
685    return xitype;
686}
687
688/**
689 * Return the corresponding XI 2.x type for the given event or 0 if no
690 * equivalent exists.
691 */
692int
693GetXI2Type(InternalEvent *event)
694{
695    int xi2type = 0;
696
697    switch(event->any.type)
698    {
699        case ET_Motion:         xi2type = XI_Motion;           break;
700        case ET_ButtonPress:    xi2type = XI_ButtonPress;      break;
701        case ET_ButtonRelease:  xi2type = XI_ButtonRelease;    break;
702        case ET_KeyPress:       xi2type = XI_KeyPress;         break;
703        case ET_KeyRelease:     xi2type = XI_KeyRelease;       break;
704        case ET_Enter:          xi2type = XI_Enter;            break;
705        case ET_Leave:          xi2type = XI_Leave;            break;
706        case ET_Hierarchy:      xi2type = XI_HierarchyChanged; break;
707        case ET_DeviceChanged:  xi2type = XI_DeviceChanged;    break;
708        case ET_RawKeyPress:    xi2type = XI_RawKeyPress;      break;
709        case ET_RawKeyRelease:  xi2type = XI_RawKeyRelease;    break;
710        case ET_RawButtonPress: xi2type = XI_RawButtonPress;   break;
711        case ET_RawButtonRelease: xi2type = XI_RawButtonRelease; break;
712        case ET_RawMotion:      xi2type = XI_RawMotion;        break;
713        case ET_FocusIn:        xi2type = XI_FocusIn;          break;
714        case ET_FocusOut:       xi2type = XI_FocusOut;         break;
715        default:
716            break;
717    }
718    return xi2type;
719}
720