[PATCH REVISED] xkb: Fix ISOLock
Andreas Wettstein
wettstein509 at solnet.ch
Thu Feb 20 11:49:24 PST 2014
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 <wettstein509 at solnet.ch>
---
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
More information about the xorg-devel
mailing list