xserver-multidpi/dix/getevents.c
Keith Packard 1dcda4f3c5 Avoid dereferencing sprite.screen when Xinerama is not running. (#8925)
With Xinerama support built into the X server but not in use,
sprite.screen is NULL and yet the SyntheticMotion
macro would dereference it. Avoid that by just passing sprite.screen
to PostSyntheticMotion which can then dereference it when Xinerama is
enabled.

Also, define PostSyntheticMotion in dixevents.h and include dixevents.h in
getevents.c
2006-11-07 01:29:51 -08:00

784 lines
24 KiB
C

/*
* Copyright © 2006 Nokia Corporation
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and that
* both that this copyright notice and this permission notice appear in
* supporting electronic documentation.
*
* The above copyright notice and this permission notice 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 COPYRIGHT HOLDERS OR AUTHORS 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <X11/X.h>
#include <X11/keysym.h>
#include "misc.h"
#include "resource.h"
#define NEED_EVENTS
#define NEED_REPLIES
#include <X11/Xproto.h>
#include "inputstr.h"
#include "scrnintstr.h"
#include "cursorstr.h"
#include "dixstruct.h"
#include "globals.h"
#include "dixevents.h"
#include "mipointer.h"
#ifdef XKB
#include <X11/extensions/XKBproto.h>
#include <X11/extensions/XKBsrv.h>
extern Bool XkbCopyKeymap(XkbDescPtr src, XkbDescPtr dst, Bool sendNotifies);
#endif
#ifdef XACE
#include "xace.h"
#endif
#ifdef PANORAMIX
#include "panoramiX.h"
#include "panoramiXsrv.h"
#endif
#include <X11/extensions/XI.h>
#include <X11/extensions/XIproto.h>
#include "exglobals.h"
#include "exevents.h"
#include "exglobals.h"
#include "extnsionst.h"
/* Maximum number of valuators, divided by six, rounded up. */
#define MAX_VALUATOR_EVENTS 6
/* Number of motion history events to store. */
#define MOTION_HISTORY_SIZE 256
/**
* Returns the maximum number of events GetKeyboardEvents,
* GetKeyboardValuatorEvents, and GetPointerEvents will ever return.
*
* Should be used in DIX as:
* xEvent *events = xcalloc(sizeof(xEvent), GetMaximumEventsNum());
*/
_X_EXPORT int
GetMaximumEventsNum() {
/* Two base events -- core and device, plus valuator events. Multiply
* by two if we're doing key repeats. */
int ret = 2 + MAX_VALUATOR_EVENTS;
#ifdef XKB
if (noXkbExtension)
#endif
ret *= 2;
return ret;
}
/**
* Convenience wrapper around GetKeyboardValuatorEvents, that takes no
* valuators.
*/
_X_EXPORT int
GetKeyboardEvents(xEvent *events, DeviceIntPtr pDev, int type, int key_code) {
return GetKeyboardValuatorEvents(events, pDev, type, key_code, 0, 0, NULL);
}
/**
* Returns a set of keyboard events for KeyPress/KeyRelease, optionally
* also with valuator events. Handles Xi and XKB.
*
* events is not NULL-terminated; the return value is the number of events.
* The DDX is responsible for allocating the event structure in the first
* place via GetMaximumEventsNum(), and for freeing it.
*
* This function does not change the core keymap to that of the device;
* that is done by SwitchCoreKeyboard, which is called from
* mieqProcessInputEvents. If replacing function, take care to call
* SetCoreKeyboard before processInputProc, so keymaps are altered to suit.
*
* Note that this function recurses! If called for non-XKB, a repeating
* key press will trigger a matching KeyRelease, as well as the
* KeyPresses.
*/
_X_EXPORT int
GetKeyboardValuatorEvents(xEvent *events, DeviceIntPtr pDev, int type,
int key_code, int first_valuator,
int num_valuators, int *valuators) {
int numEvents = 0, i = 0;
CARD32 ms = 0;
int final_valuator = first_valuator + num_valuators;
KeySym sym = pDev->key->curKeySyms.map[key_code *
pDev->key->curKeySyms.mapWidth];
deviceKeyButtonPointer *kbp = NULL;
deviceValuator *xv = NULL;
if (!events)
return 0;
if (type != KeyPress && type != KeyRelease)
return 0;
if (!pDev->key || !pDev->focus || !pDev->kbdfeed ||
(pDev->coreEvents && !inputInfo.keyboard->key))
return 0;
if (pDev->coreEvents)
numEvents = 2;
else
numEvents = 1;
if (num_valuators) {
if ((num_valuators / 6) + 1 > MAX_VALUATOR_EVENTS)
num_valuators = MAX_VALUATOR_EVENTS;
numEvents += (num_valuators / 6) + 1;
}
#ifdef XKB
if (noXkbExtension)
#endif
{
switch (sym) {
case XK_Num_Lock:
case XK_Caps_Lock:
case XK_Scroll_Lock:
case XK_Shift_Lock:
if (type == KeyRelease)
return 0;
else if (type == KeyPress &&
(pDev->key->down[key_code >> 3] & (key_code & 7)) & 1)
type = KeyRelease;
}
}
/* Handle core repeating, via press/release/press/release.
* FIXME: In theory, if you're repeating with two keyboards,
* you could get unbalanced events here. */
if (type == KeyPress &&
(((pDev->key->down[key_code >> 3] & (key_code & 7))) & 1)) {
if (!pDev->kbdfeed->ctrl.autoRepeat ||
pDev->key->modifierMap[key_code] ||
!(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3]
& (1 << (key_code & 7))))
return 0;
#ifdef XKB
if (noXkbExtension)
#endif
{
numEvents += GetKeyboardValuatorEvents(events, pDev,
KeyRelease, key_code,
first_valuator, num_valuators,
valuators);
events += numEvents;
}
}
ms = GetTimeInMillis();
kbp = (deviceKeyButtonPointer *) events;
kbp->time = ms;
kbp->deviceid = pDev->id;
if (type == KeyPress)
kbp->type = DeviceKeyPress;
else if (type == KeyRelease)
kbp->type = DeviceKeyRelease;
if (num_valuators) {
kbp->deviceid |= MORE_EVENTS;
for (i = first_valuator; i < final_valuator; i += 6) {
xv = (deviceValuator *) ++events;
xv->type = DeviceValuator;
xv->first_valuator = i;
xv->num_valuators = num_valuators;
xv->deviceid = kbp->deviceid;
switch (num_valuators - first_valuator) {
case 6:
xv->valuator5 = valuators[i+5];
case 5:
xv->valuator4 = valuators[i+4];
case 4:
xv->valuator3 = valuators[i+3];
case 3:
xv->valuator2 = valuators[i+2];
case 2:
xv->valuator1 = valuators[i+1];
case 1:
xv->valuator0 = valuators[i];
}
}
}
if (pDev->coreEvents) {
events++;
events->u.keyButtonPointer.time = ms;
events->u.u.type = type;
events->u.u.detail = key_code;
}
return numEvents;
}
/* Originally a part of xf86PostMotionEvent; modifies valuators
* in-place. */
static void
acceleratePointer(DeviceIntPtr pDev, int first_valuator, int num_valuators,
int *valuators)
{
float mult = 0.0;
int dx = 0, dy = 0;
int *px = NULL, *py = NULL;
if (!num_valuators || !valuators)
return;
if (first_valuator == 0) {
dx = valuators[0];
px = &valuators[0];
}
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) {
dy = valuators[1 - first_valuator];
py = &valuators[1 - first_valuator];
}
if (!dx && !dy)
return;
if (pDev->ptrfeed && pDev->ptrfeed->ctrl.num) {
/* modeled from xf86Events.c */
if (pDev->ptrfeed->ctrl.threshold) {
if ((abs(dx) + abs(dy)) >= pDev->ptrfeed->ctrl.threshold) {
pDev->valuator->dxremaind = ((float)dx *
(float)(pDev->ptrfeed->ctrl.num)) /
(float)(pDev->ptrfeed->ctrl.den) +
pDev->valuator->dxremaind;
if (px) {
*px = (int)pDev->valuator->dxremaind;
pDev->valuator->dxremaind = pDev->valuator->dxremaind -
(float)(*px);
}
pDev->valuator->dyremaind = ((float)dy *
(float)(pDev->ptrfeed->ctrl.num)) /
(float)(pDev->ptrfeed->ctrl.den) +
pDev->valuator->dyremaind;
if (py) {
*py = (int)pDev->valuator->dyremaind;
pDev->valuator->dyremaind = pDev->valuator->dyremaind -
(float)(*py);
}
}
}
else {
mult = pow((float)(dx * dx + dy * dy),
((float)(pDev->ptrfeed->ctrl.num) /
(float)(pDev->ptrfeed->ctrl.den) - 1.0) /
2.0) / 2.0;
if (dx) {
pDev->valuator->dxremaind = mult * (float)dx +
pDev->valuator->dxremaind;
*px = (int)pDev->valuator->dxremaind;
pDev->valuator->dxremaind = pDev->valuator->dxremaind -
(float)(*px);
}
if (dy) {
pDev->valuator->dyremaind = mult * (float)dy +
pDev->valuator->dyremaind;
*py = (int)pDev->valuator->dyremaind;
pDev->valuator->dyremaind = pDev->valuator->dyremaind -
(float)(*py);
}
}
}
}
/**
* Clip an axis to its bounds.
*/
static void
clipAxis(DeviceIntPtr pDev, int axisNum, int *val)
{
AxisInfoPtr axes = pDev->valuator->axes + axisNum;
if (*val < axes->min_value)
*val = axes->min_value;
if (axes->max_value >= 0 && *val > axes->max_value)
*val = axes->max_value;
}
/**
* Compare the list of valuators against the limits for each axis, and clip
* them to those bounds.
*/
static void
clipValuators(DeviceIntPtr pDev, int first_valuator, int num_valuators,
int *valuators)
{
AxisInfoPtr axes = pDev->valuator->axes + first_valuator;
int i;
for (i = 0; i < num_valuators; i++, axes++)
clipAxis(pDev, i + first_valuator, &(valuators[i]));
}
/**
* Fills events with valuator events for pDev, as given by the other
* parameters.
*/
static xEvent *
getValuatorEvents(xEvent *events, DeviceIntPtr pDev, int first_valuator,
int num_valuators, int *valuators) {
deviceValuator *xv = (deviceValuator *) events;
int i = 0, final_valuator = first_valuator + num_valuators;
for (i = first_valuator; i < final_valuator; i += 6, xv++, events++) {
xv->type = DeviceValuator;
xv->first_valuator = i;
xv->num_valuators = num_valuators;
xv->deviceid = pDev->id;
switch (final_valuator - i) {
case 6:
xv->valuator5 = valuators[i + 5];
case 5:
xv->valuator4 = valuators[i + 4];
case 4:
xv->valuator3 = valuators[i + 3];
case 3:
xv->valuator2 = valuators[i + 2];
case 2:
xv->valuator1 = valuators[i + 1];
case 1:
xv->valuator0 = valuators[i];
}
if (i + 6 < final_valuator)
xv->deviceid |= MORE_EVENTS;
}
return events;
}
/**
* Pick some arbitrary size for Xi motion history.
*/
_X_EXPORT int
GetMotionHistorySize()
{
return MOTION_HISTORY_SIZE;
}
/**
* Allocate the motion history buffer.
*/
_X_EXPORT void
AllocateMotionHistory(DeviceIntPtr pDev)
{
if (pDev->valuator->motion)
xfree(pDev->valuator->motion);
if (pDev->valuator->numMotionEvents < 1)
return;
pDev->valuator->motion = xalloc(((sizeof(INT32) * pDev->valuator->numAxes) +
sizeof(Time)) *
pDev->valuator->numMotionEvents);
pDev->valuator->first_motion = 0;
pDev->valuator->last_motion = 0;
}
/**
* Dump the motion history between start and stop into the supplied buffer.
* Only records the event for a given screen in theory, but in practice, we
* sort of ignore this.
*/
_X_EXPORT int
GetMotionHistory(DeviceIntPtr pDev, xTimecoord *buff, unsigned long start,
unsigned long stop, ScreenPtr pScreen)
{
int i = 0, ret = 0;
/* The size of a single motion event. */
int size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
Time current;
char *ibuff = NULL, *obuff = (char *) buff;
if (!pDev->valuator || !pDev->valuator->numMotionEvents)
return 0;
for (i = pDev->valuator->first_motion;
i != pDev->valuator->last_motion;
i = (i + 1) % pDev->valuator->numMotionEvents) {
/* We index the input buffer by which element we're accessing, which
* is not monotonic, and the output buffer by how many events we've
* written so far. */
ibuff = (char *) pDev->valuator->motion + (i * size);
memcpy(&current, ibuff, sizeof(Time));
if (current > stop) {
return ret;
}
else if (current >= start) {
memcpy(obuff, ibuff, size);
obuff += size;
ret++;
}
}
return ret;
}
/**
* Update the motion history for a specific device, with the list of
* valuators.
*/
static void
updateMotionHistory(DeviceIntPtr pDev, CARD32 ms, int first_valuator,
int num_valuators, int *valuators)
{
char *buff = (char *) pDev->valuator->motion;
if (!pDev->valuator->numMotionEvents)
return;
buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) *
pDev->valuator->last_motion;
memcpy(buff, &ms, sizeof(Time));
buff += sizeof(Time);
bzero(buff, sizeof(INT32) * pDev->valuator->numAxes);
buff += sizeof(INT32) * first_valuator;
memcpy(buff, valuators, sizeof(INT32) * num_valuators);
pDev->valuator->last_motion = (pDev->valuator->last_motion + 1) %
pDev->valuator->numMotionEvents;
/* If we're wrapping around, just keep the circular buffer going. */
if (pDev->valuator->first_motion == pDev->valuator->last_motion)
pDev->valuator->first_motion = (pDev->valuator->first_motion + 1) %
pDev->valuator->numMotionEvents;
return;
}
/**
* Generate a series of xEvents (returned in xE) representing pointer
* motion, or button presses. Xi and XKB-aware.
*
* events is not NULL-terminated; the return value is the number of events.
* The DDX is responsible for allocating the event structure in the first
* place via GetMaximumEventsNum(), and for freeing it.
*/
_X_EXPORT int
GetPointerEvents(xEvent *events, DeviceIntPtr pDev, int type, int buttons,
int flags, int first_valuator, int num_valuators,
int *valuators) {
int num_events = 0, final_valuator = 0;
CARD32 ms = 0;
deviceKeyButtonPointer *kbp = NULL;
Bool sendValuators = (type == MotionNotify || flags & POINTER_ABSOLUTE);
DeviceIntPtr cp = inputInfo.pointer;
int x = 0, y = 0;
/* Sanity checks. */
if (type != MotionNotify && type != ButtonPress && type != ButtonRelease)
return 0;
if ((type == ButtonPress || type == ButtonRelease) && !pDev->button)
return 0;
if (pDev->coreEvents)
num_events = 2;
else
num_events = 1;
/* Do we need to send a DeviceValuator event? */
if ((num_valuators + first_valuator) > 2 && sendValuators) {
if ((((num_valuators - 1) / 6) + 1) > MAX_VALUATOR_EVENTS)
num_valuators = MAX_VALUATOR_EVENTS * 6;
num_events += ((num_valuators - 1) / 6) + 1;
}
else if (type == MotionNotify && num_valuators <= 0) {
return 0;
}
final_valuator = num_valuators + first_valuator;
/* You fail. */
if (first_valuator < 0 || final_valuator > pDev->valuator->numAxes)
return 0;
ms = GetTimeInMillis();
kbp = (deviceKeyButtonPointer *) events;
kbp->time = ms;
kbp->deviceid = pDev->id;
if (flags & POINTER_ABSOLUTE) {
if (num_valuators >= 1 && first_valuator == 0) {
x = valuators[0];
}
else {
if (pDev->coreEvents)
x = cp->valuator->lastx;
else
x = pDev->valuator->lastx;
}
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) {
y = valuators[1 - first_valuator];
}
else {
if (pDev->coreEvents)
x = cp->valuator->lasty;
else
y = pDev->valuator->lasty;
}
}
else {
if (flags & POINTER_ACCELERATE)
acceleratePointer(pDev, first_valuator, num_valuators,
valuators);
if (pDev->coreEvents) {
if (first_valuator == 0 && num_valuators >= 1)
x = cp->valuator->lastx + valuators[0];
else
x = cp->valuator->lastx;
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator))
y = cp->valuator->lasty + valuators[1 - first_valuator];
else
y = cp->valuator->lasty;
}
else {
if (first_valuator == 0 && num_valuators >= 1)
x = pDev->valuator->lastx + valuators[0];
else
x = pDev->valuator->lastx;
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator))
y = pDev->valuator->lasty + valuators[1 - first_valuator];
else
y = pDev->valuator->lasty;
}
}
/* Clip both x and y to the defined limits (usually co-ord space limit). */
clipAxis(pDev, 0, &x);
clipAxis(pDev, 1, &y);
/* This takes care of crossing screens for us, as well as clipping
* to the current screen. Right now, we only have one history buffer,
* so we don't set this for both the device and core.*/
miPointerSetPosition(pDev, &x, &y, ms);
/* Drop x and y back into the valuators list, if they were originally
* present. */
if (first_valuator == 0 && num_valuators >= 1)
valuators[0] = x;
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator))
valuators[1 - first_valuator] = y;
updateMotionHistory(pDev, ms, first_valuator, num_valuators, valuators);
if (pDev->coreEvents) {
cp->valuator->lastx = x;
cp->valuator->lasty = y;
}
pDev->valuator->lastx = x;
pDev->valuator->lasty = y;
if (type == MotionNotify) {
kbp->type = DeviceMotionNotify;
}
else {
if (type == ButtonPress)
kbp->type = DeviceButtonPress;
else if (type == ButtonRelease)
kbp->type = DeviceButtonRelease;
kbp->detail = pDev->button->map[buttons];
}
kbp->root_x = x;
kbp->root_y = y;
events++;
if (final_valuator > 2 && sendValuators) {
kbp->deviceid |= MORE_EVENTS;
clipValuators(pDev, first_valuator, num_valuators, valuators);
events = getValuatorEvents(events, pDev, first_valuator,
num_valuators, valuators);
}
if (pDev->coreEvents) {
events->u.u.type = type;
events->u.keyButtonPointer.time = ms;
events->u.keyButtonPointer.rootX = x;
events->u.keyButtonPointer.rootY = y;
if (type == ButtonPress || type == ButtonRelease) {
/* We hijack SetPointerMapping to work on all core-sending
* devices, so we use the device-specific map here instead of
* the core one. */
events->u.u.detail = pDev->button->map[buttons];
}
else {
events->u.u.detail = 0;
}
}
return num_events;
}
/**
* Post ProximityIn/ProximityOut events, accompanied by valuators.
*
* events is not NULL-terminated; the return value is the number of events.
* The DDX is responsible for allocating the event structure in the first
* place via GetMaximumEventsNum(), and for freeing it.
*/
_X_EXPORT int
GetProximityEvents(xEvent *events, DeviceIntPtr pDev, int type,
int first_valuator, int num_valuators, int *valuators)
{
int num_events = 0;
deviceKeyButtonPointer *kbp = (deviceKeyButtonPointer *) events;
/* Sanity checks. */
if (type != ProximityIn && type != ProximityOut)
return 0;
if (!pDev->valuator)
return 0;
/* Do we need to send a DeviceValuator event? */
if ((pDev->valuator->mode & 1) == Relative)
num_valuators = 0;
if (num_valuators) {
if ((((num_valuators - 1) / 6) + 1) > MAX_VALUATOR_EVENTS)
num_valuators = MAX_VALUATOR_EVENTS * 6;
num_events += ((num_valuators - 1) / 6) + 1;
}
/* You fail. */
if (first_valuator < 0 ||
(num_valuators + first_valuator) > pDev->valuator->numAxes)
return 0;
kbp->type = type;
kbp->deviceid = pDev->id;
kbp->detail = 0;
kbp->time = GetTimeInMillis();
if (num_valuators) {
kbp->deviceid |= MORE_EVENTS;
events++;
events = getValuatorEvents(events, pDev, first_valuator,
num_valuators, valuators);
}
return num_events;
}
/**
* Note that pDev was the last device to send a core event. This function
* copies the complete keymap from the originating device to the core
* device, and makes sure the appropriate notifications are generated.
*
* Call this just before processInputProc.
*/
_X_EXPORT void
SwitchCoreKeyboard(DeviceIntPtr pDev)
{
KeyClassPtr ckeyc = inputInfo.keyboard->key;
if (inputInfo.keyboard->devPrivates[CoreDevicePrivatesIndex].ptr != pDev) {
memcpy(ckeyc->modifierMap, pDev->key->modifierMap, MAP_LENGTH);
if (ckeyc->modifierKeyMap)
xfree(ckeyc->modifierKeyMap);
ckeyc->modifierKeyMap = xalloc(8 * pDev->key->maxKeysPerModifier);
memcpy(ckeyc->modifierKeyMap, pDev->key->modifierKeyMap,
(8 * pDev->key->maxKeysPerModifier));
ckeyc->maxKeysPerModifier = pDev->key->maxKeysPerModifier;
ckeyc->curKeySyms.minKeyCode = pDev->key->curKeySyms.minKeyCode;
ckeyc->curKeySyms.maxKeyCode = pDev->key->curKeySyms.maxKeyCode;
SetKeySymsMap(&ckeyc->curKeySyms, &pDev->key->curKeySyms);
#ifdef XKB
if (!noXkbExtension && pDev->key->xkbInfo && pDev->key->xkbInfo->desc) {
if (!XkbCopyKeymap(pDev->key->xkbInfo->desc, ckeyc->xkbInfo->desc,
True))
FatalError("Couldn't pivot keymap from device to core!\n");
}
#endif
SendMappingNotify(MappingKeyboard, ckeyc->curKeySyms.minKeyCode,
(ckeyc->curKeySyms.maxKeyCode -
ckeyc->curKeySyms.minKeyCode),
serverClient);
inputInfo.keyboard->devPrivates[CoreDevicePrivatesIndex].ptr = pDev;
}
}
/**
* Note that pDev was the last function to send a core pointer event.
* Currently a no-op.
*
* Call this just before processInputProc.
*/
_X_EXPORT void
SwitchCorePointer(DeviceIntPtr pDev)
{
if (inputInfo.pointer->devPrivates[CoreDevicePrivatesIndex].ptr != pDev)
inputInfo.pointer->devPrivates[CoreDevicePrivatesIndex].ptr = pDev;
}
/**
* Synthesize a single motion event for the core pointer.
*
* Used in cursor functions, e.g. when cursor confinement changes, and we need
* to shift the pointer to get it inside the new bounds.
*/
void
PostSyntheticMotion(int x, int y, ScreenPtr pScreen, unsigned long time)
{
xEvent xE;
#ifdef PANORAMIX
/* Translate back to the sprite screen since processInputProc
will translate from sprite screen to screen 0 upon reentry
to the DIX layer. */
if (!noPanoramiXExtension) {
x += panoramiXdataPtr[0].x - panoramiXdataPtr[pScreen->myNum].x;
y += panoramiXdataPtr[0].y - panoramiXdataPtr[pScreen->myNum].y;
}
#endif
memset(&xE, 0, sizeof(xEvent));
xE.u.u.type = MotionNotify;
xE.u.keyButtonPointer.rootX = x;
xE.u.keyButtonPointer.rootY = y;
xE.u.keyButtonPointer.time = time;
(*inputInfo.pointer->public.processInputProc)(&xE, inputInfo.pointer, 1);
}