diff options
Diffstat (limited to 'xorg-server/xkb/xkbActions.c')
-rw-r--r-- | xorg-server/xkb/xkbActions.c | 1418 |
1 files changed, 1418 insertions, 0 deletions
diff --git a/xorg-server/xkb/xkbActions.c b/xorg-server/xkb/xkbActions.c new file mode 100644 index 000000000..8c72874df --- /dev/null +++ b/xorg-server/xkb/xkbActions.c @@ -0,0 +1,1418 @@ +/************************************************************ +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 + +#include <stdio.h> +#include <math.h> +#define NEED_EVENTS 1 +#include <X11/X.h> +#include <X11/Xproto.h> +#include <X11/keysym.h> +#include "misc.h" +#include "inputstr.h" +#include "exevents.h" +#include <xkbsrv.h> +#include "xkb.h" +#include <ctype.h> +#define EXTENSION_EVENT_BASE 64 + +DevPrivateKey xkbDevicePrivateKey = &xkbDevicePrivateKey; + +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); +} + + +void +XkbSetExtension(DeviceIntPtr device, ProcessInputProc proc) +{ + xkbDeviceInfoPtr xkbPrivPtr; + + xkbPrivPtr = (xkbDeviceInfoPtr) xcalloc(1, sizeof(xkbDeviceInfoRec)); + if (!xkbPrivPtr) + return; + xkbPrivPtr->unwrapProc = NULL; + + dixSetPrivate(&device->devPrivates, xkbDevicePrivateKey, xkbPrivPtr); + WRAP_PROCESS_INPUT_PROC(device, xkbPrivPtr, proc, xkbUnwrapProc); +} + +extern void ProcessOtherEvent( + xEvent * /* xE */, + DeviceIntPtr /* dev */, + int /* count */ +); + +/***====================================================================***/ + +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 (XkbDisableLockActions) { + switch (act->type) { + case XkbSA_LockMods: + fake.mods.type = XkbSA_SetMods; + fake.mods.flags = 0; + fake.mods.mask = act->mods.mask; + return fake; + case XkbSA_LatchMods: + fake.mods.type = XkbSA_SetMods; + fake.mods.flags = 0; + fake.mods.mask = act->mods.mask; + return fake; + case XkbSA_ISOLock: + if (act->iso.flags&XkbSA_ISODfltIsGroup) { + fake.group.type = XkbSA_SetGroup; + fake.group.flags = act->iso.flags&XkbSA_GroupAbsolute; + XkbSASetGroup(&fake.group,XkbSAGroup(&act->iso)); + } + else { + fake.mods.type = XkbSA_SetMods; + fake.mods.flags = 0; + fake.mods.mask = act->iso.mask; + } + return fake; + case XkbSA_LockGroup: + case XkbSA_LatchGroup: + /* We want everything from the latch/lock action except the + * type should be changed to set. + */ + fake = *act; + fake.group.type = XkbSA_SetGroup; + return fake; + } + } + else + 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; + if (!XkbKeyHasActions(xkb,key) || !XkbKeycodeInRange(xkb,key)) { + fake.type = XkbSA_NoAction; + return fake; + } + pActs= XkbKeyActionsPtr(xkb,key); + col= 0; + effectiveGroup= xkbState->group; + if (effectiveGroup!=XkbGroup1Index) { + if (XkbKeyNumGroups(xkb,key)>(unsigned)1) { + if (effectiveGroup>=XkbKeyNumGroups(xkb,key)) { + unsigned gi= XkbKeyGroupInfo(xkb,key); + switch (XkbOutOfRangeGroupAction(gi)) { + default: + case XkbWrapIntoRange: + effectiveGroup %= XkbKeyNumGroups(xkb,key); + break; + case XkbClampIntoRange: + effectiveGroup = XkbKeyNumGroups(xkb,key)-1; + break; + case XkbRedirectIntoRange: + effectiveGroup= XkbOutOfRangeGroupInfo(gi); + if (effectiveGroup>=XkbKeyNumGroups(xkb,key)) + effectiveGroup= 0; + break; + } + } + } + else effectiveGroup= XkbGroup1Index; + col+= (effectiveGroup*XkbKeyGroupsWidth(xkb,key)); + } + 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 +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; + } + XkbDDXFakePointerMotion(xkbi->mouseKeysFlags,dx,dy); + return xkbi->desc->ctrls->mk_interval; +} + +static int +_XkbFilterPointerMove( XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction * pAction) +{ +int x,y; +Bool accel; + + if (xkbi->device == inputInfo.keyboard) + return 0; + + 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); + XkbDDXFakePointerMotion(pAction->ptr.flags,x,y); + AccessXCancelRepeatKey(xkbi,keycode); + xkbi->mouseKeysAccel= accel&& + (xkbi->desc->ctrls->enabled_ctrls&XkbMouseKeysAccelMask); + xkbi->mouseKeysFlags= pAction->ptr.flags; + xkbi->mouseKeysDX= XkbPtrActionX(&pAction->ptr); + xkbi->mouseKeysDY= XkbPtrActionY(&pAction->ptr); + xkbi->mouseKeyTimer= TimerSet(xkbi->mouseKeyTimer, 0, + 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 (xkbi->device == inputInfo.keyboard) + return 0; + + 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); + XkbDDXFakePointerButton(ButtonPress,button); + 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++) { + XkbDDXFakePointerButton(ButtonPress,button); + XkbDDXFakePointerButton(ButtonRelease,button); + } + filter->upAction.type= XkbSA_NoAction; + } + else XkbDDXFakePointerButton(ButtonPress,button); + } + 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)) { + cn.keycode = keycode; + /* XXX: what about DeviceKeyPress? */ + 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); + case XkbSA_PtrBtn: + XkbDDXFakePointerButton(ButtonRelease,button); + 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); + 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)) { + cn.keycode = keycode; + /* XXX: what about DeviceKeyPress? */ + 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); + } + sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0); + XkbUpdateIndicators(kbd,sli->usesControls,True,NULL,&cause); + 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)) { + 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); + } + sli= XkbFindSrvLedInfo(kbd,XkbDfltXIClass,XkbDfltXIId,0); + XkbUpdateIndicators(kbd,sli->usesControls,True,NULL,&cause); + if (XkbAX_NeedFeedback(ctrls,XkbAX_FeatureFBMask)) + XkbDDXAccessXBeep(kbd,_BEEP_FEATURE_OFF,change); + } + filter->keycode= 0; + filter->active= 0; + } + return 1; +} + +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) +{ +unsigned realMods = 0; +xEvent ev; +int x,y; +XkbStateRec old; +unsigned mods,mask,oldCoreState = 0,oldCorePrevState = 0; +xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(xkbi->device); +ProcessInputProc backupproc; + + /* never actually used uninitialised, but gcc isn't smart enough + * to work that out. */ + memset(&old, 0, sizeof(old)); + + if ((filter->keycode!=0)&&(filter->keycode!=keycode)) + return 1; + + GetSpritePosition(&x,&y); + ev.u.keyButtonPointer.time = GetTimeInMillis(); + ev.u.keyButtonPointer.rootX = x; + ev.u.keyButtonPointer.rootY = y; + + 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; + + /* XXX: what about DeviceKeyPress */ + ev.u.u.type = KeyPress; + ev.u.u.detail = pAction->redirect.new_key; + + 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; + + if ( mask || mods ) { + old= xkbi->state; + oldCoreState= xkbi->device->key->state; + oldCorePrevState= xkbi->device->key->prev_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); + xkbi->device->key->state= xkbi->device->key->prev_state= + xkbi->state.mods; + } + + realMods = xkbi->device->key->modifierMap[ev.u.u.detail]; + xkbi->device->key->modifierMap[ev.u.u.detail] = 0; + /* XXX: Bad! Since the switch to XI devices xkbi->device will be the + * XI device. Sending a core event through ProcessOtherEvent will + * cause trouble. Somebody should fix this. + */ + UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc); + xkbi->device->public.processInputProc(&ev,xkbi->device,1); + COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr, + backupproc,xkbUnwrapProc); + xkbi->device->key->modifierMap[ev.u.u.detail] = realMods; + + if ( mask || mods ) { + xkbi->device->key->state= oldCoreState; + xkbi->device->key->prev_state= oldCorePrevState; + xkbi->state= old; + } + } + else if (filter->keycode==keycode) { + + /* XXX: what about DeviceKeyRelease */ + ev.u.u.type = KeyRelease; + ev.u.u.detail = filter->upAction.redirect.new_key; + + 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; + + if ( mask || mods ) { + old= xkbi->state; + oldCoreState= xkbi->device->key->state; + oldCorePrevState= xkbi->device->key->prev_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); + xkbi->device->key->state= xkbi->device->key->prev_state= + xkbi->state.mods; + } + + realMods = xkbi->device->key->modifierMap[ev.u.u.detail]; + xkbi->device->key->modifierMap[ev.u.u.detail] = 0; + /* XXX: Bad! Since the switch to XI devices xkbi->device will be the + * XI device. Sending a core event through ProcessOtherEvent will + * cause trouble. Somebody should fix this. + */ + UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc); + xkbi->device->public.processInputProc(&ev,xkbi->device,1); + COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr, + backupproc,xkbUnwrapProc); + xkbi->device->key->modifierMap[ev.u.u.detail] = realMods; + + if ( mask || mods ) { + xkbi->device->key->state= oldCoreState; + xkbi->device->key->prev_state= oldCorePrevState; + xkbi->state= old; + } + + filter->keycode= 0; + filter->active= 0; + } + return 0; +} + +static int +_XkbFilterSwitchScreen( XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction * pAction) +{ + DeviceIntPtr dev = xkbi->device; + if (dev == inputInfo.keyboard) + return 0; + + 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; + + 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; +} + + +static int +_XkbFilterDeviceBtn( XkbSrvInfoPtr xkbi, + XkbFilterPtr filter, + unsigned keycode, + XkbAction * pAction) +{ +DeviceIntPtr dev; +int button; + + if (dev == inputInfo.keyboard) + return 0; + + if (filter->keycode==0) { /* initial press */ + _XkbLookupButtonDevice(&dev, pAction->devbtn.device, serverClient, + DixUnknownAccess, &button); + if (!dev || !dev->public.on || dev == inputInfo.pointer) + 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)|| + (dev->button->down[button/8]&(1L<<(button%8)))) + return 0; + XkbDDXFakeDeviceButton(dev,True,button); + 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++) { + XkbDDXFakeDeviceButton(dev,True,button); + XkbDDXFakeDeviceButton(dev,False,button); + } + filter->upAction.type= XkbSA_NoAction; + } + else XkbDDXFakeDeviceButton(dev,True,button); + 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 || dev == inputInfo.pointer) + return 1; + + button= filter->upAction.btn.button; + switch (filter->upAction.type) { + case XkbSA_LockDeviceBtn: + if ((filter->upAction.devbtn.flags&XkbSA_LockNoUnlock)|| + ((dev->button->down[button/8]&(1L<<(button%8)))==0)) + return 0; + XkbDDXFakeDeviceButton(dev,False,button); + break; + case XkbSA_DeviceBtn: + XkbDDXFakeDeviceButton(dev,False,button); + break; + } + filter->active = 0; + } + return 0; +} + +static XkbFilterPtr +_XkbNextFreeFilter( + XkbSrvInfoPtr xkbi +) +{ +register int i; + + if (xkbi->szFilters==0) { + xkbi->szFilters = 4; + xkbi->filters = _XkbTypedCalloc(xkbi->szFilters,XkbFilterRec); + /* 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]; + } + } + xkbi->szFilters*=2; + xkbi->filters= _XkbTypedRealloc(xkbi->filters, + xkbi->szFilters, + XkbFilterRec); + /* 6/21/93 (ef) -- XXX! deal with allocation failure */ + bzero(&xkbi->filters[xkbi->szFilters/2], + (xkbi->szFilters/2)*sizeof(XkbFilterRec)); + return &xkbi->filters[xkbi->szFilters/2]; +} + +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); + } + return send; +} + +void +XkbHandleActions(DeviceIntPtr dev,DeviceIntPtr kbd,xEvent *xE,int count) +{ +int key,bit,i; +CARD8 realMods = 0; +XkbSrvInfoPtr xkbi; +KeyClassPtr keyc; +int changed,sendEvent; +Bool genStateNotify; +XkbStateRec oldState; +XkbAction act; +XkbFilterPtr filter; +Bool keyEvent; +Bool pressEvent; +ProcessInputProc backupproc; + +xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(dev); + + keyc= kbd->key; + xkbi= keyc->xkbInfo; + key= xE->u.u.detail; + /* The state may change, so if we're not in the middle of sending a state + * notify, prepare for it */ + if ((xkbi->flags&_XkbStateNotifyInProgress)==0) { + oldState= xkbi->state; + xkbi->flags|= _XkbStateNotifyInProgress; + genStateNotify= True; + } + else genStateNotify= False; + + xkbi->clearMods = xkbi->setMods = 0; + xkbi->groupChange = 0; + + sendEvent = 1; + keyEvent= ((xE->u.u.type==KeyPress)||(xE->u.u.type==DeviceKeyPress)|| + (xE->u.u.type==KeyRelease)||(xE->u.u.type==DeviceKeyRelease)); + pressEvent= (xE->u.u.type==KeyPress)||(xE->u.u.type==DeviceKeyPress)|| + (xE->u.u.type==ButtonPress)||(xE->u.u.type==DeviceButtonPress); + + 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); + sendEvent = _XkbFilterSetState(xkbi,filter,key,&act); + break; + case XkbSA_LatchMods: + case XkbSA_LatchGroup: + filter = _XkbNextFreeFilter(xkbi); + sendEvent=_XkbFilterLatchState(xkbi,filter,key,&act); + break; + case XkbSA_LockMods: + case XkbSA_LockGroup: + filter = _XkbNextFreeFilter(xkbi); + sendEvent=_XkbFilterLockState(xkbi,filter,key,&act); + break; + case XkbSA_ISOLock: + filter = _XkbNextFreeFilter(xkbi); + sendEvent=_XkbFilterISOLock(xkbi,filter,key,&act); + break; + case XkbSA_MovePtr: + filter = _XkbNextFreeFilter(xkbi); + sendEvent= _XkbFilterPointerMove(xkbi,filter,key,&act); + break; + case XkbSA_PtrBtn: + case XkbSA_LockPtrBtn: + case XkbSA_SetPtrDflt: + filter = _XkbNextFreeFilter(xkbi); + sendEvent= _XkbFilterPointerBtn(xkbi,filter,key,&act); + break; + case XkbSA_Terminate: + sendEvent= XkbDDXTerminateServer(dev,key,&act); + break; + case XkbSA_SwitchScreen: + filter = _XkbNextFreeFilter(xkbi); + sendEvent=_XkbFilterSwitchScreen(xkbi,filter,key,&act); + break; + case XkbSA_SetControls: + case XkbSA_LockControls: + filter = _XkbNextFreeFilter(xkbi); + sendEvent=_XkbFilterControls(xkbi,filter,key,&act); + break; + case XkbSA_ActionMessage: + filter = _XkbNextFreeFilter(xkbi); + sendEvent=_XkbFilterActionMessage(xkbi,filter,key,&act); + break; + case XkbSA_RedirectKey: + filter = _XkbNextFreeFilter(xkbi); + sendEvent= _XkbFilterRedirectKey(xkbi,filter,key,&act); + break; + case XkbSA_DeviceBtn: + case XkbSA_LockDeviceBtn: + filter = _XkbNextFreeFilter(xkbi); + sendEvent= _XkbFilterDeviceBtn(xkbi,filter,key,&act); + break; + case XkbSA_XFree86Private: + filter = _XkbNextFreeFilter(xkbi); + sendEvent= _XkbFilterXF86Private(xkbi,filter,key,&act); + break; + } + } + } + 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) { + if (keyEvent) { + realMods = keyc->modifierMap[key]; + keyc->modifierMap[key] = 0; + } + + UNWRAP_PROCESS_INPUT_PROC(dev,xkbPrivPtr, backupproc); + dev->public.processInputProc(xE,dev,count); + COND_WRAP_PROCESS_INPUT_PROC(dev, xkbPrivPtr, + backupproc,xkbUnwrapProc); + if (keyEvent) + keyc->modifierMap[key] = realMods; + } + else if (keyEvent) { + FixKeyState(xE,dev); + } + + xkbi->prev_state= oldState; + XkbComputeDerivedState(xkbi); + keyc->prev_state= keyc->state; + keyc->state= XkbStateFieldFromRec(&xkbi->state); + changed = XkbStateChangedFlags(&oldState,&xkbi->state); + if (genStateNotify) { + if (changed) { + xkbStateNotify sn; + sn.keycode= key; + sn.eventType= xE->u.u.type; + sn.requestMajor = sn.requestMinor = 0; + sn.changed= changed; + XkbSendStateNotify(dev,&sn); + } + xkbi->flags&= ~_XkbStateNotifyInProgress; + } + changed= XkbIndicatorsToUpdate(dev,changed,False); + if (changed) { + XkbEventCauseRec cause; + XkbSetCauseKey(&cause,key,xE->u.u.type); + XkbUpdateIndicators(dev,changed,False,NULL,&cause); + } + return; +} + +int +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); + _XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,&act); + _XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,(XkbAction *)NULL); + return Success; + } + return BadValue; +} + +int +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); + _XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,&act); + _XkbFilterLatchState(xkbi,filter,SYNTHETIC_KEYCODE,(XkbAction *)NULL); + return Success; + } + return BadValue; +} + +/***====================================================================***/ + +void +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); + if (changed) { + XkbUpdateIndicators(dev,changed,True,NULL,cause); + } + } + return; +} + |