xserver-multidpi/xkb/xkbActions.c

1435 lines
40 KiB
C
Raw Normal View History

2003-11-14 16:54:54 +01:00
/************************************************************
Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright
notice and this permission notice appear in supporting
documentation, and that the name of Silicon Graphics not be
used in advertising or publicity pertaining to distribution
of the software without specific prior written permission.
Silicon Graphics makes no representation about the suitability
of this software for any purpose. It is provided "as is"
without any express or implied warranty.
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
THE USE OR PERFORMANCE OF THIS SOFTWARE.
********************************************************/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
2003-11-14 16:54:54 +01:00
#include <stdio.h>
#include <math.h>
#include <X11/X.h>
#include <X11/Xproto.h>
#include <X11/keysym.h>
#include "misc.h"
2003-11-14 16:54:54 +01:00
#include "inputstr.h"
#include "exevents.h"
#include "eventstr.h"
#include <xkbsrv.h>
#include "xkb.h"
2003-11-14 16:54:54 +01:00
#include <ctype.h>
#include "mi.h"
#include "mipointer.h"
#include "inpututils.h"
#define EXTENSION_EVENT_BASE 64
2003-11-14 16:54:54 +01:00
DevPrivateKeyRec xkbDevicePrivateKeyRec;
void XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button);
static void XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y);
void
xkbUnwrapProc(DeviceIntPtr device, DeviceHandleProc proc,
pointer data)
{
xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(device);
ProcessInputProc backupproc;
if(xkbPrivPtr->unwrapProc)
xkbPrivPtr->unwrapProc = NULL;
UNWRAP_PROCESS_INPUT_PROC(device,xkbPrivPtr, backupproc);
proc(device,data);
COND_WRAP_PROCESS_INPUT_PROC(device,xkbPrivPtr,
backupproc,xkbUnwrapProc);
}
Bool
XkbInitPrivates(void)
{
return dixRegisterPrivateKey(&xkbDevicePrivateKeyRec, PRIVATE_DEVICE, sizeof(xkbDeviceInfoRec));
}
void
XkbSetExtension(DeviceIntPtr device, ProcessInputProc proc)
{
xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(device);
WRAP_PROCESS_INPUT_PROC(device, xkbPrivPtr, proc, xkbUnwrapProc);
}
2003-11-14 16:54:54 +01:00
/***====================================================================***/
static XkbAction
_FixUpAction(XkbDescPtr xkb,XkbAction *act)
{
static XkbAction fake;
if (XkbIsPtrAction(act)&&(!(xkb->ctrls->enabled_ctrls&XkbMouseKeysMask))) {
fake.type = XkbSA_NoAction;
return fake;
}
if (xkb->ctrls->enabled_ctrls&XkbStickyKeysMask) {
if (act->any.type==XkbSA_SetMods) {
fake.mods.type = XkbSA_LatchMods;
fake.mods.mask = act->mods.mask;
if (XkbAX_NeedOption(xkb->ctrls,XkbAX_LatchToLockMask))
fake.mods.flags= XkbSA_ClearLocks|XkbSA_LatchToLock;
else fake.mods.flags= XkbSA_ClearLocks;
return fake;
}
if (act->any.type==XkbSA_SetGroup) {
fake.group.type = XkbSA_LatchGroup;
if (XkbAX_NeedOption(xkb->ctrls,XkbAX_LatchToLockMask))
fake.group.flags= XkbSA_ClearLocks|XkbSA_LatchToLock;
else fake.group.flags= XkbSA_ClearLocks;
XkbSASetGroup(&fake.group,XkbSAGroup(&act->group));
return fake;
}
}
return *act;
}
static XkbAction
XkbGetKeyAction(XkbSrvInfoPtr xkbi,XkbStatePtr xkbState,CARD8 key)
{
int effectiveGroup;
int col;
XkbDescPtr xkb;
XkbKeyTypePtr type;
XkbAction * pActs;
static XkbAction fake;
xkb= xkbi->desc;
2003-11-14 17:49:22 +01:00
if (!XkbKeyHasActions(xkb,key) || !XkbKeycodeInRange(xkb,key)) {
2003-11-14 16:54:54 +01:00
fake.type = XkbSA_NoAction;
return fake;
}
pActs= XkbKeyActionsPtr(xkb,key);
col= 0;
effectiveGroup = XkbGetEffectiveGroup(xkbi, xkbState, key);
if (effectiveGroup != XkbGroup1Index)
col += (effectiveGroup * XkbKeyGroupsWidth(xkb, key));
2003-11-14 16:54:54 +01:00
type= XkbKeyKeyType(xkb,key,effectiveGroup);
if (type->map!=NULL) {
register unsigned i,mods;
register XkbKTMapEntryPtr entry;
mods= xkbState->mods&type->mods.mask;
for (entry= type->map,i=0;i<type->map_count;i++,entry++) {
if ((entry->active)&&(entry->mods.mask==mods)) {
col+= entry->level;
break;
}
}
}
if (pActs[col].any.type==XkbSA_NoAction)
return pActs[col];
fake= _FixUpAction(xkb,&pActs[col]);
return fake;
}
static XkbAction
2003-11-14 16:54:54 +01:00
XkbGetButtonAction(DeviceIntPtr kbd,DeviceIntPtr dev,int button)
{
XkbAction fake;
if ((dev->button)&&(dev->button->xkb_acts)) {
if (dev->button->xkb_acts[button-1].any.type!=XkbSA_NoAction) {
fake= _FixUpAction(kbd->key->xkbInfo->desc,
&dev->button->xkb_acts[button-1]);
return fake;
}
}
fake.any.type= XkbSA_NoAction;
return fake;
}
/***====================================================================***/
#define SYNTHETIC_KEYCODE 1
#define BTN_ACT_FLAG 0x100
static int
_XkbFilterSetState( XkbSrvInfoPtr xkbi,
XkbFilterPtr filter,
unsigned keycode,
XkbAction *pAction)
{
if (filter->keycode==0) { /* initial press */
filter->keycode = keycode;
filter->active = 1;
filter->filterOthers = ((pAction->mods.mask&XkbSA_ClearLocks)!=0);
filter->priv = 0;
filter->filter = _XkbFilterSetState;
if (pAction->type==XkbSA_SetMods) {
filter->upAction = *pAction;
xkbi->setMods= pAction->mods.mask;
}
else {
xkbi->groupChange = XkbSAGroup(&pAction->group);
if (pAction->group.flags&XkbSA_GroupAbsolute)
xkbi->groupChange-= xkbi->state.base_group;
filter->upAction= *pAction;
XkbSASetGroup(&filter->upAction.group,xkbi->groupChange);
}
}
else if (filter->keycode==keycode) {
if (filter->upAction.type==XkbSA_SetMods) {
xkbi->clearMods = filter->upAction.mods.mask;
if (filter->upAction.mods.flags&XkbSA_ClearLocks) {
xkbi->state.locked_mods&= ~filter->upAction.mods.mask;
}
}
else {
if (filter->upAction.group.flags&XkbSA_ClearLocks) {
xkbi->state.locked_group = 0;
}
xkbi->groupChange = -XkbSAGroup(&filter->upAction.group);
}
filter->active = 0;
}
else {
filter->upAction.mods.flags&= ~XkbSA_ClearLocks;
filter->filterOthers = 0;
}
return 1;
}
#define LATCH_KEY_DOWN 1
#define LATCH_PENDING 2
#define NO_LATCH 3
static int
_XkbFilterLatchState( XkbSrvInfoPtr xkbi,
XkbFilterPtr filter,
unsigned keycode,
XkbAction * pAction)
{
if (filter->keycode==0) { /* initial press */
filter->keycode = keycode;
filter->active = 1;
filter->filterOthers = 1;
filter->priv = LATCH_KEY_DOWN;
filter->filter = _XkbFilterLatchState;
if (pAction->type==XkbSA_LatchMods) {
filter->upAction = *pAction;
xkbi->setMods = pAction->mods.mask;
}
else {
xkbi->groupChange = XkbSAGroup(&pAction->group);
if (pAction->group.flags&XkbSA_GroupAbsolute)
xkbi->groupChange-= xkbi->state.base_group;
filter->upAction= *pAction;
XkbSASetGroup(&filter->upAction.group,xkbi->groupChange);
}
}
else if ( pAction && (filter->priv==LATCH_PENDING) ) {
if (((1<<pAction->type)&XkbSA_BreakLatch)!=0) {
filter->active = 0;
if (filter->upAction.type==XkbSA_LatchMods)
xkbi->state.latched_mods&= ~filter->upAction.mods.mask;
else xkbi->state.latched_group-=XkbSAGroup(&filter->upAction.group);
}
else if ((pAction->type==filter->upAction.type)&&
(pAction->mods.flags==filter->upAction.mods.flags)&&
(pAction->mods.mask==filter->upAction.mods.mask)) {
if (filter->upAction.mods.flags&XkbSA_LatchToLock) {
XkbControlsPtr ctrls= xkbi->desc->ctrls;
if (filter->upAction.type==XkbSA_LatchMods)
pAction->mods.type= XkbSA_LockMods;
else pAction->group.type= XkbSA_LockGroup;
if (XkbAX_NeedFeedback(ctrls,XkbAX_StickyKeysFBMask)&&
(ctrls->enabled_ctrls&XkbStickyKeysMask)) {
XkbDDXAccessXBeep(xkbi->device,_BEEP_STICKY_LOCK,
XkbStickyKeysMask);
}
}
else {
if (filter->upAction.type==XkbSA_LatchMods)
pAction->mods.type= XkbSA_SetMods;
else pAction->group.type= XkbSA_SetGroup;
}
if (filter->upAction.type==XkbSA_LatchMods)
xkbi->state.latched_mods&= ~filter->upAction.mods.mask;
else xkbi->state.latched_group-=XkbSAGroup(&filter->upAction.group);
filter->active = 0;
}
}
else if (filter->keycode==keycode) { /* release */
XkbControlsPtr ctrls= xkbi->desc->ctrls;
int needBeep;
int beepType= _BEEP_NONE;
needBeep= ((ctrls->enabled_ctrls&XkbStickyKeysMask)&&
XkbAX_NeedFeedback(ctrls,XkbAX_StickyKeysFBMask));
if (filter->upAction.type==XkbSA_LatchMods) {
xkbi->clearMods = filter->upAction.mods.mask;
if ((filter->upAction.mods.flags&XkbSA_ClearLocks)&&
(xkbi->clearMods&xkbi->state.locked_mods)==xkbi->clearMods) {
xkbi->state.locked_mods&= ~xkbi->clearMods;
filter->priv= NO_LATCH;
beepType= _BEEP_STICKY_UNLOCK;
}
}
else {
xkbi->groupChange = -XkbSAGroup(&filter->upAction.group);
if ((filter->upAction.group.flags&XkbSA_ClearLocks)&&
(xkbi->state.locked_group)) {
xkbi->state.locked_group = 0;
filter->priv = NO_LATCH;
beepType= _BEEP_STICKY_UNLOCK;
}
}
if (filter->priv==NO_LATCH) {
filter->active= 0;
}
else {
filter->priv= LATCH_PENDING;
if (filter->upAction.type==XkbSA_LatchMods) {
xkbi->state.latched_mods |= filter->upAction.mods.mask;
needBeep = xkbi->state.latched_mods ? needBeep : 0;
xkbi->state.latched_mods |= filter->upAction.mods.mask;
}
else {
xkbi->state.latched_group+= XkbSAGroup(&filter->upAction.group);
}
if (needBeep && (beepType==_BEEP_NONE))
beepType= _BEEP_STICKY_LATCH;
}
if (needBeep && (beepType!=_BEEP_NONE))
XkbDDXAccessXBeep(xkbi->device,beepType,XkbStickyKeysMask);
}
else if (filter->priv==LATCH_KEY_DOWN) {
filter->priv= NO_LATCH;
filter->filterOthers = 0;
}
return 1;
}
static int
_XkbFilterLockState( XkbSrvInfoPtr xkbi,
XkbFilterPtr filter,
unsigned keycode,
XkbAction * pAction)
{
if (pAction&&(pAction->type==XkbSA_LockGroup)) {
if (pAction->group.flags&XkbSA_GroupAbsolute)
xkbi->state.locked_group= XkbSAGroup(&pAction->group);
else xkbi->state.locked_group+= XkbSAGroup(&pAction->group);
return 1;
}
if (filter->keycode==0) { /* initial press */
filter->keycode = keycode;
filter->active = 1;
filter->filterOthers = 0;
filter->priv = 0;
filter->filter = _XkbFilterLockState;
filter->upAction = *pAction;
xkbi->state.locked_mods^= pAction->mods.mask;
xkbi->setMods = pAction->mods.mask;
}
else if (filter->keycode==keycode) {
filter->active = 0;
xkbi->clearMods = filter->upAction.mods.mask;
}
return 1;
}
#define ISO_KEY_DOWN 0
#define NO_ISO_LOCK 1
static int
_XkbFilterISOLock( XkbSrvInfoPtr xkbi,
XkbFilterPtr filter,
unsigned keycode,
XkbAction * pAction)
{
if (filter->keycode==0) { /* initial press */
CARD8 flags= pAction->iso.flags;
filter->keycode = keycode;
filter->active = 1;
filter->filterOthers = 1;
filter->priv = ISO_KEY_DOWN;
filter->upAction = *pAction;
filter->filter = _XkbFilterISOLock;
if (flags&XkbSA_ISODfltIsGroup) {
xkbi->groupChange = XkbSAGroup(&pAction->iso);
xkbi->setMods = 0;
}
else {
xkbi->setMods = pAction->iso.mask;
xkbi->groupChange = 0;
}
if ((!(flags&XkbSA_ISONoAffectMods))&&(xkbi->state.base_mods)) {
filter->priv= NO_ISO_LOCK;
xkbi->state.locked_mods^= xkbi->state.base_mods;
}
if ((!(flags&XkbSA_ISONoAffectGroup))&&(xkbi->state.base_group)) {
/* 6/22/93 (ef) -- lock groups if group key is down first */
}
if (!(flags&XkbSA_ISONoAffectPtr)) {
/* 6/22/93 (ef) -- lock mouse buttons if they're down */
}
}
else if (filter->keycode==keycode) {
CARD8 flags= filter->upAction.iso.flags;
if (flags&XkbSA_ISODfltIsGroup) {
xkbi->groupChange = -XkbSAGroup(&filter->upAction.iso);
xkbi->clearMods = 0;
if (filter->priv==ISO_KEY_DOWN)
xkbi->state.locked_group+= XkbSAGroup(&filter->upAction.iso);
}
else {
xkbi->clearMods= filter->upAction.iso.mask;
xkbi->groupChange= 0;
if (filter->priv==ISO_KEY_DOWN)
xkbi->state.locked_mods^= filter->upAction.iso.mask;
}
filter->active = 0;
}
else if (pAction) {
CARD8 flags= filter->upAction.iso.flags;
switch (pAction->type) {
case XkbSA_SetMods: case XkbSA_LatchMods:
if (!(flags&XkbSA_ISONoAffectMods)) {
pAction->type= XkbSA_LockMods;
filter->priv= NO_ISO_LOCK;
}
break;
case XkbSA_SetGroup: case XkbSA_LatchGroup:
if (!(flags&XkbSA_ISONoAffectGroup)) {
pAction->type= XkbSA_LockGroup;
filter->priv= NO_ISO_LOCK;
}
break;
case XkbSA_PtrBtn:
if (!(flags&XkbSA_ISONoAffectPtr)) {
pAction->type= XkbSA_LockPtrBtn;
filter->priv= NO_ISO_LOCK;
}
break;
case XkbSA_SetControls:
if (!(flags&XkbSA_ISONoAffectCtrls)) {
pAction->type= XkbSA_LockControls;
filter->priv= NO_ISO_LOCK;
}
break;
}
}
return 1;
}
static CARD32
_XkbPtrAccelExpire(OsTimerPtr timer,CARD32 now,pointer arg)
{
XkbSrvInfoPtr xkbi= (XkbSrvInfoPtr)arg;
XkbControlsPtr ctrls= xkbi->desc->ctrls;
int dx,dy;
if (xkbi->mouseKey==0)
return 0;
if (xkbi->mouseKeysAccel) {
if ((xkbi->mouseKeysCounter)<ctrls->mk_time_to_max) {
double step;
xkbi->mouseKeysCounter++;
step= xkbi->mouseKeysCurveFactor*
pow((double)xkbi->mouseKeysCounter,xkbi->mouseKeysCurve);
if (xkbi->mouseKeysDX<0)
dx= floor( ((double)xkbi->mouseKeysDX)*step );
else dx= ceil( ((double)xkbi->mouseKeysDX)*step );
if (xkbi->mouseKeysDY<0)
dy= floor( ((double)xkbi->mouseKeysDY)*step );
else dy= ceil( ((double)xkbi->mouseKeysDY)*step );
}
else {
dx= xkbi->mouseKeysDX*ctrls->mk_max_speed;
dy= xkbi->mouseKeysDY*ctrls->mk_max_speed;
}
if (xkbi->mouseKeysFlags&XkbSA_MoveAbsoluteX)
dx= xkbi->mouseKeysDX;
if (xkbi->mouseKeysFlags&XkbSA_MoveAbsoluteY)
dy= xkbi->mouseKeysDY;
}
else {
dx= xkbi->mouseKeysDX;
dy= xkbi->mouseKeysDY;
}
XkbFakePointerMotion(xkbi->device, xkbi->mouseKeysFlags,dx,dy);
2003-11-14 16:54:54 +01:00
return xkbi->desc->ctrls->mk_interval;
}
static int
_XkbFilterPointerMove( XkbSrvInfoPtr xkbi,
XkbFilterPtr filter,
unsigned keycode,
XkbAction * pAction)
{
int x,y;
Bool accel;
if (filter->keycode==0) { /* initial press */
filter->keycode = keycode;
filter->active = 1;
filter->filterOthers = 0;
filter->priv=0;
filter->filter = _XkbFilterPointerMove;
filter->upAction= *pAction;
xkbi->mouseKeysCounter= 0;
xkbi->mouseKey= keycode;
accel= ((pAction->ptr.flags&XkbSA_NoAcceleration)==0);
x= XkbPtrActionX(&pAction->ptr);
y= XkbPtrActionY(&pAction->ptr);
XkbFakePointerMotion(xkbi->device, pAction->ptr.flags,x,y);
2003-11-14 16:54:54 +01:00
AccessXCancelRepeatKey(xkbi,keycode);
xkbi->mouseKeysAccel= accel&&
(xkbi->desc->ctrls->enabled_ctrls&XkbMouseKeysAccelMask);
2003-11-14 17:49:22 +01:00
xkbi->mouseKeysFlags= pAction->ptr.flags;
xkbi->mouseKeysDX= XkbPtrActionX(&pAction->ptr);
xkbi->mouseKeysDY= XkbPtrActionY(&pAction->ptr);
2003-11-14 17:49:22 +01:00
xkbi->mouseKeyTimer= TimerSet(xkbi->mouseKeyTimer, 0,
2003-11-14 16:54:54 +01:00
xkbi->desc->ctrls->mk_delay,
_XkbPtrAccelExpire,(pointer)xkbi);
}
else if (filter->keycode==keycode) {
filter->active = 0;
if (xkbi->mouseKey==keycode) {
xkbi->mouseKey= 0;
xkbi->mouseKeyTimer= TimerSet(xkbi->mouseKeyTimer, 0, 0,
NULL, NULL);
}
}
return 0;
}
static int
_XkbFilterPointerBtn( XkbSrvInfoPtr xkbi,
XkbFilterPtr filter,
unsigned keycode,
XkbAction * pAction)
{
if (filter->keycode==0) { /* initial press */
int button= pAction->btn.button;
if (button==XkbSA_UseDfltButton)
button = xkbi->desc->ctrls->mk_dflt_btn;
filter->keycode = keycode;
filter->active = 1;
filter->filterOthers = 0;
filter->priv=0;
filter->filter = _XkbFilterPointerBtn;
filter->upAction= *pAction;
filter->upAction.btn.button= button;
switch (pAction->type) {
case XkbSA_LockPtrBtn:
if (((xkbi->lockedPtrButtons&(1<<button))==0)&&
((pAction->btn.flags&XkbSA_LockNoLock)==0)) {
xkbi->lockedPtrButtons|= (1<<button);
AccessXCancelRepeatKey(xkbi,keycode);
XkbFakeDeviceButton(xkbi->device, 1, button);
2003-11-14 16:54:54 +01:00
filter->upAction.type= XkbSA_NoAction;
}
break;
case XkbSA_PtrBtn:
{
register int i,nClicks;
AccessXCancelRepeatKey(xkbi,keycode);
if (pAction->btn.count>0) {
nClicks= pAction->btn.count;
for (i=0;i<nClicks;i++) {
XkbFakeDeviceButton(xkbi->device, 1, button);
XkbFakeDeviceButton(xkbi->device, 0, button);
2003-11-14 16:54:54 +01:00
}
filter->upAction.type= XkbSA_NoAction;
}
else XkbFakeDeviceButton(xkbi->device, 1, button);
2003-11-14 16:54:54 +01:00
}
break;
case XkbSA_SetPtrDflt:
{
XkbControlsPtr ctrls= xkbi->desc->ctrls;
XkbControlsRec old;
xkbControlsNotify cn;
old= *ctrls;
AccessXCancelRepeatKey(xkbi,keycode);
switch (pAction->dflt.affect) {
case XkbSA_AffectDfltBtn:
if (pAction->dflt.flags&XkbSA_DfltBtnAbsolute)
ctrls->mk_dflt_btn=
XkbSAPtrDfltValue(&pAction->dflt);
else {
ctrls->mk_dflt_btn+=
XkbSAPtrDfltValue(&pAction->dflt);
if (ctrls->mk_dflt_btn>5)
ctrls->mk_dflt_btn= 5;
else if (ctrls->mk_dflt_btn<1)
ctrls->mk_dflt_btn= 1;
}
break;
default:
ErrorF(
"Attempt to change unknown pointer default (%d) ignored\n",
pAction->dflt.affect);
break;
}
if (XkbComputeControlsNotify(xkbi->device,
&old,xkbi->desc->ctrls,
&cn,FALSE)) {
2003-11-14 16:54:54 +01:00
cn.keycode = keycode;
/* XXX: what about DeviceKeyPress? */
2003-11-14 16:54:54 +01:00
cn.eventType = KeyPress;
cn.requestMajor = 0;
cn.requestMinor = 0;
XkbSendControlsNotify(xkbi->device,&cn);
}
}
break;
}
}
else if (filter->keycode==keycode) {
int button= filter->upAction.btn.button;
switch (filter->upAction.type) {
case XkbSA_LockPtrBtn:
if (((filter->upAction.btn.flags&XkbSA_LockNoUnlock)!=0)||
((xkbi->lockedPtrButtons&(1<<button))==0)) {
break;
}
xkbi->lockedPtrButtons&= ~(1<<button);
xkb: merge lockedPtrButtons state from all attached SDs. Problem: lockedPtrButtons keeps the state of the buttons locked by a PointerKeys button press. Unconditionally clearing the bits may cause stuck buttons in this sequence of events: 1. type Shift + NumLock to enable PointerKeys 2. type 0/Ins on keypad to emulate Button 1 press → button1 press event to client 3. press and release button 1 on physical mouse → button1 release event to client Button 1 on the MD is now stuck and cannot be released. Cause: XKB PointerKeys button events are posted through the XTEST pointer device. Once a press is generated, the XTEST device's button is down. The DIX merges the button state of all attached SDs, hence the MD will have a button down while the XTEST device has a button down. PointerKey button events are only generated on the master device to avoid duplicate events (see XkbFakeDeviceButton()). If the MD has the lockedPtrButtons bit cleared by a release event on a physical device, no such event is generated when a keyboard device triggers the PointerKey ButtonRelease trigger. Since the event - if generated - is posted through the XTEST pointer device, lack of a generated ButtonRelease event on the XTEST pointer device means the button is never released, resulting in the stuck button observed above. Solution: This patch merges the MD's lockedPtrButtons with the one of all attached slave devices on release events. Thus, as long as one attached keyboard has a lockedPtrButtons bit set, this bit is kept in the MD. Once a PointerKey button is released on all keyboards, the matching release event is emulated from the MD through the XTEST pointer device, thus also releasing the button in the DIX. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2010-06-29 04:12:53 +02:00
if (IsMaster(xkbi->device))
{
XkbMergeLockedPtrBtns(xkbi->device);
/* One SD still has lock set, don't post event */
if ((xkbi->lockedPtrButtons & (1 << button)) != 0)
break;
}
/* fallthrough */
2003-11-14 16:54:54 +01:00
case XkbSA_PtrBtn:
XkbFakeDeviceButton(xkbi->device, 0, button);
2003-11-14 16:54:54 +01:00
break;
}
filter->active = 0;
}
return 0;
}
static int
_XkbFilterControls( XkbSrvInfoPtr xkbi,
XkbFilterPtr filter,
unsigned keycode,
XkbAction * pAction)
{
XkbControlsRec old;
XkbControlsPtr ctrls;
DeviceIntPtr kbd;
unsigned int change;
XkbEventCauseRec cause;
kbd= xkbi->device;
ctrls= xkbi->desc->ctrls;
old= *ctrls;
if (filter->keycode==0) { /* initial press */
filter->keycode = keycode;
filter->active = 1;
filter->filterOthers = 0;
change= XkbActionCtrls(&pAction->ctrls);
2003-11-14 16:54:54 +01:00
filter->priv = change;
filter->filter = _XkbFilterControls;
filter->upAction = *pAction;
if (pAction->type==XkbSA_LockControls) {
filter->priv= (ctrls->enabled_ctrls&change);
change&= ~ctrls->enabled_ctrls;
}
if (change) {
xkbControlsNotify cn;
XkbSrvLedInfoPtr sli;
ctrls->enabled_ctrls|= change;
if (XkbComputeControlsNotify(kbd,&old,ctrls,&cn,FALSE)) {
2003-11-14 16:54:54 +01:00
cn.keycode = keycode;
/* XXX: what about DeviceKeyPress? */
2003-11-14 16:54:54 +01:00
cn.eventType = KeyPress;
cn.requestMajor = 0;
cn.requestMinor = 0;
XkbSendControlsNotify(kbd,&cn);
}
XkbSetCauseKey(&cause,keycode,KeyPress);
/* If sticky keys were disabled, clear all locks and latches */
if ((old.enabled_ctrls&XkbStickyKeysMask)&&
(!(ctrls->enabled_ctrls&XkbStickyKeysMask))) {
XkbClearAllLatchesAndLocks(kbd,xkbi,FALSE,&cause);
2003-11-14 16:54:54 +01:00
}
sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0);
XkbUpdateIndicators(kbd,sli->usesControls,TRUE,NULL,&cause);
2003-11-14 16:54:54 +01:00
if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask))
XkbDDXAccessXBeep(kbd,_BEEP_FEATURE_ON,change);
}
}
else if (filter->keycode==keycode) {
change= filter->priv;
if (change) {
xkbControlsNotify cn;
XkbSrvLedInfoPtr sli;
ctrls->enabled_ctrls&= ~change;
if (XkbComputeControlsNotify(kbd,&old,ctrls,&cn,FALSE)) {
2003-11-14 16:54:54 +01:00
cn.keycode = keycode;
cn.eventType = KeyRelease;
cn.requestMajor = 0;
cn.requestMinor = 0;
XkbSendControlsNotify(kbd,&cn);
}
XkbSetCauseKey(&cause,keycode,KeyRelease);
/* If sticky keys were disabled, clear all locks and latches */
if ((old.enabled_ctrls&XkbStickyKeysMask)&&
(!(ctrls->enabled_ctrls&XkbStickyKeysMask))) {
XkbClearAllLatchesAndLocks(kbd,xkbi,FALSE,&cause);
2003-11-14 16:54:54 +01:00
}
sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0);
XkbUpdateIndicators(kbd,sli->usesControls,TRUE,NULL,&cause);
2003-11-14 16:54:54 +01:00
if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask))
XkbDDXAccessXBeep(kbd,_BEEP_FEATURE_OFF,change);
}
filter->keycode= 0;
filter->active= 0;
}
2003-11-14 17:49:22 +01:00
return 1;
2003-11-14 16:54:54 +01:00
}
static int
_XkbFilterActionMessage(XkbSrvInfoPtr xkbi,
XkbFilterPtr filter,
unsigned keycode,
XkbAction * pAction)
{
XkbMessageAction * pMsg;
DeviceIntPtr kbd;
kbd= xkbi->device;
if (filter->keycode==0) { /* initial press */
pMsg= &pAction->msg;
if ((pMsg->flags&XkbSA_MessageOnRelease)||
((pMsg->flags&XkbSA_MessageGenKeyEvent)==0)) {
filter->keycode = keycode;
filter->active = 1;
filter->filterOthers = 0;
filter->priv = 0;
filter->filter = _XkbFilterActionMessage;
filter->upAction = *pAction;
}
if (pMsg->flags&XkbSA_MessageOnPress) {
xkbActionMessage msg;
msg.keycode= keycode;
msg.press= 1;
msg.keyEventFollows=((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0);
memcpy((char *)msg.message,
(char *)pMsg->message,XkbActionMessageLength);
XkbSendActionMessage(kbd,&msg);
}
return ((pAction->msg.flags&XkbSA_MessageGenKeyEvent)!=0);
}
else if (filter->keycode==keycode) {
pMsg= &filter->upAction.msg;
if (pMsg->flags&XkbSA_MessageOnRelease) {
xkbActionMessage msg;
msg.keycode= keycode;
msg.press= 0;
msg.keyEventFollows=((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0);
memcpy((char *)msg.message,(char *)pMsg->message,
XkbActionMessageLength);
XkbSendActionMessage(kbd,&msg);
}
filter->keycode= 0;
filter->active= 0;
return ((pMsg->flags&XkbSA_MessageGenKeyEvent)!=0);
}
return 0;
}
static int
_XkbFilterRedirectKey( XkbSrvInfoPtr xkbi,
XkbFilterPtr filter,
unsigned keycode,
XkbAction * pAction)
{
DeviceEvent ev;
2003-11-14 17:49:22 +01:00
int x,y;
2003-11-14 16:54:54 +01:00
XkbStateRec old;
unsigned mods,mask;
xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(xkbi->device);
ProcessInputProc backupproc;
2003-11-14 16:54:54 +01:00
/* never actually used uninitialised, but gcc isn't smart enough
* to work that out. */
memset(&old, 0, sizeof(old));
memset(&ev, 0, sizeof(ev));
2003-11-14 16:54:54 +01:00
if ((filter->keycode!=0)&&(filter->keycode!=keycode))
2003-11-14 17:49:22 +01:00
return 1;
2003-11-14 16:54:54 +01:00
GetSpritePosition(xkbi->device, &x,&y);
ev.header = ET_Internal;
ev.length = sizeof(DeviceEvent);
ev.time = GetTimeInMillis();
ev.root_x = x;
ev.root_y = y;
2003-11-14 16:54:54 +01:00
if (filter->keycode==0) { /* initial press */
if ((pAction->redirect.new_key<xkbi->desc->min_key_code)||
(pAction->redirect.new_key>xkbi->desc->max_key_code)) {
return 1;
}
filter->keycode = keycode;
filter->active = 1;
filter->filterOthers = 0;
filter->priv = 0;
filter->filter = _XkbFilterRedirectKey;
filter->upAction = *pAction;
ev.type = ET_KeyPress;
ev.detail.key = pAction->redirect.new_key;
2003-11-14 16:54:54 +01:00
mask= XkbSARedirectVModsMask(&pAction->redirect);
mods= XkbSARedirectVMods(&pAction->redirect);
if (mask) XkbVirtualModsToReal(xkbi->desc,mask,&mask);
if (mods) XkbVirtualModsToReal(xkbi->desc,mods,&mods);
mask|= pAction->redirect.mods_mask;
mods|= pAction->redirect.mods;
2003-11-14 16:54:54 +01:00
if ( mask || mods ) {
old= xkbi->state;
xkbi->state.base_mods&= ~mask;
xkbi->state.base_mods|= (mods&mask);
xkbi->state.latched_mods&= ~mask;
xkbi->state.latched_mods|= (mods&mask);
xkbi->state.locked_mods&= ~mask;
xkbi->state.locked_mods|= (mods&mask);
XkbComputeDerivedState(xkbi);
}
UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc);
xkbi->device->public.processInputProc((InternalEvent*)&ev, xkbi->device);
COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr,
backupproc,xkbUnwrapProc);
2003-11-14 16:54:54 +01:00
if ( mask || mods )
2003-11-14 16:54:54 +01:00
xkbi->state= old;
}
else if (filter->keycode==keycode) {
ev.type = ET_KeyRelease;
ev.detail.key = filter->upAction.redirect.new_key;
2003-11-14 16:54:54 +01:00
mask= XkbSARedirectVModsMask(&filter->upAction.redirect);
mods= XkbSARedirectVMods(&filter->upAction.redirect);
if (mask) XkbVirtualModsToReal(xkbi->desc,mask,&mask);
if (mods) XkbVirtualModsToReal(xkbi->desc,mods,&mods);
mask|= filter->upAction.redirect.mods_mask;
mods|= filter->upAction.redirect.mods;
2003-11-14 16:54:54 +01:00
if ( mask || mods ) {
old= xkbi->state;
xkbi->state.base_mods&= ~mask;
xkbi->state.base_mods|= (mods&mask);
xkbi->state.latched_mods&= ~mask;
xkbi->state.latched_mods|= (mods&mask);
xkbi->state.locked_mods&= ~mask;
xkbi->state.locked_mods|= (mods&mask);
XkbComputeDerivedState(xkbi);
}
UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc);
xkbi->device->public.processInputProc((InternalEvent*)&ev, xkbi->device);
COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr,
backupproc,xkbUnwrapProc);
2003-11-14 16:54:54 +01:00
if ( mask || mods )
2003-11-14 16:54:54 +01:00
xkbi->state= old;
filter->keycode= 0;
filter->active= 0;
}
return 0;
2003-11-14 17:49:22 +01:00
}
static int
_XkbFilterSwitchScreen( XkbSrvInfoPtr xkbi,
XkbFilterPtr filter,
unsigned keycode,
XkbAction * pAction)
{
DeviceIntPtr dev = xkbi->device;
if (dev == inputInfo.keyboard)
return 0;
2003-11-14 17:49:22 +01:00
if (filter->keycode==0) { /* initial press */
filter->keycode = keycode;
filter->active = 1;
filter->filterOthers = 0;
filter->filter = _XkbFilterSwitchScreen;
AccessXCancelRepeatKey(xkbi, keycode);
XkbDDXSwitchScreen(dev,keycode,pAction);
return 0;
}
else if (filter->keycode==keycode) {
filter->active= 0;
return 0;
}
return 1;
}
static int
_XkbFilterXF86Private( XkbSrvInfoPtr xkbi,
XkbFilterPtr filter,
unsigned keycode,
XkbAction * pAction)
{
DeviceIntPtr dev = xkbi->device;
if (dev == inputInfo.keyboard)
return 0;
2003-11-14 17:49:22 +01:00
if (filter->keycode==0) { /* initial press */
filter->keycode = keycode;
filter->active = 1;
filter->filterOthers = 0;
filter->filter = _XkbFilterXF86Private;
XkbDDXPrivate(dev,keycode,pAction);
return 0;
}
else if (filter->keycode==keycode) {
filter->active= 0;
return 0;
}
return 1;
2003-11-14 16:54:54 +01:00
}
static int
_XkbFilterDeviceBtn( XkbSrvInfoPtr xkbi,
XkbFilterPtr filter,
unsigned keycode,
XkbAction * pAction)
{
DeviceIntPtr dev;
int button;
if (xkbi->device == inputInfo.keyboard)
return 0;
2003-11-14 16:54:54 +01:00
if (filter->keycode==0) { /* initial press */
_XkbLookupButtonDevice(&dev, pAction->devbtn.device, serverClient,
DixUnknownAccess, &button);
if (!dev || !dev->public.on)
2003-11-14 16:54:54 +01:00
return 1;
button= pAction->devbtn.button;
if ((button<1)||(button>dev->button->numButtons))
return 1;
filter->keycode = keycode;
filter->active = 1;
filter->filterOthers = 0;
filter->priv=0;
filter->filter = _XkbFilterDeviceBtn;
filter->upAction= *pAction;
switch (pAction->type) {
case XkbSA_LockDeviceBtn:
if ((pAction->devbtn.flags&XkbSA_LockNoLock)||
BitIsOn(dev->button->down, button))
2003-11-14 16:54:54 +01:00
return 0;
XkbFakeDeviceButton(dev,TRUE,button);
2003-11-14 16:54:54 +01:00
filter->upAction.type= XkbSA_NoAction;
break;
case XkbSA_DeviceBtn:
if (pAction->devbtn.count>0) {
int nClicks,i;
nClicks= pAction->btn.count;
for (i=0;i<nClicks;i++) {
XkbFakeDeviceButton(dev,TRUE,button);
XkbFakeDeviceButton(dev,FALSE,button);
2003-11-14 16:54:54 +01:00
}
filter->upAction.type= XkbSA_NoAction;
}
else XkbFakeDeviceButton(dev,TRUE,button);
2003-11-14 16:54:54 +01:00
break;
}
}
else if (filter->keycode==keycode) {
int button;
filter->active= 0;
_XkbLookupButtonDevice(&dev, filter->upAction.devbtn.device,
serverClient, DixUnknownAccess, &button);
if (!dev || !dev->public.on)
2003-11-14 16:54:54 +01:00
return 1;
button= filter->upAction.btn.button;
switch (filter->upAction.type) {
case XkbSA_LockDeviceBtn:
if ((filter->upAction.devbtn.flags&XkbSA_LockNoUnlock)||
!BitIsOn(dev->button->down, button))
2003-11-14 16:54:54 +01:00
return 0;
XkbFakeDeviceButton(dev,FALSE,button);
2003-11-14 16:54:54 +01:00
break;
case XkbSA_DeviceBtn:
XkbFakeDeviceButton(dev,FALSE,button);
2003-11-14 16:54:54 +01:00
break;
}
filter->active = 0;
}
return 0;
}
static XkbFilterPtr
_XkbNextFreeFilter(
XkbSrvInfoPtr xkbi
2003-11-14 16:54:54 +01:00
)
{
register int i;
if (xkbi->szFilters==0) {
xkbi->szFilters = 4;
xkbi->filters = calloc(xkbi->szFilters, sizeof(XkbFilterRec));
2003-11-14 16:54:54 +01:00
/* 6/21/93 (ef) -- XXX! deal with allocation failure */
}
for (i=0;i<xkbi->szFilters;i++) {
if (!xkbi->filters[i].active) {
xkbi->filters[i].keycode = 0;
return &xkbi->filters[i];
2003-11-14 16:54:54 +01:00
}
}
xkbi->szFilters*=2;
xkbi->filters= realloc(xkbi->filters,
xkbi->szFilters * sizeof(XkbFilterRec));
2003-11-14 16:54:54 +01:00
/* 6/21/93 (ef) -- XXX! deal with allocation failure */
memset(&xkbi->filters[xkbi->szFilters/2], 0,
(xkbi->szFilters/2)*sizeof(XkbFilterRec));
return &xkbi->filters[xkbi->szFilters/2];
2003-11-14 16:54:54 +01:00
}
static int
_XkbApplyFilters(XkbSrvInfoPtr xkbi,unsigned kc,XkbAction *pAction)
{
register int i,send;
send= 1;
for (i=0;i<xkbi->szFilters;i++) {
if ((xkbi->filters[i].active)&&(xkbi->filters[i].filter))
send= ((*xkbi->filters[i].filter)(xkbi,&xkbi->filters[i],kc,pAction)
&& send);
2003-11-14 16:54:54 +01:00
}
return send;
}
void
XkbHandleActions(DeviceIntPtr dev, DeviceIntPtr kbd, DeviceEvent* event)
2003-11-14 16:54:54 +01:00
{
int key,bit,i;
XkbSrvInfoPtr xkbi;
KeyClassPtr keyc;
int changed,sendEvent;
Bool genStateNotify;
XkbAction act;
XkbFilterPtr filter;
Bool keyEvent;
Bool pressEvent;
ProcessInputProc backupproc;
xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(dev);
2003-11-14 16:54:54 +01:00
keyc= kbd->key;
xkbi= keyc->xkbInfo;
key= event->detail.key;
/* The state may change, so if we're not in the middle of sending a state
* notify, prepare for it */
2003-11-14 16:54:54 +01:00
if ((xkbi->flags&_XkbStateNotifyInProgress)==0) {
xkbi->prev_state = xkbi->state;
2003-11-14 16:54:54 +01:00
xkbi->flags|= _XkbStateNotifyInProgress;
genStateNotify= TRUE;
2003-11-14 16:54:54 +01:00
}
else genStateNotify= FALSE;
2003-11-14 16:54:54 +01:00
xkbi->clearMods = xkbi->setMods = 0;
xkbi->groupChange = 0;
sendEvent = 1;
keyEvent= ((event->type == ET_KeyPress) || (event->type == ET_KeyRelease));
pressEvent= ((event->type == ET_KeyPress)|| (event->type == ET_ButtonPress));
2003-11-14 16:54:54 +01:00
if (pressEvent) {
if (keyEvent)
act = XkbGetKeyAction(xkbi,&xkbi->state,key);
else {
act = XkbGetButtonAction(kbd,dev,key);
key|= BTN_ACT_FLAG;
}
sendEvent = _XkbApplyFilters(xkbi,key,&act);
if (sendEvent) {
switch (act.type) {
case XkbSA_SetMods:
case XkbSA_SetGroup:
filter = _XkbNextFreeFilter(xkbi);
2003-11-14 16:54:54 +01:00
sendEvent = _XkbFilterSetState(xkbi,filter,key,&act);
break;
case XkbSA_LatchMods:
case XkbSA_LatchGroup:
filter = _XkbNextFreeFilter(xkbi);
2003-11-14 16:54:54 +01:00
sendEvent=_XkbFilterLatchState(xkbi,filter,key,&act);
break;
case XkbSA_LockMods:
case XkbSA_LockGroup:
filter = _XkbNextFreeFilter(xkbi);
2003-11-14 16:54:54 +01:00
sendEvent=_XkbFilterLockState(xkbi,filter,key,&act);
break;
case XkbSA_ISOLock:
filter = _XkbNextFreeFilter(xkbi);
2003-11-14 16:54:54 +01:00
sendEvent=_XkbFilterISOLock(xkbi,filter,key,&act);
break;
case XkbSA_MovePtr:
filter = _XkbNextFreeFilter(xkbi);
2003-11-14 16:54:54 +01:00
sendEvent= _XkbFilterPointerMove(xkbi,filter,key,&act);
break;
case XkbSA_PtrBtn:
case XkbSA_LockPtrBtn:
case XkbSA_SetPtrDflt:
filter = _XkbNextFreeFilter(xkbi);
2003-11-14 16:54:54 +01:00
sendEvent= _XkbFilterPointerBtn(xkbi,filter,key,&act);
break;
case XkbSA_Terminate:
sendEvent= XkbDDXTerminateServer(dev,key,&act);
break;
case XkbSA_SwitchScreen:
filter = _XkbNextFreeFilter(xkbi);
2003-11-14 17:49:22 +01:00
sendEvent=_XkbFilterSwitchScreen(xkbi,filter,key,&act);
2003-11-14 16:54:54 +01:00
break;
case XkbSA_SetControls:
case XkbSA_LockControls:
filter = _XkbNextFreeFilter(xkbi);
2003-11-14 16:54:54 +01:00
sendEvent=_XkbFilterControls(xkbi,filter,key,&act);
break;
case XkbSA_ActionMessage:
filter = _XkbNextFreeFilter(xkbi);
2003-11-14 16:54:54 +01:00
sendEvent=_XkbFilterActionMessage(xkbi,filter,key,&act);
break;
case XkbSA_RedirectKey:
filter = _XkbNextFreeFilter(xkbi);
2003-11-14 16:54:54 +01:00
sendEvent= _XkbFilterRedirectKey(xkbi,filter,key,&act);
break;
case XkbSA_DeviceBtn:
case XkbSA_LockDeviceBtn:
filter = _XkbNextFreeFilter(xkbi);
2003-11-14 16:54:54 +01:00
sendEvent= _XkbFilterDeviceBtn(xkbi,filter,key,&act);
break;
2003-11-14 17:49:22 +01:00
case XkbSA_XFree86Private:
filter = _XkbNextFreeFilter(xkbi);
2003-11-14 17:49:22 +01:00
sendEvent= _XkbFilterXF86Private(xkbi,filter,key,&act);
break;
2003-11-14 16:54:54 +01:00
}
}
}
else {
if (!keyEvent)
key|= BTN_ACT_FLAG;
sendEvent = _XkbApplyFilters(xkbi,key,NULL);
}
if (xkbi->groupChange!=0)
xkbi->state.base_group+= xkbi->groupChange;
if (xkbi->setMods) {
for (i=0,bit=1; xkbi->setMods; i++,bit<<=1 ) {
if (xkbi->setMods&bit) {
keyc->modifierKeyCount[i]++;
xkbi->state.base_mods|= bit;
xkbi->setMods&= ~bit;
}
}
}
if (xkbi->clearMods) {
for (i=0,bit=1; xkbi->clearMods; i++,bit<<=1 ) {
if (xkbi->clearMods&bit) {
keyc->modifierKeyCount[i]--;
if (keyc->modifierKeyCount[i]<=0) {
xkbi->state.base_mods&= ~bit;
keyc->modifierKeyCount[i] = 0;
}
xkbi->clearMods&= ~bit;
}
}
}
if (sendEvent) {
DeviceIntPtr tmpdev;
if (keyEvent)
tmpdev = dev;
else
tmpdev = GetPairedDevice(dev);
UNWRAP_PROCESS_INPUT_PROC(tmpdev,xkbPrivPtr, backupproc);
dev->public.processInputProc((InternalEvent*)event, tmpdev);
COND_WRAP_PROCESS_INPUT_PROC(tmpdev, xkbPrivPtr,
backupproc,xkbUnwrapProc);
2003-11-14 16:54:54 +01:00
}
else if (keyEvent) {
FixKeyState(event, dev);
}
2003-11-14 17:49:22 +01:00
2003-11-14 16:54:54 +01:00
XkbComputeDerivedState(xkbi);
changed = XkbStateChangedFlags(&xkbi->prev_state,&xkbi->state);
2003-11-14 16:54:54 +01:00
if (genStateNotify) {
if (changed) {
xkbStateNotify sn;
sn.keycode= key;
sn.eventType= event->type;
2003-11-14 16:54:54 +01:00
sn.requestMajor = sn.requestMinor = 0;
sn.changed= changed;
XkbSendStateNotify(dev,&sn);
}
xkbi->flags&= ~_XkbStateNotifyInProgress;
}
changed= XkbIndicatorsToUpdate(dev,changed,FALSE);
2003-11-14 16:54:54 +01:00
if (changed) {
XkbEventCauseRec cause;
XkbSetCauseKey(&cause, key, event->type);
XkbUpdateIndicators(dev,changed,FALSE,NULL,&cause);
2003-11-14 16:54:54 +01:00
}
return;
}
int
2003-11-14 16:54:54 +01:00
XkbLatchModifiers(DeviceIntPtr pXDev,CARD8 mask,CARD8 latches)
{
XkbSrvInfoPtr xkbi;
XkbFilterPtr filter;
XkbAction act;
unsigned clear;
if ( pXDev && pXDev->key && pXDev->key->xkbInfo ) {
xkbi = pXDev->key->xkbInfo;
clear= (mask&(~latches));
xkbi->state.latched_mods&= ~clear;
/* Clear any pending latch to locks.
*/
act.type = XkbSA_NoAction;
_XkbApplyFilters(xkbi,SYNTHETIC_KEYCODE,&act);
act.type = XkbSA_LatchMods;
act.mods.flags = 0;
act.mods.mask = mask&latches;
filter = _XkbNextFreeFilter(xkbi);
2003-11-14 16:54:54 +01:00
_XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,&act);
_XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,(XkbAction *)NULL);
return Success;
}
return BadValue;
}
int
2003-11-14 16:54:54 +01:00
XkbLatchGroup(DeviceIntPtr pXDev,int group)
{
XkbSrvInfoPtr xkbi;
XkbFilterPtr filter;
XkbAction act;
if ( pXDev && pXDev->key && pXDev->key->xkbInfo ) {
xkbi = pXDev->key->xkbInfo;
act.type = XkbSA_LatchGroup;
act.group.flags = 0;
XkbSASetGroup(&act.group,group);
filter = _XkbNextFreeFilter(xkbi);
2003-11-14 16:54:54 +01:00
_XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,&act);
_XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,(XkbAction *)NULL);
return Success;
}
return BadValue;
}
/***====================================================================***/
void
2003-11-14 16:54:54 +01:00
XkbClearAllLatchesAndLocks( DeviceIntPtr dev,
XkbSrvInfoPtr xkbi,
Bool genEv,
XkbEventCausePtr cause)
{
XkbStateRec os;
xkbStateNotify sn;
sn.changed= 0;
os= xkbi->state;
if (os.latched_mods) { /* clear all latches */
XkbLatchModifiers(dev,~0,0);
sn.changed|= XkbModifierLatchMask;
}
if (os.latched_group) {
XkbLatchGroup(dev,0);
sn.changed|= XkbGroupLatchMask;
}
if (os.locked_mods) {
xkbi->state.locked_mods= 0;
sn.changed|= XkbModifierLockMask;
}
if (os.locked_group) {
xkbi->state.locked_group= 0;
sn.changed|= XkbGroupLockMask;
}
if ( genEv && sn.changed) {
CARD32 changed;
XkbComputeDerivedState(xkbi);
sn.keycode= cause->kc;
sn.eventType= cause->event;
sn.requestMajor= cause->mjr;
sn.requestMinor= cause->mnr;
sn.changed= XkbStateChangedFlags(&os,&xkbi->state);
XkbSendStateNotify(dev,&sn);
changed= XkbIndicatorsToUpdate(dev,sn.changed,FALSE);
2003-11-14 16:54:54 +01:00
if (changed) {
XkbUpdateIndicators(dev,changed,TRUE,NULL,cause);
2003-11-14 16:54:54 +01:00
}
}
return;
}
xkb: post-fix PointerKeys button events with a DeviceChangedEvent. commit 14327858391ebe929b806efb53ad79e789361883 xkb: release XTEST pointer buttons on physical releases. (#28808) revealed a bug with the XTEST/PointerKeys interaction. Events resulting from PointerKeys are injected into the event processing stream, not appended to the event queue. The events generated for the fake button press include a DeviceChangedEvent (DCE), a raw button event and the button event itself. The DCE causes the master to switch classes to the attached XTEST pointer device. Once the fake button is processed, normal event processing continues with events in the EQ. The master still contains the XTEST classes, causing some events to be dropped if e.g. the number of valuators of the event in the queue exceeds the XTEST device's number of valuators. Example: the EQ contains the following events, processed one-by-one, left to right. [DCE (dev)][Btn down][Btn up][Motion][Motion][...] ^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up] Thus the event sequence processed looks like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...] The first DCE causes the master to switch to the device. The button up event injects a DCE to the XTEST device, causing the following Motion events to be processed with the master still being on XTEST classes. This patch post-fixes the injected event sequence with a DCE to restore the classes of the original slave device, resulting in an event sequence like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion] Note that this is a simplified description. The event sequence injected by the PointerKeys code is injected for the master device only and the matching slave device that caused the injection has already finished processing on the slave. Furthermore, the injection happens as part of the the XKB layer, before the unwrapping of the processInputProc takes us into the DIX where the DCE is actually handled. Bug reproducible with a device that reports more than 2 valuators. Simply cause button releases on the device and wait for a "too many valuators" warning message. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Daniel Stone <daniel@fooishbar.org> Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
/*
* The event is injected into the event processing, not the EQ. Thus,
* ensure that we restore the master after the event sequence to the
* original set of classes. Otherwise, the master remains on the XTEST
* classes and drops events that don't fit into the XTEST layout (e.g.
* events with more than 2 valuators).
*
* FIXME: EQ injection in the processing stage is not designed for, so this
* is a rather awkward hack. The event list returned by GetPointerEvents()
* and friends is always prefixed with a DCE if the last _posted_ device was
* different. For normal events, this sequence then resets the master during
* the processing stage. Since we inject the PointerKey events in the
* processing stage though, we need to manually reset to restore the
* previous order, because the events already in the EQ must be sent for the
* right device.
* So we post-fix the event list we get from GPE with a DCE back to the
* previous slave device.
*
* First one on drinking island wins!
*/
static void
InjectPointerKeyEvents(DeviceIntPtr dev, int type, int button, int flags, ValuatorMask *mask)
{
xkb: post-fix PointerKeys button events with a DeviceChangedEvent. commit 14327858391ebe929b806efb53ad79e789361883 xkb: release XTEST pointer buttons on physical releases. (#28808) revealed a bug with the XTEST/PointerKeys interaction. Events resulting from PointerKeys are injected into the event processing stream, not appended to the event queue. The events generated for the fake button press include a DeviceChangedEvent (DCE), a raw button event and the button event itself. The DCE causes the master to switch classes to the attached XTEST pointer device. Once the fake button is processed, normal event processing continues with events in the EQ. The master still contains the XTEST classes, causing some events to be dropped if e.g. the number of valuators of the event in the queue exceeds the XTEST device's number of valuators. Example: the EQ contains the following events, processed one-by-one, left to right. [DCE (dev)][Btn down][Btn up][Motion][Motion][...] ^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up] Thus the event sequence processed looks like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...] The first DCE causes the master to switch to the device. The button up event injects a DCE to the XTEST device, causing the following Motion events to be processed with the master still being on XTEST classes. This patch post-fixes the injected event sequence with a DCE to restore the classes of the original slave device, resulting in an event sequence like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion] Note that this is a simplified description. The event sequence injected by the PointerKeys code is injected for the master device only and the matching slave device that caused the injection has already finished processing on the slave. Furthermore, the injection happens as part of the the XKB layer, before the unwrapping of the processInputProc takes us into the DIX where the DCE is actually handled. Bug reproducible with a device that reports more than 2 valuators. Simply cause button releases on the device and wait for a "too many valuators" warning message. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Daniel Stone <daniel@fooishbar.org> Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
ScreenPtr pScreen;
EventListPtr events;
int nevents, i;
DeviceIntPtr ptr, mpointer, lastSlave = NULL;
Bool saveWait;
xkb: post-fix PointerKeys button events with a DeviceChangedEvent. commit 14327858391ebe929b806efb53ad79e789361883 xkb: release XTEST pointer buttons on physical releases. (#28808) revealed a bug with the XTEST/PointerKeys interaction. Events resulting from PointerKeys are injected into the event processing stream, not appended to the event queue. The events generated for the fake button press include a DeviceChangedEvent (DCE), a raw button event and the button event itself. The DCE causes the master to switch classes to the attached XTEST pointer device. Once the fake button is processed, normal event processing continues with events in the EQ. The master still contains the XTEST classes, causing some events to be dropped if e.g. the number of valuators of the event in the queue exceeds the XTEST device's number of valuators. Example: the EQ contains the following events, processed one-by-one, left to right. [DCE (dev)][Btn down][Btn up][Motion][Motion][...] ^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up] Thus the event sequence processed looks like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...] The first DCE causes the master to switch to the device. The button up event injects a DCE to the XTEST device, causing the following Motion events to be processed with the master still being on XTEST classes. This patch post-fixes the injected event sequence with a DCE to restore the classes of the original slave device, resulting in an event sequence like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion] Note that this is a simplified description. The event sequence injected by the PointerKeys code is injected for the master device only and the matching slave device that caused the injection has already finished processing on the slave. Furthermore, the injection happens as part of the the XKB layer, before the unwrapping of the processInputProc takes us into the DIX where the DCE is actually handled. Bug reproducible with a device that reports more than 2 valuators. Simply cause button releases on the device and wait for a "too many valuators" warning message. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Daniel Stone <daniel@fooishbar.org> Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
if (IsMaster(dev)) {
mpointer = GetMaster(dev, MASTER_POINTER);
lastSlave = mpointer->lastSlave;
xkb: post-fix PointerKeys button events with a DeviceChangedEvent. commit 14327858391ebe929b806efb53ad79e789361883 xkb: release XTEST pointer buttons on physical releases. (#28808) revealed a bug with the XTEST/PointerKeys interaction. Events resulting from PointerKeys are injected into the event processing stream, not appended to the event queue. The events generated for the fake button press include a DeviceChangedEvent (DCE), a raw button event and the button event itself. The DCE causes the master to switch classes to the attached XTEST pointer device. Once the fake button is processed, normal event processing continues with events in the EQ. The master still contains the XTEST classes, causing some events to be dropped if e.g. the number of valuators of the event in the queue exceeds the XTEST device's number of valuators. Example: the EQ contains the following events, processed one-by-one, left to right. [DCE (dev)][Btn down][Btn up][Motion][Motion][...] ^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up] Thus the event sequence processed looks like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...] The first DCE causes the master to switch to the device. The button up event injects a DCE to the XTEST device, causing the following Motion events to be processed with the master still being on XTEST classes. This patch post-fixes the injected event sequence with a DCE to restore the classes of the original slave device, resulting in an event sequence like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion] Note that this is a simplified description. The event sequence injected by the PointerKeys code is injected for the master device only and the matching slave device that caused the injection has already finished processing on the slave. Furthermore, the injection happens as part of the the XKB layer, before the unwrapping of the processInputProc takes us into the DIX where the DCE is actually handled. Bug reproducible with a device that reports more than 2 valuators. Simply cause button releases on the device and wait for a "too many valuators" warning message. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Daniel Stone <daniel@fooishbar.org> Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
ptr = GetXTestDevice(mpointer);
} else if (IsFloating(dev))
ptr = dev;
else
return;
xkb: post-fix PointerKeys button events with a DeviceChangedEvent. commit 14327858391ebe929b806efb53ad79e789361883 xkb: release XTEST pointer buttons on physical releases. (#28808) revealed a bug with the XTEST/PointerKeys interaction. Events resulting from PointerKeys are injected into the event processing stream, not appended to the event queue. The events generated for the fake button press include a DeviceChangedEvent (DCE), a raw button event and the button event itself. The DCE causes the master to switch classes to the attached XTEST pointer device. Once the fake button is processed, normal event processing continues with events in the EQ. The master still contains the XTEST classes, causing some events to be dropped if e.g. the number of valuators of the event in the queue exceeds the XTEST device's number of valuators. Example: the EQ contains the following events, processed one-by-one, left to right. [DCE (dev)][Btn down][Btn up][Motion][Motion][...] ^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up] Thus the event sequence processed looks like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...] The first DCE causes the master to switch to the device. The button up event injects a DCE to the XTEST device, causing the following Motion events to be processed with the master still being on XTEST classes. This patch post-fixes the injected event sequence with a DCE to restore the classes of the original slave device, resulting in an event sequence like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion] Note that this is a simplified description. The event sequence injected by the PointerKeys code is injected for the master device only and the matching slave device that caused the injection has already finished processing on the slave. Furthermore, the injection happens as part of the the XKB layer, before the unwrapping of the processInputProc takes us into the DIX where the DCE is actually handled. Bug reproducible with a device that reports more than 2 valuators. Simply cause button releases on the device and wait for a "too many valuators" warning message. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Daniel Stone <daniel@fooishbar.org> Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
events = InitEventList(GetMaximumEventsNum() + 1);
OsBlockSignals();
pScreen = miPointerGetScreen(ptr);
saveWait = miPointerSetWaitForUpdate(pScreen, FALSE);
nevents = GetPointerEvents(events, ptr, type, button, flags, mask);
xkb: post-fix PointerKeys button events with a DeviceChangedEvent. commit 14327858391ebe929b806efb53ad79e789361883 xkb: release XTEST pointer buttons on physical releases. (#28808) revealed a bug with the XTEST/PointerKeys interaction. Events resulting from PointerKeys are injected into the event processing stream, not appended to the event queue. The events generated for the fake button press include a DeviceChangedEvent (DCE), a raw button event and the button event itself. The DCE causes the master to switch classes to the attached XTEST pointer device. Once the fake button is processed, normal event processing continues with events in the EQ. The master still contains the XTEST classes, causing some events to be dropped if e.g. the number of valuators of the event in the queue exceeds the XTEST device's number of valuators. Example: the EQ contains the following events, processed one-by-one, left to right. [DCE (dev)][Btn down][Btn up][Motion][Motion][...] ^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up] Thus the event sequence processed looks like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...] The first DCE causes the master to switch to the device. The button up event injects a DCE to the XTEST device, causing the following Motion events to be processed with the master still being on XTEST classes. This patch post-fixes the injected event sequence with a DCE to restore the classes of the original slave device, resulting in an event sequence like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion] Note that this is a simplified description. The event sequence injected by the PointerKeys code is injected for the master device only and the matching slave device that caused the injection has already finished processing on the slave. Furthermore, the injection happens as part of the the XKB layer, before the unwrapping of the processInputProc takes us into the DIX where the DCE is actually handled. Bug reproducible with a device that reports more than 2 valuators. Simply cause button releases on the device and wait for a "too many valuators" warning message. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Daniel Stone <daniel@fooishbar.org> Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
if (IsMaster(dev) && (lastSlave && lastSlave != ptr))
UpdateFromMaster(&events[nevents], lastSlave, DEVCHANGE_POINTER_EVENT, &nevents);
miPointerSetWaitForUpdate(pScreen, saveWait);
OsReleaseSignals();
for (i = 0; i < nevents; i++)
mieqProcessDeviceEvent(ptr, (InternalEvent*)events[i].event, NULL);
FreeEventList(events, GetMaximumEventsNum());
xkb: post-fix PointerKeys button events with a DeviceChangedEvent. commit 14327858391ebe929b806efb53ad79e789361883 xkb: release XTEST pointer buttons on physical releases. (#28808) revealed a bug with the XTEST/PointerKeys interaction. Events resulting from PointerKeys are injected into the event processing stream, not appended to the event queue. The events generated for the fake button press include a DeviceChangedEvent (DCE), a raw button event and the button event itself. The DCE causes the master to switch classes to the attached XTEST pointer device. Once the fake button is processed, normal event processing continues with events in the EQ. The master still contains the XTEST classes, causing some events to be dropped if e.g. the number of valuators of the event in the queue exceeds the XTEST device's number of valuators. Example: the EQ contains the following events, processed one-by-one, left to right. [DCE (dev)][Btn down][Btn up][Motion][Motion][...] ^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up] Thus the event sequence processed looks like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...] The first DCE causes the master to switch to the device. The button up event injects a DCE to the XTEST device, causing the following Motion events to be processed with the master still being on XTEST classes. This patch post-fixes the injected event sequence with a DCE to restore the classes of the original slave device, resulting in an event sequence like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion] Note that this is a simplified description. The event sequence injected by the PointerKeys code is injected for the master device only and the matching slave device that caused the injection has already finished processing on the slave. Furthermore, the injection happens as part of the the XKB layer, before the unwrapping of the processInputProc takes us into the DIX where the DCE is actually handled. Bug reproducible with a device that reports more than 2 valuators. Simply cause button releases on the device and wait for a "too many valuators" warning message. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Daniel Stone <daniel@fooishbar.org> Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
}
static void
XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y)
{
ValuatorMask mask;
xkb: post-fix PointerKeys button events with a DeviceChangedEvent. commit 14327858391ebe929b806efb53ad79e789361883 xkb: release XTEST pointer buttons on physical releases. (#28808) revealed a bug with the XTEST/PointerKeys interaction. Events resulting from PointerKeys are injected into the event processing stream, not appended to the event queue. The events generated for the fake button press include a DeviceChangedEvent (DCE), a raw button event and the button event itself. The DCE causes the master to switch classes to the attached XTEST pointer device. Once the fake button is processed, normal event processing continues with events in the EQ. The master still contains the XTEST classes, causing some events to be dropped if e.g. the number of valuators of the event in the queue exceeds the XTEST device's number of valuators. Example: the EQ contains the following events, processed one-by-one, left to right. [DCE (dev)][Btn down][Btn up][Motion][Motion][...] ^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up] Thus the event sequence processed looks like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...] The first DCE causes the master to switch to the device. The button up event injects a DCE to the XTEST device, causing the following Motion events to be processed with the master still being on XTEST classes. This patch post-fixes the injected event sequence with a DCE to restore the classes of the original slave device, resulting in an event sequence like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion] Note that this is a simplified description. The event sequence injected by the PointerKeys code is injected for the master device only and the matching slave device that caused the injection has already finished processing on the slave. Furthermore, the injection happens as part of the the XKB layer, before the unwrapping of the processInputProc takes us into the DIX where the DCE is actually handled. Bug reproducible with a device that reports more than 2 valuators. Simply cause button releases on the device and wait for a "too many valuators" warning message. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Daniel Stone <daniel@fooishbar.org> Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
int gpe_flags = 0;
/* ignore attached SDs */
if (!IsMaster(dev) && !IsFloating(dev))
xkb: post-fix PointerKeys button events with a DeviceChangedEvent. commit 14327858391ebe929b806efb53ad79e789361883 xkb: release XTEST pointer buttons on physical releases. (#28808) revealed a bug with the XTEST/PointerKeys interaction. Events resulting from PointerKeys are injected into the event processing stream, not appended to the event queue. The events generated for the fake button press include a DeviceChangedEvent (DCE), a raw button event and the button event itself. The DCE causes the master to switch classes to the attached XTEST pointer device. Once the fake button is processed, normal event processing continues with events in the EQ. The master still contains the XTEST classes, causing some events to be dropped if e.g. the number of valuators of the event in the queue exceeds the XTEST device's number of valuators. Example: the EQ contains the following events, processed one-by-one, left to right. [DCE (dev)][Btn down][Btn up][Motion][Motion][...] ^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up] Thus the event sequence processed looks like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...] The first DCE causes the master to switch to the device. The button up event injects a DCE to the XTEST device, causing the following Motion events to be processed with the master still being on XTEST classes. This patch post-fixes the injected event sequence with a DCE to restore the classes of the original slave device, resulting in an event sequence like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion] Note that this is a simplified description. The event sequence injected by the PointerKeys code is injected for the master device only and the matching slave device that caused the injection has already finished processing on the slave. Furthermore, the injection happens as part of the the XKB layer, before the unwrapping of the processInputProc takes us into the DIX where the DCE is actually handled. Bug reproducible with a device that reports more than 2 valuators. Simply cause button releases on the device and wait for a "too many valuators" warning message. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Daniel Stone <daniel@fooishbar.org> Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
return;
if (flags & XkbSA_MoveAbsoluteX || flags & XkbSA_MoveAbsoluteY)
gpe_flags = POINTER_ABSOLUTE;
else
gpe_flags = POINTER_RELATIVE;
valuator_mask_set_range(&mask, 0, 2, (int[]){x, y});
InjectPointerKeyEvents(dev, MotionNotify, 0, gpe_flags, &mask);
}
void
XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button)
{
DeviceIntPtr ptr;
int down;
/* If dev is a slave device, and the SD is attached, do nothing. If we'd
* post through the attached master pointer we'd get duplicate events.
*
* if dev is a master keyboard, post through the XTEST device
*
* if dev is a floating slave, post through the device itself.
*/
xkb: post-fix PointerKeys button events with a DeviceChangedEvent. commit 14327858391ebe929b806efb53ad79e789361883 xkb: release XTEST pointer buttons on physical releases. (#28808) revealed a bug with the XTEST/PointerKeys interaction. Events resulting from PointerKeys are injected into the event processing stream, not appended to the event queue. The events generated for the fake button press include a DeviceChangedEvent (DCE), a raw button event and the button event itself. The DCE causes the master to switch classes to the attached XTEST pointer device. Once the fake button is processed, normal event processing continues with events in the EQ. The master still contains the XTEST classes, causing some events to be dropped if e.g. the number of valuators of the event in the queue exceeds the XTEST device's number of valuators. Example: the EQ contains the following events, processed one-by-one, left to right. [DCE (dev)][Btn down][Btn up][Motion][Motion][...] ^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up] Thus the event sequence processed looks like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...] The first DCE causes the master to switch to the device. The button up event injects a DCE to the XTEST device, causing the following Motion events to be processed with the master still being on XTEST classes. This patch post-fixes the injected event sequence with a DCE to restore the classes of the original slave device, resulting in an event sequence like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion] Note that this is a simplified description. The event sequence injected by the PointerKeys code is injected for the master device only and the matching slave device that caused the injection has already finished processing on the slave. Furthermore, the injection happens as part of the the XKB layer, before the unwrapping of the processInputProc takes us into the DIX where the DCE is actually handled. Bug reproducible with a device that reports more than 2 valuators. Simply cause button releases on the device and wait for a "too many valuators" warning message. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Daniel Stone <daniel@fooishbar.org> Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
if (IsMaster(dev)) {
DeviceIntPtr mpointer = GetMaster(dev, MASTER_POINTER);
ptr = GetXTestDevice(mpointer);
} else if (IsFloating(dev))
ptr = dev;
else
return;
down = button_is_down(ptr, button, BUTTON_PROCESSED);
if (press == down)
return;
xkb: post-fix PointerKeys button events with a DeviceChangedEvent. commit 14327858391ebe929b806efb53ad79e789361883 xkb: release XTEST pointer buttons on physical releases. (#28808) revealed a bug with the XTEST/PointerKeys interaction. Events resulting from PointerKeys are injected into the event processing stream, not appended to the event queue. The events generated for the fake button press include a DeviceChangedEvent (DCE), a raw button event and the button event itself. The DCE causes the master to switch classes to the attached XTEST pointer device. Once the fake button is processed, normal event processing continues with events in the EQ. The master still contains the XTEST classes, causing some events to be dropped if e.g. the number of valuators of the event in the queue exceeds the XTEST device's number of valuators. Example: the EQ contains the following events, processed one-by-one, left to right. [DCE (dev)][Btn down][Btn up][Motion][Motion][...] ^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up] Thus the event sequence processed looks like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...] The first DCE causes the master to switch to the device. The button up event injects a DCE to the XTEST device, causing the following Motion events to be processed with the master still being on XTEST classes. This patch post-fixes the injected event sequence with a DCE to restore the classes of the original slave device, resulting in an event sequence like this: [DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion] Note that this is a simplified description. The event sequence injected by the PointerKeys code is injected for the master device only and the matching slave device that caused the injection has already finished processing on the slave. Furthermore, the injection happens as part of the the XKB layer, before the unwrapping of the processInputProc takes us into the DIX where the DCE is actually handled. Bug reproducible with a device that reports more than 2 valuators. Simply cause button releases on the device and wait for a "too many valuators" warning message. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Daniel Stone <daniel@fooishbar.org> Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
InjectPointerKeyEvents(dev, press ? ButtonPress : ButtonRelease,
button, 0, NULL);
}