xserver-multidpi/dix/getevents.c

1158 lines
36 KiB
C
Raw Normal View History

/*
* Copyright © 2006 Nokia Corporation
* Copyright © 2006-2007 Daniel Stone
2006-10-19 23:44:46 +02:00
*
* 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <X11/X.h>
#include <X11/keysym.h>
#define NEED_EVENTS
#define NEED_REPLIES
#include <X11/Xproto.h>
#include "misc.h"
#include "resource.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 <xkbsrv.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"
#include "listdev.h" /* for sizing up DeviceClassesChangedEvent */
/* Maximum number of valuators, divided by six, rounded up, to get number
* of events. */
#define MAX_VALUATOR_EVENTS 6
/* Number of motion history events to store. */
#define MOTION_HISTORY_SIZE 256
/* InputEventList is the container list for all input events generated by the
* DDX. The DDX is expected to call GetEventList() and then pass the list into
* Get{Pointer|Keyboard}Events.
*/
Export symbols defined in the sdk. This is the biggest "visibility" patch. Instead of doing a "export" symbol on demand, export everything in the sdk, so that if some module fails due to an unresolved symbol, it is because it is using a symbol not in the sdk. Most exported symbols shouldn't really be made visible, neither advertised in the sdk, as they are only used by a single shared object. Symbols in the sdk (or referenced in sdk macros), but not defined anywhere include: XkbBuildCoreState() XkbInitialMap XkbXIUnsupported XkbCheckActionVMods() XkbSendCompatNotify() XkbDDXFakePointerButton() XkbDDXApplyConfig() _XkbStrCaseCmp() _XkbErrMessages[] _XkbErrCode _XkbErrLocation _XkbErrData XkbAccessXDetailText() XkbNKNDetailMaskText() XkbLookupGroupAndLevel() XkbInitAtoms() XkbGetOrderedDrawables() XkbFreeOrderedDrawables() XkbConvertXkbComponents() XkbWriteXKBSemantics() XkbWriteXKBLayout() XkbWriteXKBKeymap() XkbWriteXKBFile() XkbWriteCFile() XkbWriteXKMFile() XkbWriteToServer() XkbMergeFile() XkmFindTOCEntry() XkmReadFileSection() XkmReadFileSectionName() InitExtInput() xf86CheckButton() xf86SwitchCoreDevice() RamDacSetGamma() RamDacRestoreDACValues() xf86Bpp xf86ConfigPix24 xf86MouseCflags[] xf86SupportedMouseTypes[] xf86NumMouseTypes xf86ChangeBusIndex() xf86EntityEnter() xf86EntityLeave() xf86WrapperInit() xf86RingBell() xf86findOptionBoolean() xf86debugListOptions() LoadSubModuleLocal() LoaderSymbolLocal() getInt10Rec() xf86CurrentScreen xf86ReallocatePciResources() xf86NewSerialNumber() xf86RandRSetInitialMode() fbCompositeSolidMask_nx1xn fbCompositeSolidMask_nx8888x0565C fbCompositeSolidMask_nx8888x8888C fbCompositeSolidMask_nx8x0565 fbCompositeSolidMask_nx8x0888 fbCompositeSolidMask_nx8x8888 fbCompositeSrc_0565x0565 fbCompositeSrc_8888x0565 fbCompositeSrc_8888x0888 fbCompositeSrc_8888x8888 fbCompositeSrcAdd_1000x1000 fbCompositeSrcAdd_8000x8000 fbCompositeSrcAdd_8888x8888 fbGeneration fbIn fbOver fbOver24 fbOverlayGeneration fbRasterizeEdges fbRestoreAreas fbSaveAreas composeFunctions VBEBuildVbeModeList() VBECalcVbeModeIndex() TIramdac3030CalculateMNPForClock() shadowBufPtr shadowFindBuf() miRRGetScreenInfo() RRSetScreenConfig() RRModePruneUnused() PixmanImageFromPicture() extern int miPointerGetMotionEvents() miClipPicture() miRasterizeTriangle() fbPush1toN() fbInitializeBackingStore() ddxBeforeReset() SetupSprite() InitSprite() DGADeliverEvent() SPECIAL CASES o defined as _X_INTERNAL xf86NewInputDevice() o defined as static fbGCPrivateKey fbOverlayScreenPrivateKey fbScreenPrivateKey fbWinPrivateKey o defined in libXfont.so, but declared in xorg/dixfont.h GetGlyphs() QueryGlyphExtents() QueryTextExtents() ParseGlyphCachingMode() InitGlyphCaching() SetGlyphCachingMode()
2008-11-30 02:56:06 +01:00
_X_EXPORT EventListPtr InputEventList = NULL;
_X_EXPORT int InputEventListLen = 0;
_X_EXPORT int
GetEventList(EventListPtr* list)
{
*list = InputEventList;
return InputEventListLen;
}
/**
* Pick some arbitrary size for Xi motion history.
*/
_X_EXPORT int
GetMotionHistorySize(void)
{
return MOTION_HISTORY_SIZE;
}
static void
set_key_down(DeviceIntPtr pDev, int key_code)
{
pDev->key->postdown[key_code >> 3] |= (1 << (key_code & 7));
}
static void
set_key_up(DeviceIntPtr pDev, int key_code)
{
pDev->key->postdown[key_code >> 3] &= ~(1 << (key_code & 7));
}
static Bool
key_is_down(DeviceIntPtr pDev, int key_code)
{
return !!(pDev->key->postdown[key_code >> 3] & (1 << (key_code & 7)));
}
static Bool
key_autorepeats(DeviceIntPtr pDev, int key_code)
{
return !!(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3] &
(1 << (key_code & 7)));
}
Export symbols defined in the sdk. This is the biggest "visibility" patch. Instead of doing a "export" symbol on demand, export everything in the sdk, so that if some module fails due to an unresolved symbol, it is because it is using a symbol not in the sdk. Most exported symbols shouldn't really be made visible, neither advertised in the sdk, as they are only used by a single shared object. Symbols in the sdk (or referenced in sdk macros), but not defined anywhere include: XkbBuildCoreState() XkbInitialMap XkbXIUnsupported XkbCheckActionVMods() XkbSendCompatNotify() XkbDDXFakePointerButton() XkbDDXApplyConfig() _XkbStrCaseCmp() _XkbErrMessages[] _XkbErrCode _XkbErrLocation _XkbErrData XkbAccessXDetailText() XkbNKNDetailMaskText() XkbLookupGroupAndLevel() XkbInitAtoms() XkbGetOrderedDrawables() XkbFreeOrderedDrawables() XkbConvertXkbComponents() XkbWriteXKBSemantics() XkbWriteXKBLayout() XkbWriteXKBKeymap() XkbWriteXKBFile() XkbWriteCFile() XkbWriteXKMFile() XkbWriteToServer() XkbMergeFile() XkmFindTOCEntry() XkmReadFileSection() XkmReadFileSectionName() InitExtInput() xf86CheckButton() xf86SwitchCoreDevice() RamDacSetGamma() RamDacRestoreDACValues() xf86Bpp xf86ConfigPix24 xf86MouseCflags[] xf86SupportedMouseTypes[] xf86NumMouseTypes xf86ChangeBusIndex() xf86EntityEnter() xf86EntityLeave() xf86WrapperInit() xf86RingBell() xf86findOptionBoolean() xf86debugListOptions() LoadSubModuleLocal() LoaderSymbolLocal() getInt10Rec() xf86CurrentScreen xf86ReallocatePciResources() xf86NewSerialNumber() xf86RandRSetInitialMode() fbCompositeSolidMask_nx1xn fbCompositeSolidMask_nx8888x0565C fbCompositeSolidMask_nx8888x8888C fbCompositeSolidMask_nx8x0565 fbCompositeSolidMask_nx8x0888 fbCompositeSolidMask_nx8x8888 fbCompositeSrc_0565x0565 fbCompositeSrc_8888x0565 fbCompositeSrc_8888x0888 fbCompositeSrc_8888x8888 fbCompositeSrcAdd_1000x1000 fbCompositeSrcAdd_8000x8000 fbCompositeSrcAdd_8888x8888 fbGeneration fbIn fbOver fbOver24 fbOverlayGeneration fbRasterizeEdges fbRestoreAreas fbSaveAreas composeFunctions VBEBuildVbeModeList() VBECalcVbeModeIndex() TIramdac3030CalculateMNPForClock() shadowBufPtr shadowFindBuf() miRRGetScreenInfo() RRSetScreenConfig() RRModePruneUnused() PixmanImageFromPicture() extern int miPointerGetMotionEvents() miClipPicture() miRasterizeTriangle() fbPush1toN() fbInitializeBackingStore() ddxBeforeReset() SetupSprite() InitSprite() DGADeliverEvent() SPECIAL CASES o defined as _X_INTERNAL xf86NewInputDevice() o defined as static fbGCPrivateKey fbOverlayScreenPrivateKey fbScreenPrivateKey fbWinPrivateKey o defined in libXfont.so, but declared in xorg/dixfont.h GetGlyphs() QueryGlyphExtents() QueryTextExtents() ParseGlyphCachingMode() InitGlyphCaching() SetGlyphCachingMode()
2008-11-30 02:56:06 +01:00
_X_EXPORT void
CreateClassesChangedEvent(EventList* event,
DeviceIntPtr master,
DeviceIntPtr slave)
{
deviceClassesChangedEvent *dcce;
int len = sizeof(xEvent);
CARD32 ms = GetTimeInMillis();
int namelen = 0; /* dummy */
/* XXX: ok, this is a bit weird. We need to alloc enough size for the
* event so it can be filled in in POE lateron. Reason being that if
* we realloc the event in POE we can get SIGABRT when we try to free
* or realloc the original pointer.
* We can only do it here as we don't have the EventList in the event
* processing any more.
*/
SizeDeviceInfo(slave, &namelen, &len);
if (event->evlen < len)
{
event->event = realloc(event->event, len);
if (!event->event)
FatalError("[dix] Cannot allocate memory for "
"DeviceClassesChangedEvent.\n");
event->evlen = len;
}
dcce = (deviceClassesChangedEvent*)event->event;
dcce->type = GenericEvent;
dcce->extension = IReqCode;
dcce->evtype = XI_DeviceClassesChangedNotify;
dcce->time = ms;
dcce->new_slave = slave->id;
dcce->length = (len - sizeof(xEvent))/4;
}
/**
* Rescale the coord between the two axis ranges.
*/
static int
rescaleValuatorAxis(int coord, AxisInfoPtr from, AxisInfoPtr to,
int defmax)
{
int fmin = 0, tmin = 0, fmax = defmax, tmax = defmax;
if(from && from->min_value < from->max_value) {
fmin = from->min_value;
fmax = from->max_value;
}
if(to && to->min_value < to->max_value) {
tmin = to->min_value;
tmax = to->max_value;
}
if(fmin == tmin && fmax == tmax)
return coord;
if(fmax == fmin) /* avoid division by 0 */
return 0;
return roundf(((float)(coord - fmin)) * (tmax - tmin) /
(fmax - fmin)) + tmin;
}
/**
* Update all coordinates when changing to a different SD
* to ensure that relative reporting will work as expected
* without loss of precision.
*
* pDev->last.valuators will be in absolute device coordinates after this
* function.
*/
static void
updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev)
{
ScreenPtr scr = miPointerGetScreen(pDev);
int i;
DeviceIntPtr lastSlave;
/* master->last.valuators[0]/[1] is in screen coords and the actual
* position of the pointer */
pDev->last.valuators[0] = master->last.valuators[0];
pDev->last.valuators[1] = master->last.valuators[1];
if (!pDev->valuator)
return;
/* scale back to device coordinates */
if(pDev->valuator->numAxes > 0)
pDev->last.valuators[0] = rescaleValuatorAxis(pDev->last.valuators[0], NULL, pDev->valuator->axes + 0, scr->width);
if(pDev->valuator->numAxes > 1)
pDev->last.valuators[1] = rescaleValuatorAxis(pDev->last.valuators[1], NULL, pDev->valuator->axes + 1, scr->height);
/* calculate the other axis as well based on info from the old
* slave-device. If the old slave had less axes than this one,
* last.valuators is reset to 0.
*/
if ((lastSlave = master->u.lastSlave) && lastSlave->valuator) {
for (i = 2; i < pDev->valuator->numAxes; i++) {
if (i >= lastSlave->valuator->numAxes)
pDev->last.valuators[i] = 0;
else
pDev->last.valuators[i] =
rescaleValuatorAxis(pDev->last.valuators[i],
lastSlave->valuator->axes + i,
pDev->valuator->axes + i, 0);
}
}
}
/**
* Allocate the motion history buffer.
*/
_X_EXPORT void
AllocateMotionHistory(DeviceIntPtr pDev)
{
int size;
if (pDev->valuator->motion)
xfree(pDev->valuator->motion);
if (pDev->valuator->numMotionEvents < 1)
return;
/* An MD must have a motion history size large enough to keep all
* potential valuators, plus the respective range of the valuators.
* 3 * INT32 for (min_val, max_val, curr_val))
*/
if (pDev->isMaster)
size = sizeof(INT32) * 3 * MAX_VALUATORS;
else
size = sizeof(INT32) * pDev->valuator->numAxes;
size += sizeof(Time);
pDev->valuator->motion = xcalloc(pDev->valuator->numMotionEvents, size);
pDev->valuator->first_motion = 0;
pDev->valuator->last_motion = 0;
if (!pDev->valuator->motion)
ErrorF("[dix] %s: Failed to alloc motion history (%d bytes).\n",
pDev->name, size * pDev->valuator->numMotionEvents);
}
/**
* 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.
*
* If core is set, we only generate x/y, in INT16, scaled to screen coords.
*/
_X_EXPORT int
GetMotionHistory(DeviceIntPtr pDev, xTimecoord **buff, unsigned long start,
unsigned long stop, ScreenPtr pScreen, BOOL core)
{
char *ibuff = NULL, *obuff;
int i = 0, ret = 0;
int j, coord;
Time current;
/* The size of a single motion event. */
int size;
int dflt;
AxisInfo from, *to; /* for scaling */
INT32 *ocbuf, *icbuf; /* pointer to coordinates for copying */
INT16 *corebuf;
AxisInfo core_axis = {0};
if (!pDev->valuator || !pDev->valuator->numMotionEvents)
return 0;
2006-10-19 23:44:46 +02:00
if (core && !pScreen)
return 0;
if (pDev->isMaster)
size = (sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(Time);
else
size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
*buff = xalloc(size * pDev->valuator->numMotionEvents);
if (!(*buff))
return 0;
obuff = (char *)*buff;
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) {
if (core)
{
memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */
icbuf = (INT32*)(ibuff + sizeof(Time));
corebuf = (INT16*)(obuff + sizeof(Time));
/* fetch x coordinate + range */
memcpy(&from.min_value, icbuf++, sizeof(INT32));
memcpy(&from.max_value, icbuf++, sizeof(INT32));
memcpy(&coord, icbuf++, sizeof(INT32));
/* scale to screen coords */
to = &core_axis;
to->max_value = pScreen->width;
coord = rescaleValuatorAxis(coord, &from, to, pScreen->width);
memcpy(corebuf, &coord, sizeof(INT16));
corebuf++;
/* fetch y coordinate + range */
memcpy(&from.min_value, icbuf++, sizeof(INT32));
memcpy(&from.max_value, icbuf++, sizeof(INT32));
memcpy(&coord, icbuf++, sizeof(INT32));
to->max_value = pScreen->height;
coord = rescaleValuatorAxis(coord, &from, to, pScreen->height);
memcpy(corebuf, &coord, sizeof(INT16));
} else if (pDev->isMaster)
{
memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */
ocbuf = (INT32*)(obuff + sizeof(Time));
icbuf = (INT32*)(ibuff + sizeof(Time));
for (j = 0; j < MAX_VALUATORS; j++)
{
if (j >= pDev->valuator->numAxes)
break;
/* fetch min/max/coordinate */
memcpy(&from.min_value, icbuf++, sizeof(INT32));
memcpy(&from.max_value, icbuf++, sizeof(INT32));
memcpy(&coord, icbuf++, sizeof(INT32));
to = (j < pDev->valuator->numAxes) ? &pDev->valuator->axes[j] : NULL;
/* x/y scaled to screen if no range is present */
if (j == 0 && (from.max_value < from.min_value))
from.max_value = pScreen->width;
else if (j == 1 && (from.max_value < from.min_value))
from.max_value = pScreen->height;
if (j == 0 && (to->max_value < to->min_value))
dflt = pScreen->width;
else if (j == 1 && (to->max_value < to->min_value))
dflt = pScreen->height;
else
dflt = 0;
/* scale from stored range into current range */
coord = rescaleValuatorAxis(coord, &from, to, 0);
memcpy(ocbuf, &coord, sizeof(INT32));
ocbuf++;
}
} else
memcpy(obuff, ibuff, size);
/* don't advance by size here. size may be different to the
* actually written size if the MD has less valuators than MAX */
if (core)
obuff += sizeof(INT32) + sizeof(Time);
else
obuff += (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
ret++;
}
}
return ret;
}
/**
* Update the motion history for a specific device, with the list of
* valuators.
*
* Layout of the history buffer:
* for SDs: [time] [val0] [val1] ... [valn]
* for MDs: [time] [min_val0] [max_val0] [val0] [min_val1] ... [valn]
*
* For events that have some valuators unset (first_valuator > 0):
* min_val == max_val == val == 0.
*/
static void
updateMotionHistory(DeviceIntPtr pDev, CARD32 ms, int first_valuator,
int num_valuators, int *valuators)
{
char *buff = (char *) pDev->valuator->motion;
ValuatorClassPtr v;
int i;
if (!pDev->valuator->numMotionEvents)
return;
v = pDev->valuator;
if (pDev->isMaster)
{
buff += ((sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(CARD32)) *
v->last_motion;
memcpy(buff, &ms, sizeof(Time));
buff += sizeof(Time);
memset(buff, 0, sizeof(INT32) * 3 * MAX_VALUATORS);
buff += 3 * sizeof(INT32) * first_valuator;
for (i = first_valuator; i < first_valuator + num_valuators; i++)
{
if (i >= v->numAxes)
break;
memcpy(buff, &v->axes[i].min_value, sizeof(INT32));
buff += sizeof(INT32);
memcpy(buff, &v->axes[i].max_value, sizeof(INT32));
buff += sizeof(INT32);
memcpy(buff, &valuators[i - first_valuator], sizeof(INT32));
buff += sizeof(INT32);
}
} else
{
buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) *
pDev->valuator->last_motion;
memcpy(buff, &ms, sizeof(Time));
buff += sizeof(Time);
memset(buff, 0, 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;
}
/**
* 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());
*
* This MUST be absolutely constant, from init until exit.
*/
_X_EXPORT int
GetMaximumEventsNum(void) {
/* One base event -- device, plus valuator events.
* Multiply by two if we're doing non-XKB key repeats. */
int ret = 1 + MAX_VALUATOR_EVENTS;
#ifdef XKB
if (noXkbExtension)
#endif
ret *= 2;
/* One possible DeviceClassesChangedEvent */
ret++;
return ret;
}
/**
* Clip an axis to its bounds, which are declared in the call to
* InitValuatorAxisClassStruct.
*/
static void
clipAxis(DeviceIntPtr pDev, int axisNum, int *val)
{
2008-04-30 05:47:14 +02:00
AxisInfoPtr axis = pDev->valuator->axes + axisNum;
/* InitValuatoraAxisStruct ensures that (min < max). */
/* If a value range is defined, clip. If not, do nothing */
if (axis->max_value <= axis->min_value)
return;
if (*val < axis->min_value)
2008-04-30 05:47:14 +02:00
*val = axis->min_value;
if (*val > axis->max_value)
2008-04-30 05:47:14 +02:00
*val = axis->max_value;
}
/**
* Clip every axis in the list of valuators to its 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 EventList *
getValuatorEvents(EventList *events, DeviceIntPtr pDev,
int first_valuator, int num_valuators, int *valuators) {
deviceValuator *xv;
int i;
for (i = 0; i < num_valuators; i += 6, events++) {
xv = (deviceValuator*)events->event;
xv->type = DeviceValuator;
xv->first_valuator = first_valuator + i;
xv->num_valuators = ((num_valuators - i) > 6) ? 6 : (num_valuators - i);
xv->deviceid = pDev->id;
switch (num_valuators - 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 + 0];
}
if (i + 6 < num_valuators)
xv->deviceid |= MORE_EVENTS;
}
return events;
}
/**
* Create the DCCE event (does not update the master's device state yet, this
* is done in the event processing).
* Pull in the coordinates from the MD if necessary.
*
* @param events Pointer to a pre-allocated event list.
* @param dev The slave device that generated an event.
* @param num_events The current number of events, returns the number of
* events if a DCCE was generated.
* @return The updated @events pointer.
*/
static EventListPtr
updateFromMaster(EventListPtr events, DeviceIntPtr dev, int *num_events)
{
DeviceIntPtr master = dev->u.master;
if (master && master->u.lastSlave != dev)
{
CreateClassesChangedEvent(events, master, dev);
updateSlaveDeviceCoords(master, dev);
master->u.lastSlave = dev;
master->last.numValuators = dev->last.numValuators;
(*num_events)++;
events++;
}
return events;
}
/**
* Move the device's pointer to the position given in the valuators.
*
* @param dev The device which's pointer is to be moved.
* @param x Returns the x position of the pointer after the move.
* @param y Returns the y position of the pointer after the move.
* @param first The first valuator in @valuators
* @param num Total number of valuators in @valuators.
* @param valuators Valuator data for each axis between @first and
* @first+@num.
*/
static void
moveAbsolute(DeviceIntPtr dev, int *x, int *y,
int first, int num, int *valuators)
{
int i;
if (num >= 1 && first == 0)
*x = *(valuators + 0);
else
*x = dev->last.valuators[0];
if (first <= 1 && num >= (2 - first))
*y = *(valuators + 1 - first);
else
*y = dev->last.valuators[1];
clipAxis(dev, 0, x);
clipAxis(dev, 1, y);
i = (first > 2) ? 0 : 2;
for (; i < num; i++)
{
dev->last.valuators[i + first] = valuators[i];
clipAxis(dev, i, &dev->last.valuators[i + first]);
}
}
/**
* Move the device's pointer by the values given in @valuators.
*
* @param dev The device which's pointer is to be moved.
* @param x Returns the x position of the pointer after the move.
* @param y Returns the y position of the pointer after the move.
* @param first The first valuator in @valuators
* @param num Total number of valuators in @valuators.
* @param valuators Valuator data for each axis between @first and
* @first+@num.
*/
static void
moveRelative(DeviceIntPtr dev, int *x, int *y,
int first, int num, int *valuators)
{
int i;
*x = dev->last.valuators[0];
*y = dev->last.valuators[1];
if (num >= 1 && first == 0)
*x += *(valuators +0);
if (first <= 1 && num >= (2 - first))
*y += *(valuators + 1 - first);
/* if attached, clip both x and y to the defined limits (usually
* co-ord space limit). If it is attached, we need x/y to go over the
* limits to be able to change screens. */
if(dev->u.master) {
clipAxis(dev, 0, x);
clipAxis(dev, 1, y);
}
/* calc other axes, clip, drop back into valuators */
i = (first > 2) ? 0 : 2;
for (; i < num; i++)
{
dev->last.valuators[i + first] += valuators[i];
clipAxis(dev, i, &dev->last.valuators[i + first]);
valuators[i] = dev->last.valuators[i + first];
}
}
/**
* Accelerate the data in valuators based on the device's acceleration scheme.
*
* @param dev The device which's pointer is to be moved.
* @param first The first valuator in @valuators
* @param num Total number of valuators in @valuators.
* @param valuators Valuator data for each axis between @first and
* @first+@num.
* @param ms Current time.
*/
static void
accelPointer(DeviceIntPtr dev, int first, int num, int *valuators, CARD32 ms)
{
if (dev->valuator->accelScheme.AccelSchemeProc)
dev->valuator->accelScheme.AccelSchemeProc(dev, first, num, valuators, ms);
}
/**
* If we have HW cursors, this actually moves the visible sprite. If not, we
* just do all the screen crossing, etc.
*
* We scale from device to screen coordinates here, call
* miPointerSetPosition() and then scale back into device coordinates (if
* needed). miPSP will change x/y if the screen was crossed.
*
* @param dev The device to be moved.
* @param x Pointer to current x-axis value, may be modified.
* @param y Pointer to current y-axis value, may be modified.
* @param scr Screen the device's sprite is currently on.
* @param screenx Screen x coordinate the sprite is on after the update.
* @param screeny Screen y coordinate the sprite is on after the update.
*/
static void
positionSprite(DeviceIntPtr dev, int *x, int *y,
ScreenPtr scr, int *screenx, int *screeny)
{
/* scale x&y to screen */
*screenx = rescaleValuatorAxis(*x, dev->valuator->axes + 0, NULL, scr->width);
*screeny = rescaleValuatorAxis(*y, dev->valuator->axes + 1, NULL, scr->height);
dev->last.valuators[0] = *screenx;
dev->last.valuators[1] = *screeny;
/* This takes care of crossing screens for us, as well as clipping
* to the current screen. */
miPointerSetPosition(dev, &dev->last.valuators[0], &dev->last.valuators[1]);
if (dev->u.master) {
dev->u.master->last.valuators[0] = dev->last.valuators[0];
dev->u.master->last.valuators[1] = dev->last.valuators[1];
}
/* Crossed screen? Scale back to device coordiantes */
if(*screenx != dev->last.valuators[0])
{
scr = miPointerGetScreen(dev);
*x = rescaleValuatorAxis(dev->last.valuators[0], NULL,
dev->valuator->axes + 0, scr->width);
*screenx = dev->last.valuators[0];
}
if(*screeny != dev->last.valuators[1])
{
scr = miPointerGetScreen(dev);
*screeny = dev->last.valuators[1];
*y = rescaleValuatorAxis(dev->last.valuators[1], NULL,
dev->valuator->axes + 1, scr->height);
}
}
/**
* Update the motion history for the device and (if appropriate) for its
* master device.
* @param dev Slave device to update.
* @param first First valuator to append to history.
* @param num Total number of valuators to append to history.
* @param ms Current time
*/
static void
updateHistory(DeviceIntPtr dev, int first, int num, CARD32 ms)
{
updateMotionHistory(dev, ms, first, num, &dev->last.valuators[first]);
if (dev->u.master)
updateMotionHistory(dev->u.master, ms, first, num,
&dev->last.valuators[first]);
}
/**
* Calculate how many DeviceValuator events are needed given a number of
* valuators.
* @param num_valuators Number of valuators to attach to event.
* @return the number of DeviceValuator events needed.
*/
static int
countValuatorEvents(int num_valuators)
{
if (num_valuators) {
if ((num_valuators / 6) + 1 > MAX_VALUATOR_EVENTS)
num_valuators = MAX_VALUATOR_EVENTS;
return (num_valuators / 6) + 1;
} else
return 0;
}
/**
* Convenience wrapper around GetKeyboardValuatorEvents, that takes no
* valuators.
*/
_X_EXPORT int
GetKeyboardEvents(EventList *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.
*
* DOES NOT GENERATE CORE EVENTS! Core events are created when processing the
* event (ProcessOtherEvent).
*
* 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 that 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(EventList *events, DeviceIntPtr pDev, int type,
int key_code, int first_valuator,
int num_valuators, int *valuators) {
int numEvents = 0;
CARD32 ms = 0;
KeySym *map;
KeySym sym;
deviceKeyButtonPointer *kbp = NULL;
if (!events ||!pDev->key || !pDev->focus || !pDev->kbdfeed ||
(type != KeyPress && type != KeyRelease) ||
(key_code < 8 || key_code > 255))
return 0;
numEvents = 1;
map = pDev->key->curKeySyms.map;
sym = map[(key_code - pDev->key->curKeySyms.minKeyCode)
* pDev->key->curKeySyms.mapWidth];
events = updateFromMaster(events, pDev, &numEvents);
numEvents += countValuatorEvents(num_valuators);
#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 && key_is_down(pDev, key_code))
type = KeyRelease;
}
}
/* Handle core repeating, via press/release/press/release.
* FIXME: In theory, if you're repeating with two keyboards in non-XKB,
* you could get unbalanced events here. */
if (type == KeyPress && key_is_down(pDev, key_code)) {
/* If autorepeating is disabled either globally or just for that key,
* or we have a modifier, don't generate a repeat event. */
if (!pDev->kbdfeed->ctrl.autoRepeat ||
!key_autorepeats(pDev, key_code) ||
pDev->key->modifierMap[key_code])
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->event;
kbp->time = ms;
kbp->deviceid = pDev->id;
kbp->detail = key_code;
if (type == KeyPress) {
kbp->type = DeviceKeyPress;
set_key_down(pDev, key_code);
}
else if (type == KeyRelease) {
kbp->type = DeviceKeyRelease;
set_key_up(pDev, key_code);
}
events++;
if (num_valuators) {
kbp->deviceid |= MORE_EVENTS;
clipValuators(pDev, first_valuator, num_valuators, valuators);
events = getValuatorEvents(events, pDev, first_valuator,
num_valuators, valuators);
}
return numEvents;
}
/**
* Initialize an event list and fill with 32 byte sized events.
* This event list is to be passed into GetPointerEvents() and
* GetKeyboardEvents().
*
* @param num_events Number of elements in list.
*/
Export symbols defined in the sdk. This is the biggest "visibility" patch. Instead of doing a "export" symbol on demand, export everything in the sdk, so that if some module fails due to an unresolved symbol, it is because it is using a symbol not in the sdk. Most exported symbols shouldn't really be made visible, neither advertised in the sdk, as they are only used by a single shared object. Symbols in the sdk (or referenced in sdk macros), but not defined anywhere include: XkbBuildCoreState() XkbInitialMap XkbXIUnsupported XkbCheckActionVMods() XkbSendCompatNotify() XkbDDXFakePointerButton() XkbDDXApplyConfig() _XkbStrCaseCmp() _XkbErrMessages[] _XkbErrCode _XkbErrLocation _XkbErrData XkbAccessXDetailText() XkbNKNDetailMaskText() XkbLookupGroupAndLevel() XkbInitAtoms() XkbGetOrderedDrawables() XkbFreeOrderedDrawables() XkbConvertXkbComponents() XkbWriteXKBSemantics() XkbWriteXKBLayout() XkbWriteXKBKeymap() XkbWriteXKBFile() XkbWriteCFile() XkbWriteXKMFile() XkbWriteToServer() XkbMergeFile() XkmFindTOCEntry() XkmReadFileSection() XkmReadFileSectionName() InitExtInput() xf86CheckButton() xf86SwitchCoreDevice() RamDacSetGamma() RamDacRestoreDACValues() xf86Bpp xf86ConfigPix24 xf86MouseCflags[] xf86SupportedMouseTypes[] xf86NumMouseTypes xf86ChangeBusIndex() xf86EntityEnter() xf86EntityLeave() xf86WrapperInit() xf86RingBell() xf86findOptionBoolean() xf86debugListOptions() LoadSubModuleLocal() LoaderSymbolLocal() getInt10Rec() xf86CurrentScreen xf86ReallocatePciResources() xf86NewSerialNumber() xf86RandRSetInitialMode() fbCompositeSolidMask_nx1xn fbCompositeSolidMask_nx8888x0565C fbCompositeSolidMask_nx8888x8888C fbCompositeSolidMask_nx8x0565 fbCompositeSolidMask_nx8x0888 fbCompositeSolidMask_nx8x8888 fbCompositeSrc_0565x0565 fbCompositeSrc_8888x0565 fbCompositeSrc_8888x0888 fbCompositeSrc_8888x8888 fbCompositeSrcAdd_1000x1000 fbCompositeSrcAdd_8000x8000 fbCompositeSrcAdd_8888x8888 fbGeneration fbIn fbOver fbOver24 fbOverlayGeneration fbRasterizeEdges fbRestoreAreas fbSaveAreas composeFunctions VBEBuildVbeModeList() VBECalcVbeModeIndex() TIramdac3030CalculateMNPForClock() shadowBufPtr shadowFindBuf() miRRGetScreenInfo() RRSetScreenConfig() RRModePruneUnused() PixmanImageFromPicture() extern int miPointerGetMotionEvents() miClipPicture() miRasterizeTriangle() fbPush1toN() fbInitializeBackingStore() ddxBeforeReset() SetupSprite() InitSprite() DGADeliverEvent() SPECIAL CASES o defined as _X_INTERNAL xf86NewInputDevice() o defined as static fbGCPrivateKey fbOverlayScreenPrivateKey fbScreenPrivateKey fbWinPrivateKey o defined in libXfont.so, but declared in xorg/dixfont.h GetGlyphs() QueryGlyphExtents() QueryTextExtents() ParseGlyphCachingMode() InitGlyphCaching() SetGlyphCachingMode()
2008-11-30 02:56:06 +01:00
_X_EXPORT EventListPtr
InitEventList(int num_events)
{
EventListPtr events;
int i;
events = (EventListPtr)xcalloc(num_events, sizeof(EventList));
if (!events)
return NULL;
for (i = 0; i < num_events; i++)
{
events[i].evlen = sizeof(xEvent);
events[i].event = xcalloc(1, sizeof(xEvent));
if (!events[i].event)
{
/* rollback */
while(i--)
xfree(events[i].event);
xfree(events);
events = NULL;
break;
}
}
return events;
}
/**
* Allocs min_size memory for each event in the list.
*/
_X_EXPORT void
SetMinimumEventSize(EventListPtr list, int num_events, int min_size)
{
if (!list)
return;
while(num_events--)
{
if (list[num_events].evlen < min_size)
{
list[num_events].evlen = min_size;
list[num_events].event = realloc(list[num_events].event, min_size);
if (!list[num_events].event)
{
FatalError("[dix] Failed to set event list's "
"min_size to %d.\n", min_size);
}
}
}
}
/**
* Free an event list.
*
* @param list The list to be freed.
* @param num_events Number of elements in list.
*/
_X_EXPORT void
FreeEventList(EventListPtr list, int num_events)
{
if (!list)
return;
while(num_events--)
xfree(list[num_events].event);
xfree(list);
}
/**
* Generate a series of xEvents (filled into the EventList) representing
* pointer motion, or button presses. Xi and XKB-aware.
*
* DOES NOT GENERATE CORE EVENTS! Core events are created when processing the
* event (ProcessOtherEvent).
*
* 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 InitEventList() and GetMaximumEventsNum(), and for freeing it.
*
* In the generated events rootX/Y will be in absolute screen coords and
* the valuator information in the absolute or relative device coords.
*
* last.valuators[x] of the device is always in absolute device coords.
* last.valuators[x] of the master device is in absolute screen coords.
*
* master->last.valuators[x] for x > 2 is undefined.
*/
_X_EXPORT int
GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons,
int flags, int first_valuator, int num_valuators,
int *valuators) {
int num_events = 1;
CARD32 ms;
deviceKeyButtonPointer *kbp = NULL;
int x, y, /* switches between device and screen coords */
cx, cy; /* only screen coordinates */
ScreenPtr scr = miPointerGetScreen(pDev);
ms = GetTimeInMillis(); /* before pointer update to help precision */
if (!scr || !pDev->valuator || first_valuator < 0 ||
((num_valuators + first_valuator) > pDev->valuator->numAxes) ||
(type != MotionNotify && type != ButtonPress && type != ButtonRelease) ||
(type != MotionNotify && !pDev->button) ||
(type == MotionNotify && num_valuators <= 0))
return 0;
num_events += countValuatorEvents(num_valuators);
events = updateFromMaster(events, pDev, &num_events);
if (flags & POINTER_ABSOLUTE)
moveAbsolute(pDev, &x, &y, first_valuator, num_valuators, valuators);
else {
if (flags & POINTER_ACCELERATE)
accelPointer(pDev, first_valuator, num_valuators, valuators, ms);
moveRelative(pDev, &x, &y, first_valuator, num_valuators, valuators);
}
positionSprite(pDev, &x, &y, scr, &cx, &cy);
updateHistory(pDev, first_valuator, num_valuators, ms);
/* dropy x/y (device coordinates) back into valuators for next event */
pDev->last.valuators[0] = x;
pDev->last.valuators[1] = y;
/* Update the valuators with the true value sent to the client*/
if (num_valuators >= 1 && first_valuator == 0)
valuators[0] = x;
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator))
valuators[1 - first_valuator] = y;
kbp = (deviceKeyButtonPointer *) events->event;
kbp->time = ms;
kbp->deviceid = pDev->id;
if (type == MotionNotify) {
kbp->type = DeviceMotionNotify;
}
else {
if (type == ButtonPress)
kbp->type = DeviceButtonPress;
else if (type == ButtonRelease)
kbp->type = DeviceButtonRelease;
kbp->detail = buttons;
}
kbp->root_x = cx; /* root_x/y always in screen coords */
kbp->root_y = cy;
events++;
if (num_valuators) {
kbp->deviceid |= MORE_EVENTS;
if (flags & POINTER_ABSOLUTE)
clipValuators(pDev, first_valuator, num_valuators, valuators);
events = getValuatorEvents(events, pDev, first_valuator,
num_valuators, valuators);
}
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(EventList *events, DeviceIntPtr pDev, int type,
int first_valuator, int num_valuators, int *valuators)
{
int num_events = 1;
deviceKeyButtonPointer *kbp;
/* 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;
events = updateFromMaster(events, pDev, &num_events);
kbp = (deviceKeyButtonPointer *) events->event;
kbp->type = type;
kbp->deviceid = pDev->id;
kbp->detail = 0;
kbp->time = GetTimeInMillis();
if (num_valuators) {
kbp->deviceid |= MORE_EVENTS;
events++;
clipValuators(pDev, first_valuator, num_valuators, valuators);
events = getValuatorEvents(events, pDev, first_valuator,
num_valuators, valuators);
}
return num_events;
}
/**
* 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.
*/
Export symbols defined in the sdk. This is the biggest "visibility" patch. Instead of doing a "export" symbol on demand, export everything in the sdk, so that if some module fails due to an unresolved symbol, it is because it is using a symbol not in the sdk. Most exported symbols shouldn't really be made visible, neither advertised in the sdk, as they are only used by a single shared object. Symbols in the sdk (or referenced in sdk macros), but not defined anywhere include: XkbBuildCoreState() XkbInitialMap XkbXIUnsupported XkbCheckActionVMods() XkbSendCompatNotify() XkbDDXFakePointerButton() XkbDDXApplyConfig() _XkbStrCaseCmp() _XkbErrMessages[] _XkbErrCode _XkbErrLocation _XkbErrData XkbAccessXDetailText() XkbNKNDetailMaskText() XkbLookupGroupAndLevel() XkbInitAtoms() XkbGetOrderedDrawables() XkbFreeOrderedDrawables() XkbConvertXkbComponents() XkbWriteXKBSemantics() XkbWriteXKBLayout() XkbWriteXKBKeymap() XkbWriteXKBFile() XkbWriteCFile() XkbWriteXKMFile() XkbWriteToServer() XkbMergeFile() XkmFindTOCEntry() XkmReadFileSection() XkmReadFileSectionName() InitExtInput() xf86CheckButton() xf86SwitchCoreDevice() RamDacSetGamma() RamDacRestoreDACValues() xf86Bpp xf86ConfigPix24 xf86MouseCflags[] xf86SupportedMouseTypes[] xf86NumMouseTypes xf86ChangeBusIndex() xf86EntityEnter() xf86EntityLeave() xf86WrapperInit() xf86RingBell() xf86findOptionBoolean() xf86debugListOptions() LoadSubModuleLocal() LoaderSymbolLocal() getInt10Rec() xf86CurrentScreen xf86ReallocatePciResources() xf86NewSerialNumber() xf86RandRSetInitialMode() fbCompositeSolidMask_nx1xn fbCompositeSolidMask_nx8888x0565C fbCompositeSolidMask_nx8888x8888C fbCompositeSolidMask_nx8x0565 fbCompositeSolidMask_nx8x0888 fbCompositeSolidMask_nx8x8888 fbCompositeSrc_0565x0565 fbCompositeSrc_8888x0565 fbCompositeSrc_8888x0888 fbCompositeSrc_8888x8888 fbCompositeSrcAdd_1000x1000 fbCompositeSrcAdd_8000x8000 fbCompositeSrcAdd_8888x8888 fbGeneration fbIn fbOver fbOver24 fbOverlayGeneration fbRasterizeEdges fbRestoreAreas fbSaveAreas composeFunctions VBEBuildVbeModeList() VBECalcVbeModeIndex() TIramdac3030CalculateMNPForClock() shadowBufPtr shadowFindBuf() miRRGetScreenInfo() RRSetScreenConfig() RRModePruneUnused() PixmanImageFromPicture() extern int miPointerGetMotionEvents() miClipPicture() miRasterizeTriangle() fbPush1toN() fbInitializeBackingStore() ddxBeforeReset() SetupSprite() InitSprite() DGADeliverEvent() SPECIAL CASES o defined as _X_INTERNAL xf86NewInputDevice() o defined as static fbGCPrivateKey fbOverlayScreenPrivateKey fbScreenPrivateKey fbWinPrivateKey o defined in libXfont.so, but declared in xorg/dixfont.h GetGlyphs() QueryGlyphExtents() QueryTextExtents() ParseGlyphCachingMode() InitGlyphCaching() SetGlyphCachingMode()
2008-11-30 02:56:06 +01:00
_X_EXPORT void
PostSyntheticMotion(DeviceIntPtr pDev,
int x,
int y,
int screen,
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[screen].x;
y += panoramiXdataPtr[0].y - panoramiXdataPtr[screen].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;
(*pDev->public.processInputProc)(&xE, pDev, 1);
}