Xext: use GPE/GKE from XTestFakeInput #16145

This commit fixes two problems:
1) XTFI used to assemble the event itself, then passed it to the device. It's
much easier to just pass the variables into GPE/GKE and let the DIX do the
rest.

2) XTFI would pass the VCP/VCK as default device to event processing. As a
result, updating LEDs would be updated on the VCK, not on the actual keyboard.
Instead, we now pass the events through the last-used SD, thus toggling the
LEDs on the last keyboard that sent through this MD.

Also some cleanup in XTFI to merge validity checks a bit closer together
rather than having several different sections.

This breaks XTestFakeMotion with Xinerama though.

X.Org Bug 16145 <http://bugs.freedesktop.org/show_bug.cgi?id=16145>
This commit is contained in:
Peter Hutterer 2008-05-30 15:20:35 +09:30
parent 341a61b608
commit 105d28652d

View File

@ -42,6 +42,7 @@
#include "scrnintstr.h" #include "scrnintstr.h"
#include "dixevents.h" #include "dixevents.h"
#include "sleepuntil.h" #include "sleepuntil.h"
#include "mi.h"
#define _XTEST_SERVER_ #define _XTEST_SERVER_
#include <X11/extensions/XTest.h> #include <X11/extensions/XTest.h>
#include <X11/extensions/xteststr.h> #include <X11/extensions/xteststr.h>
@ -164,8 +165,13 @@ ProcXTestFakeInput(client)
WindowPtr root; WindowPtr root;
Bool extension = FALSE; Bool extension = FALSE;
deviceValuator *dv = NULL; deviceValuator *dv = NULL;
int base; int valuators[MAX_VALUATORS] = {0};
int *values; int numValuators = 0;
int firstValuator;
EventListPtr events;
int nevents;
int i;
int base = 0;
nev = (stuff->length << 2) - sizeof(xReq); nev = (stuff->length << 2) - sizeof(xReq);
if ((nev % sizeof(xEvent)) || !nev) if ((nev % sizeof(xEvent)) || !nev)
@ -177,6 +183,18 @@ ProcXTestFakeInput(client)
if (type >= EXTENSION_EVENT_BASE) if (type >= EXTENSION_EVENT_BASE)
{ {
extension = TRUE;
/* check device */
rc = dixLookupDevice(&dev, stuff->deviceid & 0177, client,
DixWriteAccess);
if (rc != Success)
{
client->errorValue = stuff->deviceid & 0177;
return rc;
}
/* check type */
type -= DeviceValuator; type -= DeviceValuator;
switch (type) { switch (type) {
case XI_DeviceKeyPress: case XI_DeviceKeyPress:
@ -191,12 +209,31 @@ ProcXTestFakeInput(client)
client->errorValue = ev->u.u.type; client->errorValue = ev->u.u.type;
return BadValue; return BadValue;
} }
/* check validity */
if (nev == 1 && type == XI_DeviceMotionNotify) if (nev == 1 && type == XI_DeviceMotionNotify)
return BadLength; /* DevMotion must be followed by DevValuator */ return BadLength; /* DevMotion must be followed by DevValuator */
if (type == XI_DeviceMotionNotify) if (type == XI_DeviceMotionNotify)
base = ((deviceValuator *)(ev+1))->first_valuator; {
else firstValuator = ((deviceValuator *)(ev+1))->first_valuator;
base = 0; if (firstValuator > dev->valuator->numAxes)
{
client->errorValue = ev->u.u.type;
return BadValue;
}
} else
firstValuator = 0;
if (nev == 1 && type == XI_DeviceMotionNotify && !dev->valuator)
{
client->errorValue = dv->first_valuator;
return BadValue;
}
/* check validity of valuator events */
base = firstValuator;
for (n = 1; n < nev; n++) for (n = 1; n < nev; n++)
{ {
dv = (deviceValuator *)(ev + n); dv = (deviceValuator *)(ev + n);
@ -210,17 +247,32 @@ ProcXTestFakeInput(client)
client->errorValue = dv->first_valuator; client->errorValue = dv->first_valuator;
return BadValue; return BadValue;
} }
if (!dv->num_valuators || dv->num_valuators > 6) switch(dv->num_valuators)
{
case 6: valuators[base + 5] = dv->valuator5;
case 5: valuators[base + 4] = dv->valuator4;
case 4: valuators[base + 3] = dv->valuator3;
case 3: valuators[base + 2] = dv->valuator2;
case 2: valuators[base + 1] = dv->valuator1;
case 1: valuators[base] = dv->valuator0;
break;
default:
client->errorValue = dv->num_valuators;
return BadValue;
}
base += dv->num_valuators;
numValuators += dv->num_valuators;
if (firstValuator + numValuators > dev->valuator->numAxes)
{ {
client->errorValue = dv->num_valuators; client->errorValue = dv->num_valuators;
return BadValue; return BadValue;
} }
base += dv->num_valuators;
} }
type = type - XI_DeviceKeyPress + KeyPress; type = type - XI_DeviceKeyPress + KeyPress;
extension = TRUE;
} } else
else
{ {
if (nev != 1) if (nev != 1)
return BadLength; return BadLength;
@ -228,34 +280,26 @@ ProcXTestFakeInput(client)
{ {
case KeyPress: case KeyPress:
case KeyRelease: case KeyRelease:
case MotionNotify: dev = PickKeyboard(client);
break;
case ButtonPress: case ButtonPress:
case ButtonRelease: case ButtonRelease:
dev = PickPointer(client);
break;
case MotionNotify:
dev = PickPointer(client);
valuators[0] = ev->u.keyButtonPointer.rootX;
valuators[1] = ev->u.keyButtonPointer.rootY;
numValuators = 2;
firstValuator = 0;
break; break;
default: default:
client->errorValue = ev->u.u.type; client->errorValue = ev->u.u.type;
return BadValue; return BadValue;
} }
ev->u.u.type += (DeviceValuator - 1); if (dev->u.lastSlave)
if (ev->u.u.type == DeviceMotionNotify) dev = dev->u.lastSlave;
{
/* fake up valuator */
xEvent *ne = xalloc(2 * sizeof(xEvent));
if (ne) {
memcpy(ne, ev, sizeof(xEvent));
memcpy(&ne[1], ev, sizeof(xEvent));
ev = ne;
dv = (deviceValuator*)(ne + 1);
dv->type = DeviceValuator;
dv->first_valuator = 0;
dv->num_valuators = 2;
dv->valuator0 = ev->u.keyButtonPointer.rootX;
dv->valuator1 = ev->u.keyButtonPointer.rootY;
nev = 2;
}
}
} }
/* If the event has a time set, wait for it to pass */ /* If the event has a time set, wait for it to pass */
@ -288,37 +332,10 @@ ProcXTestFakeInput(client)
return Success; return Success;
} }
if (extension)
{
rc = dixLookupDevice(&dev, stuff->deviceid & 0177, client,
DixWriteAccess);
if (rc != Success)
{
client->errorValue = stuff->deviceid & 0177;
return rc;
}
if (nev > 1)
{
dv = (deviceValuator *)(ev + 1);
if (!dev->valuator || dv->first_valuator >= dev->valuator->numAxes)
{
client->errorValue = dv->first_valuator;
return BadValue;
}
if (dv->first_valuator + dv->num_valuators >
dev->valuator->numAxes)
{
client->errorValue = dv->num_valuators;
return BadValue;
}
}
}
switch (type) switch (type)
{ {
case KeyPress: case KeyPress:
case KeyRelease: case KeyRelease:
if (!extension)
dev = PickKeyboard(client);
if (ev->u.u.detail < dev->key->curKeySyms.minKeyCode || if (ev->u.u.detail < dev->key->curKeySyms.minKeyCode ||
ev->u.u.detail > dev->key->curKeySyms.maxKeyCode) ev->u.u.detail > dev->key->curKeySyms.maxKeyCode)
{ {
@ -327,66 +344,13 @@ ProcXTestFakeInput(client)
} }
break; break;
case MotionNotify: case MotionNotify:
if (extension) /* broken lib, XI events have root uninitialized */
{ if (extension || ev->u.keyButtonPointer.root == None)
if (ev->u.u.detail != xFalse && ev->u.u.detail != xTrue)
{
client->errorValue = ev->u.u.detail;
return BadValue;
}
/* detail is True for relative coordinates */
if (ev->u.u.detail == xTrue && dev->valuator->mode == Absolute)
{
values = dev->valuator->axisVal + dv->first_valuator;
for (n = 1; n < nev; n++)
{
dv = (deviceValuator *)(ev + n);
switch (dv->num_valuators)
{
case 6:
dv->valuator5 += values[5];
case 5:
dv->valuator4 += values[4];
case 4:
dv->valuator3 += values[3];
case 3:
dv->valuator2 += values[2];
case 2:
dv->valuator1 += values[1];
case 1:
dv->valuator0 += values[0];
}
values += 6;
}
}
/* For XI events, the actual event is mostly unset. Since we
* want to update the sprite nontheless, we need to fake up
* sane values for the event. */
ev->u.keyButtonPointer.root = None;
dv = (deviceValuator*)(ev + 1);
if (dv->num_valuators && dv->first_valuator == 0)
ev->u.keyButtonPointer.rootX = dv->valuator0;
else
ev->u.keyButtonPointer.rootX = 0;
/* XXX: AFAIK, XI requires always sending _all_ valuators,
* i.e. you can't just send vals 3 - 7. (whot) */
if (dv->num_valuators > 1 && dv->first_valuator == 0)
ev->u.keyButtonPointer.rootY = dv->valuator1;
else
ev->u.keyButtonPointer.rootY = 0;
}
if (!dev)
dev = PickPointer(client);
if (ev->u.keyButtonPointer.root == None)
root = GetCurrentRootWindow(dev); root = GetCurrentRootWindow(dev);
else else
{ {
rc = dixLookupWindow(&root, ev->u.keyButtonPointer.root, client, rc = dixLookupWindow(&root, ev->u.keyButtonPointer.root,
DixGetAttrAccess); client, DixGetAttrAccess);
if (rc != Success) if (rc != Success)
return rc; return rc;
if (root->parent) if (root->parent)
@ -395,91 +359,23 @@ ProcXTestFakeInput(client)
return BadValue; return BadValue;
} }
} }
if (ev->u.u.detail == xTrue) if (ev->u.u.detail != xTrue && ev->u.u.detail != xFalse)
{
int x, y;
if (!extension || !dev->valuator->mode == Absolute)
{
/* if Absolute, rootX already has the final coords. */
GetSpritePosition(dev, &x, &y);
ev->u.keyButtonPointer.rootX += x;
ev->u.keyButtonPointer.rootY += y;
}
}
else if (ev->u.u.detail != xFalse)
{ {
client->errorValue = ev->u.u.detail; client->errorValue = ev->u.u.detail;
return BadValue; return BadValue;
} }
#ifdef PANORAMIX /* FIXME: Xinerama! */
if (!noPanoramiXExtension) {
ScreenPtr pScreen = root->drawable.pScreen;
BoxRec box;
int i;
int x = ev->u.keyButtonPointer.rootX + panoramiXdataPtr[0].x;
int y = ev->u.keyButtonPointer.rootY + panoramiXdataPtr[0].y;
if (!POINT_IN_REGION(pScreen, &XineramaScreenRegions[pScreen->myNum],
x, y, &box)) {
FOR_NSCREENS(i) {
if (i == pScreen->myNum) continue;
if (POINT_IN_REGION(pScreen,
&XineramaScreenRegions[i],
x, y, &box)) {
root = WindowTable[i];
x -= panoramiXdataPtr[i].x;
y -= panoramiXdataPtr[i].y;
ev->u.keyButtonPointer.rootX = x;
ev->u.keyButtonPointer.rootY = y;
break;
}
}
}
}
#endif
if (ev->u.keyButtonPointer.rootX < 0)
ev->u.keyButtonPointer.rootX = 0;
else if (ev->u.keyButtonPointer.rootX >= root->drawable.width)
ev->u.keyButtonPointer.rootX = root->drawable.width - 1;
if (ev->u.keyButtonPointer.rootY < 0)
ev->u.keyButtonPointer.rootY = 0;
else if (ev->u.keyButtonPointer.rootY >= root->drawable.height)
ev->u.keyButtonPointer.rootY = root->drawable.height - 1;
#ifdef PANORAMIX
if ((!noPanoramiXExtension
&& root->drawable.pScreen->myNum
!= XineramaGetCursorScreen(dev))
|| (noPanoramiXExtension && root != GetCurrentRootWindow(dev)))
#else
if (root != GetCurrentRootWindow(dev))
#endif
{
NewCurrentScreen(dev, root->drawable.pScreen,
ev->u.keyButtonPointer.rootX,
ev->u.keyButtonPointer.rootY);
return client->noClientException;
}
/* Only update sprite for MDs and floating SDs */
if (dev->isMaster || (!dev->isMaster && !dev->u.master))
{
(*root->drawable.pScreen->SetCursorPosition)
(dev, root->drawable.pScreen,
ev->u.keyButtonPointer.rootX,
ev->u.keyButtonPointer.rootY, FALSE);
}
dev->last.valuators[0] = ev->u.keyButtonPointer.rootX;
dev->last.valuators[1] = ev->u.keyButtonPointer.rootY;
break; break;
case ButtonPress: case ButtonPress:
case ButtonRelease: case ButtonRelease:
if (!extension) if (!extension)
{
dev = PickPointer(client); dev = PickPointer(client);
if (dev->u.lastSlave)
ev->u.keyButtonPointer.rootX = dev->last.valuators[0]; dev = dev->u.lastSlave;
ev->u.keyButtonPointer.rootY = dev->last.valuators[1]; }
if (!ev->u.u.detail || ev->u.u.detail > dev->button->numButtons) if (!ev->u.u.detail || ev->u.u.detail > dev->button->numButtons)
{ {
client->errorValue = ev->u.u.detail; client->errorValue = ev->u.u.detail;
@ -489,19 +385,31 @@ ProcXTestFakeInput(client)
} }
if (screenIsSaved == SCREEN_SAVER_ON) if (screenIsSaved == SCREEN_SAVER_ON)
dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
ev->u.keyButtonPointer.time = currentTime.milliseconds;
if (!dev->isMaster && dev->u.master) GetEventList(&events);
{ /* duplicate and route through master */ switch(type) {
xEvent *master_event = NULL; case MotionNotify:
CopyGetMasterEvent(dev->u.master, ev, &master_event, nev); nevents = GetPointerEvents(events, dev, type, 0,
(*dev->public.processInputProc)(ev, dev, nev); (ev->u.u.detail == xFalse) ? POINTER_ABSOLUTE : 0,
(*dev->public.processInputProc)(master_event, dev->u.master, nev); firstValuator, numValuators, valuators);
xfree(master_event); break;
} else case ButtonPress:
(*dev->public.processInputProc)(ev, dev, nev); case ButtonRelease:
if (!extension && type == MotionNotify) nevents = GetPointerEvents(events, dev, type, ev->u.u.detail,
xfree(ev); POINTER_ABSOLUTE, firstValuator,
numValuators, valuators);
break;
case KeyPress:
case KeyRelease:
nevents = GetKeyboardEvents(events, dev, type, ev->u.u.detail);
break;
}
OsBlockSignals();
for (i = 0; i < nevents; i++)
mieqEnqueue(dev, events->event);
OsReleaseSignals();
return client->noClientException; return client->noClientException;
} }