Add initial support of back-end XInput extension.

This commit is contained in:
David Reveman 2008-07-20 23:17:09 -04:00
parent 96322ebffc
commit 442a1cce7a
5 changed files with 298 additions and 91 deletions

View file

@ -47,6 +47,8 @@
#ifndef DMXINPUT_H
#define DMXINPUT_H
#define DMX_XINPUT_EVENT_NUM 18
/** Maximum number of file descriptors for SIGIO handling */
#define DMX_MAX_SIGIO_FDS 4
@ -129,6 +131,8 @@ struct _DMXInputInfo {
char *geometry; /**< XKB geometry from command line */
int k, m, o;
int event[DMX_XINPUT_EVENT_NUM];
};
extern int dmxNumInputs; /**< Number of #dmxInputs */

View file

@ -160,20 +160,107 @@ static int dmxBackendSameDisplay(myPrivate *priv, long screen)
return retcode;
}
typedef struct _TestEventData {
DMXInputInfo *dmxInput;
XEvent *X;
long deviceId;
} TestEventData;
static Bool inputEventPredicate (Display *xdisplay,
XEvent *X,
XPointer arg)
{
TestEventData *data = (TestEventData *) arg;
int i;
switch (X->type) {
case MotionNotify:
case ButtonPress:
case ButtonRelease:
case KeyPress:
case KeyRelease:
case KeymapNotify:
data->deviceId = -1;
*(data->X) = *X;
return TRUE;
default:
for (i = 0; i < DMX_XINPUT_EVENT_NUM; i++)
{
if (data->dmxInput->event[i] == X->type)
{
switch (i) {
case XI_DeviceMotionNotify: {
XDeviceMotionEvent *dmev = (XDeviceMotionEvent *) X;
XMotionEvent *mev = (XMotionEvent *) data->X;
mev->type = MotionNotify;
mev->x = dmev->x;
mev->y = dmev->y;
mev->state = dmev->state;
} break;
case XI_DeviceButtonPress: {
XDeviceButtonEvent *dbev = (XDeviceButtonEvent *) X;
XButtonEvent *bev = (XButtonEvent *) data->X;
bev->type = ButtonPress;
bev->button = dbev->button;
bev->x = dbev->x;
bev->y = dbev->y;
bev->state = dbev->state;
} break;
case XI_DeviceButtonRelease: {
XDeviceButtonEvent *dbev = (XDeviceButtonEvent *) X;
XButtonEvent *bev = (XButtonEvent *) data->X;
bev->type = ButtonRelease;
bev->button = dbev->button;
bev->x = dbev->x;
bev->y = dbev->y;
bev->state = dbev->state;
} break;
case XI_DeviceKeyPress: {
XDeviceKeyEvent *dkev = (XDeviceKeyEvent *) X;
XKeyEvent *kev = (XKeyEvent *) data->X;
kev->type = KeyPress;
kev->keycode = dkev->keycode;
kev->x = dkev->x;
kev->y = dkev->y;
kev->state = dkev->state;
} break;
case XI_DeviceKeyRelease: {
XDeviceKeyEvent *dkev = (XDeviceKeyEvent *) X;
XKeyEvent *kev = (XKeyEvent *) data->X;
kev->type = KeyRelease;
kev->keycode = dkev->keycode;
kev->x = dkev->x;
kev->y = dkev->y;
kev->state = dkev->state;
} break;
default:
*(data->X) = *X;
}
data->deviceId = ((XDeviceStateNotifyEvent *) X)->deviceid;
return TRUE;
}
}
}
return FALSE;
}
static void *dmxBackendTestEvents(DMXScreenInfo *dmxScreen, void *closure)
{
XEvent *X = (XEvent *)closure;
int result = 0;
XEvent X;
int result = 0;
XLIB_PROLOGUE (dmxScreen);
result = XCheckMaskEvent(dmxScreen->beDisplay,
KeyPressMask |
KeyReleaseMask |
KeymapStateMask |
ButtonPressMask |
ButtonReleaseMask |
PointerMotionMask,
X);
result = XCheckIfEvent (dmxScreen->beDisplay,
&X,
inputEventPredicate,
closure);
XLIB_EPILOGUE (dmxScreen);
return (result) ? dmxScreen : NULL;
}
@ -210,41 +297,49 @@ void dmxBackendUpdatePosition(pointer private, int x, int y)
}
static DeviceIntPtr
dmxGetButtonDevice (DMXInputInfo *dmxInput)
dmxGetButtonDevice (DMXInputInfo *dmxInput,
XID deviceId)
{
int i;
for (i = 0; i < dmxInput->numDevs; i++)
if (dmxInput->devs[i]->pDevice->button)
return dmxInput->devs[i]->pDevice;
if (deviceId < 0 || dmxInput->devs[i]->deviceId == deviceId)
return dmxInput->devs[i]->pDevice;
return NULL;
}
static DeviceIntPtr
dmxGetPairedButtonDevice (DMXInputInfo *dmxInput,
DeviceIntPtr pOther)
DeviceIntPtr pDevice)
{
return dmxGetButtonDevice (dmxInput);
GETDMXLOCALFROMPDEVICE;
return dmxGetButtonDevice (dmxInput, dmxLocal->attached);
}
static DeviceIntPtr
dmxGetKeyboardDevice (DMXInputInfo *dmxInput)
dmxGetKeyboardDevice (DMXInputInfo *dmxInput,
XID deviceId)
{
int i;
for (i = 0; i < dmxInput->numDevs; i++)
if (dmxInput->devs[i]->pDevice->key)
return dmxInput->devs[i]->pDevice;
if (deviceId < 0 || dmxInput->devs[i]->deviceId == deviceId)
return dmxInput->devs[i]->pDevice;
return NULL;
}
static DeviceIntPtr
dmxGetPairedKeyboardDevice (DMXInputInfo *dmxInput,
DeviceIntPtr pOther)
DeviceIntPtr pDevice)
{
return dmxGetKeyboardDevice (dmxInput);
GETDMXLOCALFROMPDEVICE;
return dmxGetKeyboardDevice (dmxInput, dmxLocal->attached);
}
static int
@ -455,15 +550,13 @@ void dmxBackendCollectEvents(DevicePtr pDev,
XEvent X;
DMXScreenInfo *dmxScreen;
DeviceIntPtr pButtonDev, pKeyDev;
TestEventData data = { dmxInput, &X };
while ((dmxScreen = dmxBackendGetEvent(priv, &X)))
while ((dmxScreen = dmxBackendGetEvent(priv, (void *) &data)))
{
if (X.xany.send_event)
continue;
switch (X.type) {
case MotionNotify:
pButtonDev = dmxGetButtonDevice (dmxInput);
pButtonDev = dmxGetButtonDevice (dmxInput, data.deviceId);
if (pButtonDev)
{
pKeyDev = dmxGetPairedKeyboardDevice (dmxInput, pButtonDev);
@ -476,7 +569,7 @@ void dmxBackendCollectEvents(DevicePtr pDev,
break;
case ButtonPress:
case ButtonRelease:
pButtonDev = dmxGetButtonDevice (dmxInput);
pButtonDev = dmxGetButtonDevice (dmxInput, data.deviceId);
if (pButtonDev)
{
dmxUpdateSpritePosition (pButtonDev, X.xbutton.x, X.xbutton.y);
@ -494,7 +587,7 @@ void dmxBackendCollectEvents(DevicePtr pDev,
break;
case KeyPress:
case KeyRelease:
pKeyDev = dmxGetKeyboardDevice (dmxInput);
pKeyDev = dmxGetKeyboardDevice (dmxInput, data.deviceId);
if (pKeyDev)
{
pButtonDev = dmxGetPairedButtonDevice (dmxInput, pKeyDev);
@ -509,6 +602,8 @@ void dmxBackendCollectEvents(DevicePtr pDev,
X.xkey.keycode,
X.type);
}
break;
case KeymapNotify:
default:
break;
}

View file

@ -290,12 +290,44 @@ void dmxCommonKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
int dmxCommonKbdOn(DevicePtr pDev)
{
GETPRIVFROMPDEV;
GETDMXINPUTFROMPRIV;
if (priv->be) dmxCommonSaveState(priv);
priv->eventMask |= DMX_KEYBOARD_EVENT_MASK;
XSelectInput(priv->display, priv->window, priv->eventMask);
if (priv->be)
XSetInputFocus(priv->display, priv->window, RevertToPointerRoot,
CurrentTime);
if (priv->be && dmxLocal->deviceId >= 0)
{
XEventClass cls[2];
if (!(priv->xi = XOpenDevice (priv->display, dmxLocal->deviceId))) {
dmxLog(dmxWarning, "Cannot open %s device (id=%d) on %s\n",
dmxLocal->deviceName ? dmxLocal->deviceName : "(unknown)",
dmxLocal->deviceId, dmxInput->name);
return -1;
}
DeviceKeyPress (priv->xi, dmxInput->event[XI_DeviceKeyPress], cls[0]);
DeviceKeyRelease (priv->xi, dmxInput->event[XI_DeviceKeyRelease],
cls[1]);
XLIB_PROLOGUE (priv->be);
XSelectExtensionEvent(priv->display, priv->window, cls, 2);
XLIB_EPILOGUE (priv->be);
XLIB_PROLOGUE (priv->be);
XSetInputFocus(priv->display, priv->window, RevertToPointerRoot,
CurrentTime);
XLIB_EPILOGUE (priv->be);
}
else
{
priv->eventMask |= DMX_KEYBOARD_EVENT_MASK;
XSelectInput(priv->display, priv->window, priv->eventMask);
if (priv->be)
{
XLIB_PROLOGUE (priv->be);
XSetInputFocus(priv->display, priv->window, RevertToPointerRoot,
CurrentTime);
XLIB_EPILOGUE (priv->be);
}
}
return -1;
}
@ -303,8 +335,16 @@ int dmxCommonKbdOn(DevicePtr pDev)
void dmxCommonKbdOff(DevicePtr pDev)
{
GETPRIVFROMPDEV;
priv->eventMask &= ~DMX_KEYBOARD_EVENT_MASK;
XSelectInput(priv->display, priv->window, priv->eventMask);
if (priv->xi)
{
XCloseDevice(priv->display, priv->xi);
priv->xi = NULL;
}
else
{
priv->eventMask &= ~DMX_KEYBOARD_EVENT_MASK;
XSelectInput(priv->display, priv->window, priv->eventMask);
}
dmxCommonRestoreState(priv);
}
@ -380,7 +420,7 @@ void dmxCommonOthGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
/* Print out information about the XInput Extension. */
handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler);
ext = XGetExtensionVersion(display, INAME);
ext = XQueryInputVersion(display, XI_2_Major, XI_2_Minor);
XSetExtensionErrorHandler(handler);
if (ext && ext != (XExtensionVersion *)NoSuchExtension) {
@ -486,24 +526,48 @@ int dmxCommonMouOn(DevicePtr pDev)
GETPRIVFROMPDEV;
GETDMXINPUTFROMPRIV;
priv->eventMask |= DMX_POINTER_EVENT_MASK;
if (dmxShadowFB) {
XLIB_PROLOGUE (&dmxScreens[dmxInput->scrnIdx]);
XWarpPointer(priv->display, priv->window, priv->window,
0, 0, 0, 0,
priv->initPointerX,
priv->initPointerY);
XLIB_EPILOGUE (&dmxScreens[dmxInput->scrnIdx]);
dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE);
if (priv->be && dmxLocal->deviceId >= 0)
{
XEventClass cls[3];
if (!(priv->xi = XOpenDevice (priv->display, dmxLocal->deviceId))) {
dmxLog(dmxWarning, "Cannot open %s device (id=%d) on %s\n",
dmxLocal->deviceName ? dmxLocal->deviceName : "(unknown)",
dmxLocal->deviceId, dmxInput->name);
return -1;
}
DeviceMotionNotify (priv->xi, dmxInput->event[XI_DeviceMotionNotify],
cls[0]);
DeviceButtonPress (priv->xi, dmxInput->event[XI_DeviceButtonPress],
cls[1]);
DeviceButtonRelease (priv->xi, dmxInput->event[XI_DeviceButtonRelease],
cls[2]);
XLIB_PROLOGUE (priv->be);
XSelectExtensionEvent(priv->display, priv->window, cls, 3);
XLIB_EPILOGUE (priv->be);
}
if (!priv->be) {
XLIB_PROLOGUE (&dmxScreens[dmxInput->scrnIdx]);
XSelectInput(priv->display, priv->window, priv->eventMask);
XLIB_EPILOGUE (&dmxScreens[dmxInput->scrnIdx]);
AddEnabledDevice(XConnectionNumber(priv->display));
} else {
dmxPropertyIterate(priv->be, dmxCommonXSelect, priv);
dmxPropertyIterate(priv->be, dmxCommonAddEnabledDevice, dmxInput);
else
{
priv->eventMask |= DMX_POINTER_EVENT_MASK;
if (dmxShadowFB) {
XLIB_PROLOGUE (&dmxScreens[dmxInput->scrnIdx]);
XWarpPointer(priv->display, priv->window, priv->window,
0, 0, 0, 0,
priv->initPointerX,
priv->initPointerY);
XLIB_EPILOGUE (&dmxScreens[dmxInput->scrnIdx]);
dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE);
}
if (!priv->be) {
XLIB_PROLOGUE (&dmxScreens[dmxInput->scrnIdx]);
XSelectInput(priv->display, priv->window, priv->eventMask);
XLIB_EPILOGUE (&dmxScreens[dmxInput->scrnIdx]);
AddEnabledDevice(XConnectionNumber(priv->display));
} else {
dmxPropertyIterate(priv->be, dmxCommonXSelect, priv);
}
}
return -1;
@ -514,16 +578,23 @@ void dmxCommonMouOff(DevicePtr pDev)
{
GETPRIVFROMPDEV;
GETDMXINPUTFROMPRIV;
priv->eventMask &= ~DMX_POINTER_EVENT_MASK;
if (!priv->be) {
RemoveEnabledDevice(XConnectionNumber(priv->display));
XLIB_PROLOGUE (&dmxScreens[dmxInput->scrnIdx]);
XSelectInput(priv->display, priv->window, priv->eventMask);
XLIB_EPILOGUE (&dmxScreens[dmxInput->scrnIdx]);
} else {
dmxPropertyIterate(priv->be, dmxCommonRemoveEnabledDevice, dmxInput);
dmxPropertyIterate(priv->be, dmxCommonXSelect, priv);
if (priv->xi)
{
XCloseDevice(priv->display, priv->xi);
priv->xi = NULL;
}
else
{
priv->eventMask &= ~DMX_POINTER_EVENT_MASK;
if (!priv->be) {
RemoveEnabledDevice(XConnectionNumber(priv->display));
XLIB_PROLOGUE (&dmxScreens[dmxInput->scrnIdx]);
XSelectInput(priv->display, priv->window, priv->eventMask);
XLIB_EPILOGUE (&dmxScreens[dmxInput->scrnIdx]);
} else {
dmxPropertyIterate(priv->be, dmxCommonXSelect, priv);
}
}
}

View file

@ -690,6 +690,17 @@ static char *dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal)
DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
char *buf;
if (dmxLocal->deviceName)
{
buf = xalloc (strlen (dmxInput->name) +
strlen (dmxLocal->deviceName) + 4);
if (buf)
{
sprintf (buf, "%s's %s", dmxInput->name, dmxLocal->deviceName);
return buf;
}
}
#define LEN 32
buf = xalloc (strlen (dmxInput->name) + LEN);
@ -788,6 +799,7 @@ DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput,
dmxLocal->sendsCore = dmxInput->core;
dmxLocal->savedSendsCore = dmxInput->core;
dmxLocal->deviceId = -1;
dmxLocal->attached = -1;
++dmxInput->numDevs;
dmxInput->devs = xrealloc(dmxInput->devs,
@ -834,6 +846,20 @@ int dmxInputExtensionErrorHandler(Display *dsp, char *name, char *reason)
return 0;
}
static XID dmxGetMasterDevice(XDeviceInfo *device)
{
XAttachInfoPtr ai;
int i;
for (i = 0, ai = device->inputclassinfo;
i < device->num_classes;
ai = (XAttachInfoPtr) ((char *) ai + ai->length), i++)
if (ai->class == AttachClass)
return ai->attached;
return -1;
}
static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI)
{
XExtensionVersion *ext;
@ -844,7 +870,7 @@ static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI)
DMXLocalInputInfoPtr dmxLocal;
int (*handler)(Display *, char *, char *);
if (!(display = XOpenDisplay(dmxInput->name))) return;
display = dmxScreens[dmxInput->scrnIdx].beDisplay;
/* Print out information about the XInput Extension. */
handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler);
@ -890,8 +916,23 @@ static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI)
dmxL->deviceName = (devices[i].name
? xstrdup(devices[i].name)
: NULL);
dmxL->attached = dmxGetMasterDevice (&devices[i]);
break;
}
}
if (j == dmxInput->numDevs)
{
dmxLocal = dmxInputCopyLocal(dmxInput,
&DMXBackendKbd);
dmxLocal->isCore = FALSE;
dmxLocal->sendsCore = FALSE;
dmxLocal->deviceId = devices[i].id;
dmxLocal->deviceName = (devices[i].name
? xstrdup(devices[i].name)
: NULL);
dmxLocal->attached = dmxGetMasterDevice (&devices[i]);
}
break;
case IsXPointer:
for (j = 0; j < dmxInput->numDevs; j++) {
@ -901,37 +942,28 @@ static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI)
dmxL->deviceName = (devices[i].name
? xstrdup(devices[i].name)
: NULL);
dmxL->attached = dmxGetMasterDevice (&devices[i]);
break;
}
}
if (j == dmxInput->numDevs)
{
dmxLocal = dmxInputCopyLocal(dmxInput,
&DMXBackendMou);
dmxLocal->isCore = FALSE;
dmxLocal->sendsCore = FALSE;
dmxLocal->deviceId = devices[i].id;
dmxLocal->deviceName = (devices[i].name
? xstrdup(devices[i].name)
: NULL);
dmxLocal->attached = dmxGetMasterDevice (&devices[i]);
}
break;
#if 0
case IsXExtensionDevice:
case IsXExtensionKeyboard:
case IsXExtensionPointer:
if (doXI) {
if (!dmxInput->numDevs) {
dmxLog(dmxWarning,
"Cannot use remote (%s) XInput devices if"
" not also using core devices\n",
dmxInput->name);
} else {
dmxLocal = dmxInputCopyLocal(dmxInput,
&DMXCommonOth);
dmxLocal->isCore = FALSE;
dmxLocal->sendsCore = FALSE;
dmxLocal->deviceId = devices[i].id;
dmxLocal->deviceName = (devices[i].name
? xstrdup(devices[i].name)
: NULL);
}
}
break;
#endif
}
}
}
XFreeDeviceList(devices);
}
XCloseDisplay(display);
}
/** Re-initialize all the devices described in \a dmxInput. Called from
@ -971,6 +1003,8 @@ void dmxInputInit(DMXInputInfo *dmxInput)
int doWindows = 1; /* On by default */
int hasXkb = 0;
memset (dmxInput->event, 0, sizeof (dmxInput->event));
dmxInput->k = dmxInput->m = dmxInput->o = 0;
a = dmxArgParse(dmxInput->name);
@ -1019,14 +1053,13 @@ void dmxInputInit(DMXInputInfo *dmxInput)
if ((dmxInput->scrnIdx != -1 && dmxInput->scrnIdx == i) ||
dmxPropertySameDisplay(&dmxScreens[i], name)) {
if (dmxScreens[i].shared)
{
dmxLog(dmxFatal,
"Cannot take input from shared backend (%s)\n",
name);
if (0 && !dmxInput->core) {
dmxLog(dmxWarning,
"Cannot use core devices on a backend (%s)"
" as XInput devices\n", name);
} else {
}
else
{
char *pt;
for (pt = (char *)dmxInput->name; pt && *pt; pt++)
if (*pt == ',') *pt = '\0';
@ -1163,6 +1196,8 @@ void dmxInputLogDevices(void)
dmxInput->inputIdx, len, len, dmxInput->name);
if (dmxInput->devs[i]->deviceId >= 0)
dmxLogCont(dmxInfo, "/id%d", dmxInput->devs[i]->deviceId);
if (dmxInput->devs[i]->attached >= 0)
dmxLogCont(dmxInfo, "/a%d", dmxInput->devs[i]->attached);
if (dmxInput->devs[i]->deviceName)
dmxLogCont(dmxInfo, "=%s", dmxInput->devs[i]->deviceName);
dmxLogCont(dmxInfo, "] %s\n",

View file

@ -265,6 +265,8 @@ typedef struct _DMXLocalInputInfo {
* if any */
const char *deviceName; /**< devive name on remote
* side, if any */
long attached; /**< the master device this device
* is attached to */
unsigned int state; /**< Modifier/Button state */