[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