Xi: When switching MD classes, make a deep copy instead of pointer flip.
Turns out it's really really hard synchronising device state across multiple duplicated events if they all share the same struct. So instead of doing so, when the SD changes deep-copy all it's classes into the MD. The MD then has the same capabilities, but the state can be set separately. This should fix xkb, key state, repeat etc. problems. Updating the device state allows us to remove the SwitchCoreKeyboard from the event gathering, it's all done during event processing now.
This commit is contained in:
parent
cc4586df60
commit
64711a0948
214
Xi/exevents.c
214
Xi/exevents.c
|
@ -76,7 +76,9 @@ SOFTWARE.
|
||||||
#include "listdev.h" /* for CopySwapXXXClass */
|
#include "listdev.h" /* for CopySwapXXXClass */
|
||||||
|
|
||||||
#ifdef XKB
|
#ifdef XKB
|
||||||
|
#include <X11/extensions/XKBproto.h>
|
||||||
#include "xkbsrv.h"
|
#include "xkbsrv.h"
|
||||||
|
extern Bool XkbCopyKeymap(XkbDescPtr src, XkbDescPtr dst, Bool sendNotifies);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WID(w) ((w) ? ((w)->drawable.id) : 0)
|
#define WID(w) ((w) ? ((w)->drawable.id) : 0)
|
||||||
|
@ -102,6 +104,154 @@ RegisterOtherDevice(DeviceIntPtr device)
|
||||||
device->public.realInputProc = ProcessOtherEvent;
|
device->public.realInputProc = ProcessOtherEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the device->key into master->key and send a mapping notify to the
|
||||||
|
* clients if appropriate.
|
||||||
|
* master->key needs to be allocated by the caller.
|
||||||
|
*
|
||||||
|
* Device is the slave device. If it is attached to a master device, we may
|
||||||
|
* need to send a mapping notify to the client because it causes the MD
|
||||||
|
* to change state.
|
||||||
|
*
|
||||||
|
* Mapping notify needs to be sent in the following cases:
|
||||||
|
* - different slave device on same master
|
||||||
|
* - different master
|
||||||
|
*
|
||||||
|
* XXX: They way how the code is we also send a map notify if the slave device
|
||||||
|
* stays the same, but the master changes. This isn't really necessary though.
|
||||||
|
*
|
||||||
|
* XXX: this gives you funny behaviour with the ClientPointer. When a
|
||||||
|
* MappingNotify is sent to the client, the client usually responds with a
|
||||||
|
* GetKeyboardMapping. This will retrieve the ClientPointer's keyboard
|
||||||
|
* mapping, regardless of which keyboard sent the last mapping notify request.
|
||||||
|
* So depending on the CP setting, your keyboard may change layout in each
|
||||||
|
* app...
|
||||||
|
*
|
||||||
|
* This code is basically the old SwitchCoreKeyboard.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master)
|
||||||
|
{
|
||||||
|
static DeviceIntPtr lastMapNotifyDevice = NULL;
|
||||||
|
KeyClassPtr mk, dk; /* master, device */
|
||||||
|
BOOL sendNotify = FALSE;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (device == master)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dk = device->key;
|
||||||
|
mk = master->key;
|
||||||
|
|
||||||
|
if (master->devPrivates[CoreDevicePrivatesIndex].ptr != device) {
|
||||||
|
memcpy(mk->modifierMap, dk->modifierMap, MAP_LENGTH);
|
||||||
|
|
||||||
|
mk->modifierKeyMap = xcalloc(8, dk->maxKeysPerModifier);
|
||||||
|
if (!mk->modifierKeyMap)
|
||||||
|
FatalError("[Xi] no memory for class shift.\n");
|
||||||
|
memcpy(mk->modifierKeyMap, dk->modifierKeyMap,
|
||||||
|
(8 * dk->maxKeysPerModifier));
|
||||||
|
|
||||||
|
mk->maxKeysPerModifier = dk->maxKeysPerModifier;
|
||||||
|
mk->curKeySyms.minKeyCode = dk->curKeySyms.minKeyCode;
|
||||||
|
mk->curKeySyms.maxKeyCode = dk->curKeySyms.maxKeyCode;
|
||||||
|
SetKeySymsMap(&mk->curKeySyms, &dk->curKeySyms);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy state from the extended keyboard to core. If you omit this,
|
||||||
|
* holding Ctrl on keyboard one, and pressing Q on keyboard two, will
|
||||||
|
* cause your app to quit. This feels wrong to me, hence the below
|
||||||
|
* code.
|
||||||
|
*
|
||||||
|
* XXX: If you synthesise core modifier events, the state will get
|
||||||
|
* clobbered here. You'll have to work out something sensible
|
||||||
|
* to fix that. Good luck.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define KEYBOARD_MASK (ShiftMask | LockMask | ControlMask | Mod1Mask | \
|
||||||
|
Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)
|
||||||
|
mk->state &= ~(KEYBOARD_MASK);
|
||||||
|
mk->state |= (dk->state & KEYBOARD_MASK);
|
||||||
|
#undef KEYBOARD_MASK
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
mk->modifierKeyCount[i] = dk->modifierKeyCount[i];
|
||||||
|
|
||||||
|
#ifdef XKB
|
||||||
|
if (!mk->xkbInfo || !mk->xkbInfo->desc)
|
||||||
|
XkbInitDevice(master);
|
||||||
|
if (!noXkbExtension && dk->xkbInfo && dk->xkbInfo->desc) {
|
||||||
|
if (!XkbCopyKeymap(dk->xkbInfo->desc, mk->xkbInfo->desc, True))
|
||||||
|
FatalError("Couldn't pivot keymap from device to core!\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
master->devPrivates[CoreDevicePrivatesIndex].ptr = device;
|
||||||
|
sendNotify = TRUE;
|
||||||
|
} else if (lastMapNotifyDevice != master)
|
||||||
|
sendNotify = TRUE;
|
||||||
|
|
||||||
|
if (sendNotify)
|
||||||
|
{
|
||||||
|
SendMappingNotify(master, MappingKeyboard,
|
||||||
|
mk->curKeySyms.minKeyCode,
|
||||||
|
(mk->curKeySyms.maxKeyCode -
|
||||||
|
mk->curKeySyms.minKeyCode),
|
||||||
|
serverClient);
|
||||||
|
lastMapNotifyDevice = master;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_X_EXPORT void
|
||||||
|
DeepCopyDeviceClasses(DeviceIntPtr from, DeviceIntPtr to)
|
||||||
|
{
|
||||||
|
#define ALLOC_COPY_CLASS_IF(field, type) \
|
||||||
|
if (from->field)\
|
||||||
|
{ \
|
||||||
|
to->field = xcalloc(1, sizeof(type)); \
|
||||||
|
if (!to->field) \
|
||||||
|
FatalError("[Xi] no memory for class shift.\n"); \
|
||||||
|
memcpy(to->field, from->field, sizeof(type)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
ALLOC_COPY_CLASS_IF(key, KeyClassRec);
|
||||||
|
if (to->key)
|
||||||
|
{
|
||||||
|
#ifdef XKB
|
||||||
|
to->key->xkbInfo = NULL;
|
||||||
|
#endif
|
||||||
|
CopyKeyClass(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from->valuator)
|
||||||
|
{
|
||||||
|
ValuatorClassPtr v;
|
||||||
|
to->valuator = xalloc(sizeof(ValuatorClassRec) +
|
||||||
|
from->valuator->numAxes * sizeof(AxisInfo) +
|
||||||
|
from->valuator->numAxes * sizeof(unsigned int));
|
||||||
|
v = to->valuator;
|
||||||
|
if (!v)
|
||||||
|
FatalError("[Xi] no memory for class shift.\n");
|
||||||
|
memcpy(v, from->valuator, sizeof(ValuatorClassRec));
|
||||||
|
v->axes = (AxisInfoPtr)&v[1];
|
||||||
|
memcpy(v->axes, from->valuator->axes, v->numAxes * sizeof(AxisInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
ALLOC_COPY_CLASS_IF(button, ButtonClassRec);
|
||||||
|
/* XXX: XkbAction needs to be copied */
|
||||||
|
ALLOC_COPY_CLASS_IF(focus, FocusClassRec);
|
||||||
|
ALLOC_COPY_CLASS_IF(proximity, ProximityClassRec);
|
||||||
|
ALLOC_COPY_CLASS_IF(absolute, AbsoluteClassRec);
|
||||||
|
ALLOC_COPY_CLASS_IF(kbdfeed, KbdFeedbackClassRec);
|
||||||
|
/* XXX: XkbSrvLedInfo needs to be copied*/
|
||||||
|
ALLOC_COPY_CLASS_IF(ptrfeed, PtrFeedbackClassRec);
|
||||||
|
ALLOC_COPY_CLASS_IF(intfeed, IntegerFeedbackClassRec);
|
||||||
|
ALLOC_COPY_CLASS_IF(stringfeed, StringFeedbackClassRec);
|
||||||
|
ALLOC_COPY_CLASS_IF(bell, BellFeedbackClassRec);
|
||||||
|
ALLOC_COPY_CLASS_IF(leds, LedFeedbackClassRec);
|
||||||
|
/* XXX: XkbSrvLedInfo needs to be copied. */
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ChangeMasterDeviceClasses(DeviceIntPtr device,
|
ChangeMasterDeviceClasses(DeviceIntPtr device,
|
||||||
deviceClassesChangedEvent *dcce)
|
deviceClassesChangedEvent *dcce)
|
||||||
|
@ -119,21 +269,31 @@ ChangeMasterDeviceClasses(DeviceIntPtr device,
|
||||||
dcce->num_classes = 0;
|
dcce->num_classes = 0;
|
||||||
|
|
||||||
master->public.devicePrivate = device->public.devicePrivate;
|
master->public.devicePrivate = device->public.devicePrivate;
|
||||||
master->key = device->key;
|
|
||||||
master->valuator = device->valuator;
|
if (master->key)
|
||||||
master->button = device->button;
|
xfree(master->key->modifierKeyMap);
|
||||||
master->focus = device->focus;
|
#ifdef XKB
|
||||||
master->proximity = device->proximity;
|
if (master->key && master->key->xkbInfo)
|
||||||
master->absolute = device->absolute;
|
XkbFreeInfo(master->key->xkbInfo);
|
||||||
master->kbdfeed = device->kbdfeed;
|
#endif
|
||||||
master->ptrfeed = device->ptrfeed;
|
xfree(master->key); master->key = NULL;
|
||||||
master->intfeed = device->intfeed;
|
xfree(master->valuator); master->valuator = NULL;
|
||||||
master->stringfeed = device->stringfeed;
|
xfree(master->button); master->button = NULL;
|
||||||
master->bell = device->bell;
|
xfree(master->focus); master->focus = NULL;
|
||||||
master->leds = device->leds;
|
xfree(master->proximity); master->proximity = NULL;
|
||||||
|
xfree(master->absolute); master->absolute = NULL;
|
||||||
|
xfree(master->kbdfeed); master->kbdfeed = NULL;
|
||||||
|
xfree(master->ptrfeed); master->ptrfeed = NULL;
|
||||||
|
xfree(master->stringfeed); master->stringfeed = NULL;
|
||||||
|
xfree(master->bell); master->bell = NULL;
|
||||||
|
xfree(master->leds); master->leds = NULL;
|
||||||
|
xfree(master->intfeed); master->intfeed = NULL;
|
||||||
|
|
||||||
|
DeepCopyDeviceClasses(device, master);
|
||||||
|
|
||||||
/* event is already correct size, see comment in GetPointerEvents */
|
/* event is already correct size, see comment in GetPointerEvents */
|
||||||
classbuff = (char*)&dcce[1];
|
classbuff = (char*)&dcce[1];
|
||||||
|
|
||||||
/* we don't actually swap if there's a NullClient, swapping is done
|
/* we don't actually swap if there's a NullClient, swapping is done
|
||||||
* later when event is delivered. */
|
* later when event is delivered. */
|
||||||
CopySwapClasses(NullClient, master, &dcce->num_classes, &classbuff);
|
CopySwapClasses(NullClient, master, &dcce->num_classes, &classbuff);
|
||||||
|
@ -159,9 +319,9 @@ UpdateDeviceState(DeviceIntPtr device, xEvent* xE, int count)
|
||||||
int key = 0,
|
int key = 0,
|
||||||
bit = 0;
|
bit = 0;
|
||||||
|
|
||||||
KeyClassPtr k = device->key;
|
KeyClassPtr k = NULL;
|
||||||
ButtonClassPtr b = device->button;
|
ButtonClassPtr b = NULL;
|
||||||
ValuatorClassPtr v = device->valuator;
|
ValuatorClassPtr v = NULL;
|
||||||
deviceValuator *xV = (deviceValuator *) xE;
|
deviceValuator *xV = (deviceValuator *) xE;
|
||||||
BYTE *kptr = NULL;
|
BYTE *kptr = NULL;
|
||||||
CARD16 modifiers = 0,
|
CARD16 modifiers = 0,
|
||||||
|
@ -181,6 +341,11 @@ UpdateDeviceState(DeviceIntPtr device, xEvent* xE, int count)
|
||||||
if (xE->u.u.type == GenericEvent)
|
if (xE->u.u.type == GenericEvent)
|
||||||
return DEFAULT;
|
return DEFAULT;
|
||||||
|
|
||||||
|
k = device->key;
|
||||||
|
v = device->valuator;
|
||||||
|
b = device->button;
|
||||||
|
|
||||||
|
|
||||||
if (xE->u.u.type != DeviceValuator)
|
if (xE->u.u.type != DeviceValuator)
|
||||||
{
|
{
|
||||||
key = xE->u.u.detail;
|
key = xE->u.u.detail;
|
||||||
|
@ -272,10 +437,9 @@ UpdateDeviceState(DeviceIntPtr device, xEvent* xE, int count)
|
||||||
*kptr |= bit;
|
*kptr |= bit;
|
||||||
if (device->valuator)
|
if (device->valuator)
|
||||||
device->valuator->motionHintWindow = NullWindow;
|
device->valuator->motionHintWindow = NullWindow;
|
||||||
if (!device->isMaster)
|
b->buttonsDown++;
|
||||||
b->buttonsDown++;
|
|
||||||
b->motionMask = DeviceButtonMotionMask;
|
b->motionMask = DeviceButtonMotionMask;
|
||||||
if (!device->isMaster && !b->map[key]) /* bit already unset for MDs */
|
if (!b->map[key])
|
||||||
return DONT_PROCESS;
|
return DONT_PROCESS;
|
||||||
if (b->map[key] <= 5)
|
if (b->map[key] <= 5)
|
||||||
b->state |= (Button1Mask >> 1) << b->map[key];
|
b->state |= (Button1Mask >> 1) << b->map[key];
|
||||||
|
@ -290,9 +454,7 @@ UpdateDeviceState(DeviceIntPtr device, xEvent* xE, int count)
|
||||||
*kptr &= ~bit;
|
*kptr &= ~bit;
|
||||||
if (device->valuator)
|
if (device->valuator)
|
||||||
device->valuator->motionHintWindow = NullWindow;
|
device->valuator->motionHintWindow = NullWindow;
|
||||||
if (!device->isMaster)
|
if (b->buttonsDown >= 1 && !--b->buttonsDown)
|
||||||
b->buttonsDown--;
|
|
||||||
if (b->buttonsDown >= 1 && !b->buttonsDown)
|
|
||||||
b->motionMask = 0;
|
b->motionMask = 0;
|
||||||
if (!b->map[key])
|
if (!b->map[key])
|
||||||
return DONT_PROCESS;
|
return DONT_PROCESS;
|
||||||
|
@ -323,9 +485,9 @@ ProcessOtherEvent(xEventPtr xE, DeviceIntPtr device, int count)
|
||||||
GrabPtr grab = device->deviceGrab.grab;
|
GrabPtr grab = device->deviceGrab.grab;
|
||||||
Bool deactivateDeviceGrab = FALSE;
|
Bool deactivateDeviceGrab = FALSE;
|
||||||
int key = 0, rootX, rootY;
|
int key = 0, rootX, rootY;
|
||||||
ButtonClassPtr b = device->button;
|
ButtonClassPtr b;
|
||||||
KeyClassPtr k = device->key;
|
KeyClassPtr k;
|
||||||
ValuatorClassPtr v = device->valuator;
|
ValuatorClassPtr v;
|
||||||
deviceValuator *xV = (deviceValuator *) xE;
|
deviceValuator *xV = (deviceValuator *) xE;
|
||||||
BOOL sendCore = FALSE;
|
BOOL sendCore = FALSE;
|
||||||
xEvent core;
|
xEvent core;
|
||||||
|
@ -336,6 +498,10 @@ ProcessOtherEvent(xEventPtr xE, DeviceIntPtr device, int count)
|
||||||
if (ret == DONT_PROCESS)
|
if (ret == DONT_PROCESS)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
v = device->valuator;
|
||||||
|
b = device->button;
|
||||||
|
k = device->key;
|
||||||
|
|
||||||
coretype = XItoCoreType(xE->u.u.type);
|
coretype = XItoCoreType(xE->u.u.type);
|
||||||
if (device->isMaster && device->coreEvents && coretype)
|
if (device->isMaster && device->coreEvents && coretype)
|
||||||
sendCore = TRUE;
|
sendCore = TRUE;
|
||||||
|
|
|
@ -865,63 +865,6 @@ GetProximityEvents(EventList *events, DeviceIntPtr pDev, int type,
|
||||||
return num_events;
|
return num_events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pDev is the slave device that is about to send an event. If it is attached
|
|
||||||
* to a master device, then we need to send a mapping notify to the client.
|
|
||||||
* To do so, we need to remember the last master device that sent a mapping
|
|
||||||
* event.
|
|
||||||
*
|
|
||||||
* Mapping notify needs to be sent in the following cases:
|
|
||||||
* - different slave device on same master
|
|
||||||
* - different master
|
|
||||||
*
|
|
||||||
* Call this just before processInputProc.
|
|
||||||
*
|
|
||||||
* XXX: They way how the code is we also send a map notify if the slave device
|
|
||||||
* stays the same, but the master changes. This isn't really necessary though.
|
|
||||||
*
|
|
||||||
* XXX: this gives you funny behaviour with the ClientPointer. When a
|
|
||||||
* MappingNotify is sent to the client, the client usually responds with a
|
|
||||||
* GetKeyboardMapping. This will retrieve the ClientPointer's keyboard
|
|
||||||
* mapping, regardless of which keyboard sent the last mapping notify request.
|
|
||||||
* So depending on the CP setting, your keyboard may change layout in each
|
|
||||||
* app...
|
|
||||||
*/
|
|
||||||
_X_EXPORT void
|
|
||||||
SwitchCoreKeyboard(DeviceIntPtr pDev)
|
|
||||||
{
|
|
||||||
static DeviceIntPtr lastMapNotifyDevice = NULL;
|
|
||||||
DeviceIntPtr master;
|
|
||||||
KeyClassPtr ckeyc;
|
|
||||||
int i = 0;
|
|
||||||
BOOL sendNotify = FALSE;
|
|
||||||
|
|
||||||
if (pDev->isMaster || !pDev->u.master)
|
|
||||||
return;
|
|
||||||
|
|
||||||
master = pDev->u.master;
|
|
||||||
ckeyc = master->key;
|
|
||||||
|
|
||||||
if (master->devPrivates[CoreDevicePrivatesIndex].ptr != pDev) {
|
|
||||||
master->devPrivates[CoreDevicePrivatesIndex].ptr = pDev;
|
|
||||||
sendNotify = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastMapNotifyDevice != master)
|
|
||||||
sendNotify = TRUE;
|
|
||||||
|
|
||||||
if (sendNotify)
|
|
||||||
{
|
|
||||||
SendMappingNotify(pDev, MappingKeyboard, ckeyc->curKeySyms.minKeyCode,
|
|
||||||
(ckeyc->curKeySyms.maxKeyCode -
|
|
||||||
ckeyc->curKeySyms.minKeyCode),
|
|
||||||
serverClient);
|
|
||||||
lastMapNotifyDevice = master;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note that pDev was the last function to send a core pointer event.
|
* Note that pDev was the last function to send a core pointer event.
|
||||||
* Currently a no-op.
|
* Currently a no-op.
|
||||||
|
|
|
@ -458,7 +458,6 @@ extern int GetMotionHistory(
|
||||||
unsigned long stop,
|
unsigned long stop,
|
||||||
ScreenPtr pScreen);
|
ScreenPtr pScreen);
|
||||||
|
|
||||||
extern void SwitchCoreKeyboard(DeviceIntPtr pDev);
|
|
||||||
extern void SwitchCorePointer(DeviceIntPtr pDev);
|
extern void SwitchCorePointer(DeviceIntPtr pDev);
|
||||||
|
|
||||||
extern DeviceIntPtr LookupDeviceIntRec(
|
extern DeviceIntPtr LookupDeviceIntRec(
|
||||||
|
@ -483,6 +482,8 @@ extern DeviceIntPtr NextFreePointerDevice(void);
|
||||||
extern int AllocMasterDevice(char* name,
|
extern int AllocMasterDevice(char* name,
|
||||||
DeviceIntPtr* ptr,
|
DeviceIntPtr* ptr,
|
||||||
DeviceIntPtr* keybd);
|
DeviceIntPtr* keybd);
|
||||||
|
extern void DeepCopyDeviceClasses(DeviceIntPtr from,
|
||||||
|
DeviceIntPtr to);
|
||||||
|
|
||||||
/* Window/device based access control */
|
/* Window/device based access control */
|
||||||
extern Bool ACRegisterClient(ClientPtr client);
|
extern Bool ACRegisterClient(ClientPtr client);
|
||||||
|
|
Loading…
Reference in New Issue