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:
parent
341a61b608
commit
105d28652d
308
Xext/xtest.c
308
Xext/xtest.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue