xwayland/dix/eventconvert.c

1141 lines
32 KiB
C

/*
* Copyright © 2009 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/**
* @file eventconvert.c
* This file contains event conversion routines from InternalEvent to the
* matching protocol events.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <stdint.h>
#include <X11/X.h>
#include <X11/extensions/XIproto.h>
#include <X11/extensions/XI2proto.h>
#include <X11/extensions/XI.h>
#include <X11/extensions/XI2.h>
#include "dix.h"
#include "inputstr.h"
#include "misc.h"
#include "eventstr.h"
#include "exevents.h"
#include "exglobals.h"
#include "eventconvert.h"
#include "inpututils.h"
#include "xiquerydevice.h"
#include "xkbsrv.h"
#include "inpututils.h"
static int countValuators(DeviceEvent *ev, int *first);
static int getValuatorEvents(DeviceEvent *ev, deviceValuator * xv);
static int eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count);
static int eventToDeviceChanged(DeviceChangedEvent *ev, xEvent **dcce);
static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi);
static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi);
static int eventToBarrierEvent(BarrierEvent *ev, xEvent **xi);
static int eventToTouchOwnershipEvent(TouchOwnershipEvent *ev, xEvent **xi);
static int eventToGestureSwipeEvent(GestureEvent *ev, xEvent **xi);
static int eventToGesturePinchEvent(GestureEvent *ev, xEvent **xi);
/* Do not use, read comments below */
BOOL EventIsKeyRepeat(xEvent *event);
/**
* Hack to allow detectable autorepeat for core and XI1 events.
* The sequence number is unused until we send to the client and can be
* misused to store data. More or less, anyway.
*
* Do not use this. It may change any time without warning, eat your babies
* and piss on your cat.
*/
static void
EventSetKeyRepeatFlag(xEvent *event, BOOL on)
{
event->u.u.sequenceNumber = on;
}
/**
* Check if the event was marked as a repeat event before.
* NOTE: This is a nasty hack and should NOT be used by anyone else but
* TryClientEvents.
*/
BOOL
EventIsKeyRepeat(xEvent *event)
{
return ! !event->u.u.sequenceNumber;
}
/**
* Convert the given event to the respective core event.
*
* Return values:
* Success ... core contains the matching core event.
* BadValue .. One or more values in the internal event are invalid.
* BadMatch .. The event has no core equivalent.
*
* @param[in] event The event to convert into a core event.
* @param[in] core The memory location to store the core event at.
* @return Success or the matching error code.
*/
int
EventToCore(InternalEvent *event, xEvent **core_out, int *count_out)
{
xEvent *core = NULL;
int count = 0;
int ret = BadImplementation;
switch (event->any.type) {
case ET_Motion:
{
DeviceEvent *e = &event->device_event;
/* Don't create core motion event if neither x nor y are
* present */
if (!BitIsOn(e->valuators.mask, 0) && !BitIsOn(e->valuators.mask, 1)) {
ret = BadMatch;
goto out;
}
}
/* fallthrough */
case ET_ButtonPress:
case ET_ButtonRelease:
case ET_KeyPress:
case ET_KeyRelease:
{
DeviceEvent *e = &event->device_event;
if (e->detail.key > 0xFF) {
ret = BadMatch;
goto out;
}
core = calloc(1, sizeof(*core));
if (!core)
return BadAlloc;
count = 1;
core->u.u.type = e->type - ET_KeyPress + KeyPress;
core->u.u.detail = e->detail.key & 0xFF;
core->u.keyButtonPointer.time = e->time;
core->u.keyButtonPointer.rootX = e->root_x;
core->u.keyButtonPointer.rootY = e->root_y;
core->u.keyButtonPointer.state = e->corestate;
core->u.keyButtonPointer.root = e->root;
EventSetKeyRepeatFlag(core, (e->type == ET_KeyPress && e->key_repeat));
ret = Success;
}
break;
case ET_ProximityIn:
case ET_ProximityOut:
case ET_RawKeyPress:
case ET_RawKeyRelease:
case ET_RawButtonPress:
case ET_RawButtonRelease:
case ET_RawMotion:
case ET_RawTouchBegin:
case ET_RawTouchUpdate:
case ET_RawTouchEnd:
case ET_TouchBegin:
case ET_TouchUpdate:
case ET_TouchEnd:
case ET_TouchOwnership:
case ET_BarrierHit:
case ET_BarrierLeave:
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
ret = BadMatch;
break;
default:
/* XXX: */
ErrorF("[dix] EventToCore: Not implemented yet \n");
ret = BadImplementation;
}
out:
*core_out = core;
*count_out = count;
return ret;
}
/**
* Convert the given event to the respective XI 1.x event and store it in
* xi. xi is allocated on demand and must be freed by the caller.
* count returns the number of events in xi. If count is 1, and the type of
* xi is GenericEvent, then xi may be larger than 32 bytes.
*
* Return values:
* Success ... core contains the matching core event.
* BadValue .. One or more values in the internal event are invalid.
* BadMatch .. The event has no XI equivalent.
*
* @param[in] ev The event to convert into an XI 1 event.
* @param[out] xi Future memory location for the XI event.
* @param[out] count Number of elements in xi.
*
* @return Success or the error code.
*/
int
EventToXI(InternalEvent *ev, xEvent **xi, int *count)
{
switch (ev->any.type) {
case ET_Motion:
case ET_ButtonPress:
case ET_ButtonRelease:
case ET_KeyPress:
case ET_KeyRelease:
case ET_ProximityIn:
case ET_ProximityOut:
return eventToKeyButtonPointer(&ev->device_event, xi, count);
case ET_DeviceChanged:
case ET_RawKeyPress:
case ET_RawKeyRelease:
case ET_RawButtonPress:
case ET_RawButtonRelease:
case ET_RawMotion:
case ET_RawTouchBegin:
case ET_RawTouchUpdate:
case ET_RawTouchEnd:
case ET_TouchBegin:
case ET_TouchUpdate:
case ET_TouchEnd:
case ET_TouchOwnership:
case ET_BarrierHit:
case ET_BarrierLeave:
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
*count = 0;
*xi = NULL;
return BadMatch;
default:
break;
}
ErrorF("[dix] EventToXI: Not implemented for %d \n", ev->any.type);
return BadImplementation;
}
/**
* Convert the given event to the respective XI 2.x event and store it in xi.
* xi is allocated on demand and must be freed by the caller.
*
* Return values:
* Success ... core contains the matching core event.
* BadValue .. One or more values in the internal event are invalid.
* BadMatch .. The event has no XI2 equivalent.
*
* @param[in] ev The event to convert into an XI2 event
* @param[out] xi Future memory location for the XI2 event.
*
* @return Success or the error code.
*/
int
EventToXI2(InternalEvent *ev, xEvent **xi)
{
switch (ev->any.type) {
/* Enter/FocusIn are for grabs. We don't need an actual event, since
* the real events delivered are triggered elsewhere */
case ET_Enter:
case ET_FocusIn:
*xi = NULL;
return Success;
case ET_Motion:
case ET_ButtonPress:
case ET_ButtonRelease:
case ET_KeyPress:
case ET_KeyRelease:
case ET_TouchBegin:
case ET_TouchUpdate:
case ET_TouchEnd:
return eventToDeviceEvent(&ev->device_event, xi);
case ET_TouchOwnership:
return eventToTouchOwnershipEvent(&ev->touch_ownership_event, xi);
case ET_ProximityIn:
case ET_ProximityOut:
*xi = NULL;
return BadMatch;
case ET_DeviceChanged:
return eventToDeviceChanged(&ev->changed_event, xi);
case ET_RawKeyPress:
case ET_RawKeyRelease:
case ET_RawButtonPress:
case ET_RawButtonRelease:
case ET_RawMotion:
case ET_RawTouchBegin:
case ET_RawTouchUpdate:
case ET_RawTouchEnd:
return eventToRawEvent(&ev->raw_event, xi);
case ET_BarrierHit:
case ET_BarrierLeave:
return eventToBarrierEvent(&ev->barrier_event, xi);
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
return eventToGesturePinchEvent(&ev->gesture_event, xi);
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return eventToGestureSwipeEvent(&ev->gesture_event, xi);
default:
break;
}
ErrorF("[dix] EventToXI2: Not implemented for %d \n", ev->any.type);
return BadImplementation;
}
static int
eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count)
{
int num_events;
int first; /* dummy */
deviceKeyButtonPointer *kbp;
/* Sorry, XI 1.x protocol restrictions. */
if (ev->detail.button > 0xFF || ev->deviceid >= 0x80) {
*count = 0;
return Success;
}
num_events = (countValuators(ev, &first) + 5) / 6; /* valuator ev */
if (num_events <= 0) {
switch (ev->type) {
case ET_KeyPress:
case ET_KeyRelease:
case ET_ButtonPress:
case ET_ButtonRelease:
/* no axes is ok */
break;
case ET_Motion:
case ET_ProximityIn:
case ET_ProximityOut:
*count = 0;
return BadMatch;
default:
*count = 0;
return BadImplementation;
}
}
num_events++; /* the actual event event */
*xi = calloc(num_events, sizeof(xEvent));
if (!(*xi)) {
return BadAlloc;
}
kbp = (deviceKeyButtonPointer *) (*xi);
kbp->detail = ev->detail.button;
kbp->time = ev->time;
kbp->root = ev->root;
kbp->root_x = ev->root_x;
kbp->root_y = ev->root_y;
kbp->deviceid = ev->deviceid;
kbp->state = ev->corestate;
EventSetKeyRepeatFlag((xEvent *) kbp,
(ev->type == ET_KeyPress && ev->key_repeat));
if (num_events > 1)
kbp->deviceid |= MORE_EVENTS;
switch (ev->type) {
case ET_Motion:
kbp->type = DeviceMotionNotify;
break;
case ET_ButtonPress:
kbp->type = DeviceButtonPress;
break;
case ET_ButtonRelease:
kbp->type = DeviceButtonRelease;
break;
case ET_KeyPress:
kbp->type = DeviceKeyPress;
break;
case ET_KeyRelease:
kbp->type = DeviceKeyRelease;
break;
case ET_ProximityIn:
kbp->type = ProximityIn;
break;
case ET_ProximityOut:
kbp->type = ProximityOut;
break;
default:
break;
}
if (num_events > 1) {
getValuatorEvents(ev, (deviceValuator *) (kbp + 1));
}
*count = num_events;
return Success;
}
/**
* Set first to the first valuator in the event ev and return the number of
* valuators from first to the last set valuator.
*/
static int
countValuators(DeviceEvent *ev, int *first)
{
int first_valuator = -1, last_valuator = -1, num_valuators = 0;
int i;
for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) {
if (BitIsOn(ev->valuators.mask, i)) {
if (first_valuator == -1)
first_valuator = i;
last_valuator = i;
}
}
if (first_valuator != -1) {
num_valuators = last_valuator - first_valuator + 1;
*first = first_valuator;
}
return num_valuators;
}
static int
getValuatorEvents(DeviceEvent *ev, deviceValuator * xv)
{
int i;
int state = 0;
int first_valuator, num_valuators;
num_valuators = countValuators(ev, &first_valuator);
if (num_valuators > 0) {
DeviceIntPtr dev = NULL;
dixLookupDevice(&dev, ev->deviceid, serverClient, DixUseAccess);
/* State needs to be assembled BEFORE the device is updated. */
state = (dev &&
dev->key) ? XkbStateFieldFromRec(&dev->key->xkbInfo->
state) : 0;
state |= (dev && dev->button) ? (dev->button->state) : 0;
}
for (i = 0; i < num_valuators; i += 6, xv++) {
INT32 *valuators = &xv->valuator0; // Treat all 6 vals as an array
int j;
xv->type = DeviceValuator;
xv->first_valuator = first_valuator + i;
xv->num_valuators = ((num_valuators - i) > 6) ? 6 : (num_valuators - i);
xv->deviceid = ev->deviceid;
xv->device_state = state;
/* Unset valuators in masked valuator events have the proper data values
* in the case of an absolute axis in between two set valuators. */
for (j = 0; j < xv->num_valuators; j++)
valuators[j] = ev->valuators.data[xv->first_valuator + j];
if (i + 6 < num_valuators)
xv->deviceid |= MORE_EVENTS;
}
return (num_valuators + 5) / 6;
}
static int
appendKeyInfo(DeviceChangedEvent *dce, xXIKeyInfo * info)
{
uint32_t *kc;
int i;
info->type = XIKeyClass;
info->num_keycodes = dce->keys.max_keycode - dce->keys.min_keycode + 1;
info->length = sizeof(xXIKeyInfo) / 4 + info->num_keycodes;
info->sourceid = dce->sourceid;
kc = (uint32_t *) &info[1];
for (i = 0; i < info->num_keycodes; i++)
*kc++ = i + dce->keys.min_keycode;
return info->length * 4;
}
static int
appendButtonInfo(DeviceChangedEvent *dce, xXIButtonInfo * info)
{
unsigned char *bits;
int mask_len;
mask_len = bytes_to_int32(bits_to_bytes(dce->buttons.num_buttons));
info->type = XIButtonClass;
info->num_buttons = dce->buttons.num_buttons;
info->length = bytes_to_int32(sizeof(xXIButtonInfo)) +
info->num_buttons + mask_len;
info->sourceid = dce->sourceid;
bits = (unsigned char *) &info[1];
memset(bits, 0, mask_len * 4);
/* FIXME: is_down? */
bits += mask_len * 4;
memcpy(bits, dce->buttons.names, dce->buttons.num_buttons * sizeof(Atom));
return info->length * 4;
}
static int
appendValuatorInfo(DeviceChangedEvent *dce, xXIValuatorInfo * info,
int axisnumber)
{
info->type = XIValuatorClass;
info->length = sizeof(xXIValuatorInfo) / 4;
info->label = dce->valuators[axisnumber].name;
info->min.integral = dce->valuators[axisnumber].min;
info->min.frac = 0;
info->max.integral = dce->valuators[axisnumber].max;
info->max.frac = 0;
info->value = double_to_fp3232(dce->valuators[axisnumber].value);
info->resolution = dce->valuators[axisnumber].resolution;
info->number = axisnumber;
info->mode = dce->valuators[axisnumber].mode;
info->sourceid = dce->sourceid;
return info->length * 4;
}
static int
appendScrollInfo(DeviceChangedEvent *dce, xXIScrollInfo * info, int axisnumber)
{
if (dce->valuators[axisnumber].scroll.type == SCROLL_TYPE_NONE)
return 0;
info->type = XIScrollClass;
info->length = sizeof(xXIScrollInfo) / 4;
info->number = axisnumber;
switch (dce->valuators[axisnumber].scroll.type) {
case SCROLL_TYPE_VERTICAL:
info->scroll_type = XIScrollTypeVertical;
break;
case SCROLL_TYPE_HORIZONTAL:
info->scroll_type = XIScrollTypeHorizontal;
break;
default:
ErrorF("[Xi] Unknown scroll type %d. This is a bug.\n",
dce->valuators[axisnumber].scroll.type);
break;
}
info->increment =
double_to_fp3232(dce->valuators[axisnumber].scroll.increment);
info->sourceid = dce->sourceid;
info->flags = 0;
if (dce->valuators[axisnumber].scroll.flags & SCROLL_FLAG_DONT_EMULATE)
info->flags |= XIScrollFlagNoEmulation;
if (dce->valuators[axisnumber].scroll.flags & SCROLL_FLAG_PREFERRED)
info->flags |= XIScrollFlagPreferred;
return info->length * 4;
}
static int
eventToDeviceChanged(DeviceChangedEvent *dce, xEvent **xi)
{
xXIDeviceChangedEvent *dcce;
int len = sizeof(xXIDeviceChangedEvent);
int nkeys;
char *ptr;
if (dce->buttons.num_buttons) {
len += sizeof(xXIButtonInfo);
len += dce->buttons.num_buttons * sizeof(Atom); /* button names */
len += pad_to_int32(bits_to_bytes(dce->buttons.num_buttons));
}
if (dce->num_valuators) {
int i;
len += sizeof(xXIValuatorInfo) * dce->num_valuators;
for (i = 0; i < dce->num_valuators; i++)
if (dce->valuators[i].scroll.type != SCROLL_TYPE_NONE)
len += sizeof(xXIScrollInfo);
}
nkeys = (dce->keys.max_keycode > 0) ?
dce->keys.max_keycode - dce->keys.min_keycode + 1 : 0;
if (nkeys > 0) {
len += sizeof(xXIKeyInfo);
len += sizeof(CARD32) * nkeys; /* keycodes */
}
dcce = calloc(1, len);
if (!dcce) {
ErrorF("[Xi] BadAlloc in SendDeviceChangedEvent.\n");
return BadAlloc;
}
dcce->type = GenericEvent;
dcce->extension = IReqCode;
dcce->evtype = XI_DeviceChanged;
dcce->time = dce->time;
dcce->deviceid = dce->deviceid;
dcce->sourceid = dce->sourceid;
dcce->reason =
(dce->flags & DEVCHANGE_DEVICE_CHANGE) ? XIDeviceChange : XISlaveSwitch;
dcce->num_classes = 0;
dcce->length = bytes_to_int32(len - sizeof(xEvent));
ptr = (char *) &dcce[1];
if (dce->buttons.num_buttons) {
dcce->num_classes++;
ptr += appendButtonInfo(dce, (xXIButtonInfo *) ptr);
}
if (nkeys) {
dcce->num_classes++;
ptr += appendKeyInfo(dce, (xXIKeyInfo *) ptr);
}
if (dce->num_valuators) {
int i;
dcce->num_classes += dce->num_valuators;
for (i = 0; i < dce->num_valuators; i++)
ptr += appendValuatorInfo(dce, (xXIValuatorInfo *) ptr, i);
for (i = 0; i < dce->num_valuators; i++) {
if (dce->valuators[i].scroll.type != SCROLL_TYPE_NONE) {
dcce->num_classes++;
ptr += appendScrollInfo(dce, (xXIScrollInfo *) ptr, i);
}
}
}
*xi = (xEvent *) dcce;
return Success;
}
static int
count_bits(unsigned char *ptr, int len)
{
int bits = 0;
unsigned int i;
unsigned char x;
for (i = 0; i < len; i++) {
x = ptr[i];
while (x > 0) {
bits += (x & 0x1);
x >>= 1;
}
}
return bits;
}
static int
eventToDeviceEvent(DeviceEvent *ev, xEvent **xi)
{
int len = sizeof(xXIDeviceEvent);
xXIDeviceEvent *xde;
int i, btlen, vallen;
char *ptr;
FP3232 *axisval;
/* FIXME: this should just send the buttons we have, not MAX_BUTTONs. Same
* with MAX_VALUATORS below */
/* btlen is in 4 byte units */
btlen = bytes_to_int32(bits_to_bytes(MAX_BUTTONS));
len += btlen * 4; /* buttonmask len */
vallen = count_bits(ev->valuators.mask, ARRAY_SIZE(ev->valuators.mask));
len += vallen * 2 * sizeof(uint32_t); /* axisvalues */
vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS));
len += vallen * 4; /* valuators mask */
*xi = calloc(1, len);
xde = (xXIDeviceEvent *) * xi;
xde->type = GenericEvent;
xde->extension = IReqCode;
xde->evtype = GetXI2Type(ev->type);
xde->time = ev->time;
xde->length = bytes_to_int32(len - sizeof(xEvent));
if (IsTouchEvent((InternalEvent *) ev))
xde->detail = ev->touchid;
else
xde->detail = ev->detail.button;
xde->root = ev->root;
xde->buttons_len = btlen;
xde->valuators_len = vallen;
xde->deviceid = ev->deviceid;
xde->sourceid = ev->sourceid;
xde->root_x = double_to_fp1616(ev->root_x + ev->root_x_frac);
xde->root_y = double_to_fp1616(ev->root_y + ev->root_y_frac);
if (IsTouchEvent((InternalEvent *)ev)) {
if (ev->type == ET_TouchUpdate)
xde->flags |= (ev->flags & TOUCH_PENDING_END) ? XITouchPendingEnd : 0;
if (ev->flags & TOUCH_POINTER_EMULATED)
xde->flags |= XITouchEmulatingPointer;
} else {
xde->flags = ev->flags;
if (ev->key_repeat)
xde->flags |= XIKeyRepeat;
}
xde->mods.base_mods = ev->mods.base;
xde->mods.latched_mods = ev->mods.latched;
xde->mods.locked_mods = ev->mods.locked;
xde->mods.effective_mods = ev->mods.effective;
xde->group.base_group = ev->group.base;
xde->group.latched_group = ev->group.latched;
xde->group.locked_group = ev->group.locked;
xde->group.effective_group = ev->group.effective;
ptr = (char *) &xde[1];
for (i = 0; i < sizeof(ev->buttons) * 8; i++) {
if (BitIsOn(ev->buttons, i))
SetBit(ptr, i);
}
ptr += xde->buttons_len * 4;
axisval = (FP3232 *) (ptr + xde->valuators_len * 4);
for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) {
if (BitIsOn(ev->valuators.mask, i)) {
SetBit(ptr, i);
*axisval = double_to_fp3232(ev->valuators.data[i]);
axisval++;
}
}
return Success;
}
static int
eventToTouchOwnershipEvent(TouchOwnershipEvent *ev, xEvent **xi)
{
int len = sizeof(xXITouchOwnershipEvent);
xXITouchOwnershipEvent *xtoe;
*xi = calloc(1, len);
xtoe = (xXITouchOwnershipEvent *) * xi;
xtoe->type = GenericEvent;
xtoe->extension = IReqCode;
xtoe->length = bytes_to_int32(len - sizeof(xEvent));
xtoe->evtype = GetXI2Type(ev->type);
xtoe->deviceid = ev->deviceid;
xtoe->time = ev->time;
xtoe->sourceid = ev->sourceid;
xtoe->touchid = ev->touchid;
xtoe->flags = 0; /* we don't have wire flags for ownership yet */
return Success;
}
static int
eventToRawEvent(RawDeviceEvent *ev, xEvent **xi)
{
xXIRawEvent *raw;
int vallen, nvals;
int i, len = sizeof(xXIRawEvent);
char *ptr;
FP3232 *axisval, *axisval_raw;
nvals = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask));
len += nvals * sizeof(FP3232) * 2; /* 8 byte per valuator, once
raw, once processed */
vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS));
len += vallen * 4; /* valuators mask */
*xi = calloc(1, len);
raw = (xXIRawEvent *) * xi;
raw->type = GenericEvent;
raw->extension = IReqCode;
raw->evtype = GetXI2Type(ev->type);
raw->time = ev->time;
raw->length = bytes_to_int32(len - sizeof(xEvent));
raw->detail = ev->detail.button;
raw->deviceid = ev->deviceid;
raw->sourceid = ev->sourceid;
raw->valuators_len = vallen;
raw->flags = ev->flags;
ptr = (char *) &raw[1];
axisval = (FP3232 *) (ptr + raw->valuators_len * 4);
axisval_raw = axisval + nvals;
for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) {
if (BitIsOn(ev->valuators.mask, i)) {
SetBit(ptr, i);
*axisval = double_to_fp3232(ev->valuators.data[i]);
*axisval_raw = double_to_fp3232(ev->valuators.data_raw[i]);
axisval++;
axisval_raw++;
}
}
return Success;
}
static int
eventToBarrierEvent(BarrierEvent *ev, xEvent **xi)
{
xXIBarrierEvent *barrier;
int len = sizeof(xXIBarrierEvent);
*xi = calloc(1, len);
barrier = (xXIBarrierEvent*) *xi;
barrier->type = GenericEvent;
barrier->extension = IReqCode;
barrier->evtype = GetXI2Type(ev->type);
barrier->length = bytes_to_int32(len - sizeof(xEvent));
barrier->deviceid = ev->deviceid;
barrier->sourceid = ev->sourceid;
barrier->time = ev->time;
barrier->event = ev->window;
barrier->root = ev->root;
barrier->dx = double_to_fp3232(ev->dx);
barrier->dy = double_to_fp3232(ev->dy);
barrier->dtime = ev->dt;
barrier->flags = ev->flags;
barrier->eventid = ev->event_id;
barrier->barrier = ev->barrierid;
barrier->root_x = double_to_fp1616(ev->root_x);
barrier->root_y = double_to_fp1616(ev->root_y);
return Success;
}
int
eventToGesturePinchEvent(GestureEvent *ev, xEvent **xi)
{
int len = sizeof(xXIGesturePinchEvent);
xXIGesturePinchEvent *xpe;
*xi = calloc(1, len);
xpe = (xXIGesturePinchEvent *) * xi;
xpe->type = GenericEvent;
xpe->extension = IReqCode;
xpe->evtype = GetXI2Type(ev->type);
xpe->time = ev->time;
xpe->length = bytes_to_int32(len - sizeof(xEvent));
xpe->detail = ev->num_touches;
xpe->root = ev->root;
xpe->deviceid = ev->deviceid;
xpe->sourceid = ev->sourceid;
xpe->root_x = double_to_fp1616(ev->root_x);
xpe->root_y = double_to_fp1616(ev->root_y);
xpe->flags |= (ev->flags & GESTURE_CANCELLED) ? XIGesturePinchEventCancelled : 0;
xpe->delta_x = double_to_fp1616(ev->delta_x);
xpe->delta_y = double_to_fp1616(ev->delta_y);
xpe->delta_unaccel_x = double_to_fp1616(ev->delta_unaccel_x);
xpe->delta_unaccel_y = double_to_fp1616(ev->delta_unaccel_y);
xpe->scale = double_to_fp1616(ev->scale);
xpe->delta_angle = double_to_fp1616(ev->delta_angle);
xpe->mods.base_mods = ev->mods.base;
xpe->mods.latched_mods = ev->mods.latched;
xpe->mods.locked_mods = ev->mods.locked;
xpe->mods.effective_mods = ev->mods.effective;
xpe->group.base_group = ev->group.base;
xpe->group.latched_group = ev->group.latched;
xpe->group.locked_group = ev->group.locked;
xpe->group.effective_group = ev->group.effective;
return Success;
}
int
eventToGestureSwipeEvent(GestureEvent *ev, xEvent **xi)
{
int len = sizeof(xXIGestureSwipeEvent);
xXIGestureSwipeEvent *xde;
*xi = calloc(1, len);
xde = (xXIGestureSwipeEvent *) * xi;
xde->type = GenericEvent;
xde->extension = IReqCode;
xde->evtype = GetXI2Type(ev->type);
xde->time = ev->time;
xde->length = bytes_to_int32(len - sizeof(xEvent));
xde->detail = ev->num_touches;
xde->root = ev->root;
xde->deviceid = ev->deviceid;
xde->sourceid = ev->sourceid;
xde->root_x = double_to_fp1616(ev->root_x);
xde->root_y = double_to_fp1616(ev->root_y);
xde->flags |= (ev->flags & GESTURE_CANCELLED) ? XIGestureSwipeEventCancelled : 0;
xde->delta_x = double_to_fp1616(ev->delta_x);
xde->delta_y = double_to_fp1616(ev->delta_y);
xde->delta_unaccel_x = double_to_fp1616(ev->delta_unaccel_x);
xde->delta_unaccel_y = double_to_fp1616(ev->delta_unaccel_y);
xde->mods.base_mods = ev->mods.base;
xde->mods.latched_mods = ev->mods.latched;
xde->mods.locked_mods = ev->mods.locked;
xde->mods.effective_mods = ev->mods.effective;
xde->group.base_group = ev->group.base;
xde->group.latched_group = ev->group.latched;
xde->group.locked_group = ev->group.locked;
xde->group.effective_group = ev->group.effective;
return Success;
}
/**
* Return the corresponding core type for the given event or 0 if no core
* equivalent exists.
*/
int
GetCoreType(enum EventType type)
{
int coretype = 0;
switch (type) {
case ET_Motion:
coretype = MotionNotify;
break;
case ET_ButtonPress:
coretype = ButtonPress;
break;
case ET_ButtonRelease:
coretype = ButtonRelease;
break;
case ET_KeyPress:
coretype = KeyPress;
break;
case ET_KeyRelease:
coretype = KeyRelease;
break;
default:
break;
}
return coretype;
}
/**
* Return the corresponding XI 1.x type for the given event or 0 if no
* equivalent exists.
*/
int
GetXIType(enum EventType type)
{
int xitype = 0;
switch (type) {
case ET_Motion:
xitype = DeviceMotionNotify;
break;
case ET_ButtonPress:
xitype = DeviceButtonPress;
break;
case ET_ButtonRelease:
xitype = DeviceButtonRelease;
break;
case ET_KeyPress:
xitype = DeviceKeyPress;
break;
case ET_KeyRelease:
xitype = DeviceKeyRelease;
break;
case ET_ProximityIn:
xitype = ProximityIn;
break;
case ET_ProximityOut:
xitype = ProximityOut;
break;
default:
break;
}
return xitype;
}
/**
* Return the corresponding XI 2.x type for the given event or 0 if no
* equivalent exists.
*/
int
GetXI2Type(enum EventType type)
{
int xi2type = 0;
switch (type) {
case ET_Motion:
xi2type = XI_Motion;
break;
case ET_ButtonPress:
xi2type = XI_ButtonPress;
break;
case ET_ButtonRelease:
xi2type = XI_ButtonRelease;
break;
case ET_KeyPress:
xi2type = XI_KeyPress;
break;
case ET_KeyRelease:
xi2type = XI_KeyRelease;
break;
case ET_Enter:
xi2type = XI_Enter;
break;
case ET_Leave:
xi2type = XI_Leave;
break;
case ET_Hierarchy:
xi2type = XI_HierarchyChanged;
break;
case ET_DeviceChanged:
xi2type = XI_DeviceChanged;
break;
case ET_RawKeyPress:
xi2type = XI_RawKeyPress;
break;
case ET_RawKeyRelease:
xi2type = XI_RawKeyRelease;
break;
case ET_RawButtonPress:
xi2type = XI_RawButtonPress;
break;
case ET_RawButtonRelease:
xi2type = XI_RawButtonRelease;
break;
case ET_RawMotion:
xi2type = XI_RawMotion;
break;
case ET_RawTouchBegin:
xi2type = XI_RawTouchBegin;
break;
case ET_RawTouchUpdate:
xi2type = XI_RawTouchUpdate;
break;
case ET_RawTouchEnd:
xi2type = XI_RawTouchEnd;
break;
case ET_FocusIn:
xi2type = XI_FocusIn;
break;
case ET_FocusOut:
xi2type = XI_FocusOut;
break;
case ET_TouchBegin:
xi2type = XI_TouchBegin;
break;
case ET_TouchEnd:
xi2type = XI_TouchEnd;
break;
case ET_TouchUpdate:
xi2type = XI_TouchUpdate;
break;
case ET_TouchOwnership:
xi2type = XI_TouchOwnership;
break;
case ET_BarrierHit:
xi2type = XI_BarrierHit;
break;
case ET_BarrierLeave:
xi2type = XI_BarrierLeave;
break;
case ET_GesturePinchBegin:
xi2type = XI_GesturePinchBegin;
break;
case ET_GesturePinchUpdate:
xi2type = XI_GesturePinchUpdate;
break;
case ET_GesturePinchEnd:
xi2type = XI_GesturePinchEnd;
break;
case ET_GestureSwipeBegin:
xi2type = XI_GestureSwipeBegin;
break;
case ET_GestureSwipeUpdate:
xi2type = XI_GestureSwipeUpdate;
break;
case ET_GestureSwipeEnd:
xi2type = XI_GestureSwipeEnd;
break;
default:
break;
}
return xi2type;
}
/**
* Converts a gesture type to corresponding Gesture{Pinch,Swipe}Begin.
* Returns 0 if the input type is not a gesture.
*/
enum EventType
GestureTypeToBegin(enum EventType type)
{
switch (type) {
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
return ET_GesturePinchBegin;
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return ET_GestureSwipeBegin;
default:
return 0;
}
}
/**
* Converts a gesture type to corresponding Gesture{Pinch,Swipe}End.
* Returns 0 if the input type is not a gesture.
*/
enum EventType
GestureTypeToEnd(enum EventType type)
{
switch (type) {
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
return ET_GesturePinchEnd;
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return ET_GestureSwipeEnd;
default:
return 0;
}
}