This change addresses the following issues, in order of decreasing importance:
- The "affect" flags did not work as they were looked for in the wrong flag byte. - The clearLocks and latchToLock flags from the original actions were not overwritten. As clearLocks is the same bit as NoLock flag, this typically prevented SetMods being turned into LockMods. - Only SetMods/LatchMods actions before the ISOLock action transformed to locks, support for groups, controls and buttons was missing (see comments by ef). - Base modifiers set by LockMods before the ISOLock incorrectly will affect the locked modifiers. - Support for NoLock and NoUnlock was missing. Signed-off-by: Andreas Wettstein <[email protected]> --- xkb/xkbActions.c | 159 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 117 insertions(+), 42 deletions(-) diff --git a/xkb/xkbActions.c b/xkb/xkbActions.c index a3d89c6..acd9110 100644 --- a/xkb/xkbActions.c +++ b/xkb/xkbActions.c @@ -190,6 +190,8 @@ _XkbFilterSetState(XkbSrvInfoPtr xkbi, if (pAction->type == XkbSA_SetMods) { filter->upAction = *pAction; xkbi->setMods = pAction->mods.mask; + /* This is used in case an ISOLock comes up. */ + filter->priv = xkbi->state.locked_mods & pAction->mods.mask; } else { xkbi->groupChange = XkbSAGroup(&pAction->group); @@ -340,12 +342,14 @@ _XkbFilterLatchState(XkbSrvInfoPtr xkbi, else if (pAction && (filter->priv == LATCH_KEY_DOWN)) { /* Latch was broken before it became pending: degrade to a SetMods/SetGroup. */ - if (filter->upAction.type == XkbSA_LatchMods) + if (filter->upAction.type == XkbSA_LatchMods) { filter->upAction.type = XkbSA_SetMods; - else + filter->priv = xkbi->state.locked_mods & filter->upAction.mods.mask; + } else { filter->upAction.type = XkbSA_SetGroup; + filter->priv = 0; + } filter->filter = _XkbFilterSetState; - filter->priv = 0; return filter->filter(xkbi, filter, keycode, pAction); } return 1; @@ -385,6 +389,47 @@ _XkbFilterLockState(XkbSrvInfoPtr xkbi, return 1; } + +static Bool +_XkbTransformActionForISOLock(XkbAction* pAction, + CARD8 flags, CARD8 affect) +{ + switch (pAction->type) { + case XkbSA_SetMods: + case XkbSA_LatchMods: + if (!(affect & XkbSA_ISONoAffectMods)) { + pAction->type = XkbSA_LockMods; + pAction->mods.flags &= ~(XkbSA_ClearLocks | XkbSA_LatchToLock); + pAction->mods.flags |= flags & (XkbSA_LockNoLock | XkbSA_LockNoUnlock); + return 1; + } + break; + case XkbSA_SetGroup: + case XkbSA_LatchGroup: + if (!(affect & XkbSA_ISONoAffectGroup)) { + pAction->type = XkbSA_LockGroup; + pAction->group.flags &= ~(XkbSA_ClearLocks | XkbSA_LatchToLock); + return 1; + } + break; + case XkbSA_PtrBtn: + if (!(affect & XkbSA_ISONoAffectPtr)) { + pAction->type = XkbSA_LockPtrBtn; + pAction->btn.flags |= flags & (XkbSA_LockNoLock | XkbSA_LockNoUnlock); + return 1; + } + break; + case XkbSA_SetControls: + if (!(affect & XkbSA_ISONoAffectCtrls)) { + pAction->type = XkbSA_LockControls; + pAction->ctrls.flags |= flags & (XkbSA_LockNoLock | XkbSA_LockNoUnlock); + return 1; + } + break; + } + return 0; +} + #define ISO_KEY_DOWN 0 #define NO_ISO_LOCK 1 @@ -392,9 +437,12 @@ static int _XkbFilterISOLock(XkbSrvInfoPtr xkbi, XkbFilterPtr filter, unsigned keycode, XkbAction *pAction) { + int i; if (filter->keycode == 0) { /* initial press */ + AccessXCancelRepeatKey(xkbi, keycode); CARD8 flags = pAction->iso.flags; + CARD8 affect = pAction->iso.affect; filter->keycode = keycode; filter->active = 1; @@ -410,15 +458,61 @@ _XkbFilterISOLock(XkbSrvInfoPtr xkbi, 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 */ + + for (i = 0; i < xkbi->szFilters; i++) { + if ((xkbi->filters[i].active) && (xkbi->filters[i].filter)) { + XkbAction *upAction = &xkbi->filters[i].upAction; + unsigned char oldtype = upAction->type; + + if (_XkbTransformActionForISOLock(upAction, flags, affect)) { + switch (oldtype) { + /* Latches cannot occur, as they have been tranformed by their own filter */ + case XkbSA_SetMods: + xkbi->filters[i].filter = _XkbFilterLockState; + if (!(flags & XkbSA_LockNoLock)) + xkbi->state.locked_mods |= upAction->mods.mask; + break; + case XkbSA_SetGroup: + xkbi->filters[i].active = 0; + xkbi->groupChange -= XkbSAGroup(&upAction->group); + xkbi->state.locked_group += XkbSAGroup(&upAction->group); + break; + case XkbSA_PtrBtn: + /* We miss actions with nonzero click count. */ + if (!(xkbi->lockedPtrButtons & (1 << upAction->btn.button)) && + !(flags & XkbSA_LockNoLock)) { + xkbi->lockedPtrButtons |= (1 << upAction->btn.button); + upAction->type = XkbSA_NoAction; + } + /* Unlocking is handled by the already transformed filter. */ + break; + case XkbSA_SetControls: + /** Avoid the NoUnlook handling in _XkbFilterControls, + so the controls to disable on key release are + determined by the new value of priv.*/ + upAction->ctrls.flags &= ~XkbSA_LockNoUnlock; + + if (flags & XkbSA_LockNoUnlock) { + if (!(flags & XkbSA_LockNoLock)) + xkbi->filters[i].priv = 0; + } + else { + /* priv contains the controls that have been + enabled by the SetControl action. From those, + we can obtain the controls that had already been + enabled before. */ + int setByAction = xkbi->filters[i].priv; + int setBefore = XkbActionCtrls(&upAction->ctrls) & ~setByAction; + if (flags & XkbSA_LockNoLock) + xkbi->filters[i].priv = XkbActionCtrls(&upAction->ctrls); + else + xkbi->filters[i].priv = setBefore; + } + break; + } + filter->priv = NO_ISO_LOCK; + } + } } } else if (filter->keycode == keycode) { @@ -433,42 +527,23 @@ _XkbFilterISOLock(XkbSrvInfoPtr xkbi, else { xkbi->clearMods = filter->upAction.iso.mask; xkbi->groupChange = 0; - if (filter->priv == ISO_KEY_DOWN) - xkbi->state.locked_mods ^= filter->upAction.iso.mask; + if (filter->priv == ISO_KEY_DOWN) { + unsigned char common = + xkbi->state.locked_mods & filter->upAction.iso.mask; + if (!(flags & XkbSA_LockNoLock)) + xkbi->state.locked_mods |= filter->upAction.iso.mask; + if (!(flags & XkbSA_LockNoUnlock)) + xkbi->state.locked_mods &= ~common; + } } filter->active = 0; } else if (pAction) { CARD8 flags = filter->upAction.iso.flags; + CARD8 affect = filter->upAction.iso.affect; - 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; - } + if (_XkbTransformActionForISOLock(pAction, flags, affect)) + filter->priv = NO_ISO_LOCK; } return 1; } -- 1.8.3.1 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
