[PATCH 1/3] xkb: Several fixes to ISOLock and a few related changes.

Andreas Wettstein wettstein509 at solnet.ch
Thu Jan 23 11:39:49 PST 2014


Several fixes to ISOLock:
- Use the proper byte to access the "affect" flags.
- When changing a Set/Latch action to a Lock action, also change the
  flags for the action.
- Respect NoLock/NoUnlock.
- Add the missing transformation of actions that occurred before the
  ISOLock was pressed.

Support NoLock/NoUnlock for "Controls".

Output changes:
- support flag "genKeyEvent" flag for message actions.
- Output "affect" flags for control locks, modifier locks, and ISOLock.

Furthermore, prevent autorepeat for Set/Lock actions.  This serves
mainly to reduce the number of cases that can occur in connection with
ISOLock.  Also note that the code did not properly check whether a key
is released, so autorepeat handling was incorrect anyway.

Signed-off-by: Andreas Wettstein <wettstein509 at solnet.ch>
---
 xkb/xkbActions.c | 177 ++++++++++++++++++++++++++++++++++++++++---------------
 xkb/xkbtext.c    |  50 +++++++++++++++-
 2 files changed, 179 insertions(+), 48 deletions(-)

diff --git a/xkb/xkbActions.c b/xkb/xkbActions.c
index e32005c..f726775 100644
--- a/xkb/xkbActions.c
+++ b/xkb/xkbActions.c
@@ -181,6 +181,7 @@ _XkbFilterSetState(XkbSrvInfoPtr xkbi,
                    XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
 {
     if (filter->keycode == 0) { /* initial press */
+        AccessXCancelRepeatKey(xkbi, keycode);
         filter->keycode = keycode;
         filter->active = 1;
         filter->filterOthers = ((pAction->mods.mask & XkbSA_ClearLocks) != 0);
@@ -189,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);
@@ -339,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;
@@ -354,6 +359,9 @@ static int
 _XkbFilterLockState(XkbSrvInfoPtr xkbi,
                     XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
 {
+    if (filter->keycode == 0) /* initial press */
+        AccessXCancelRepeatKey(xkbi, keycode);
+
     if (pAction && (pAction->type == XkbSA_LockGroup)) {
         if (pAction->group.flags & XkbSA_GroupAbsolute)
             xkbi->state.locked_group = XkbSAGroup(&pAction->group);
@@ -381,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
 
@@ -388,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;
@@ -406,15 +458,56 @@ _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:
+                        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) {
@@ -429,42 +522,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;
 }
@@ -635,6 +709,7 @@ _XkbFilterPointerBtn(XkbSrvInfoPtr xkbi,
         }
             break;
         }
+        return 0;
     }
     else if (filter->keycode == keycode) {
         int button = filter->upAction.btn.button;
@@ -660,8 +735,9 @@ _XkbFilterPointerBtn(XkbSrvInfoPtr xkbi,
             break;
         }
         filter->active = 0;
+        return 0;
     }
-    return 0;
+    return 1;
 }
 
 static int
@@ -678,17 +754,26 @@ _XkbFilterControls(XkbSrvInfoPtr xkbi,
     ctrls = xkbi->desc->ctrls;
     old = *ctrls;
     if (filter->keycode == 0) { /* initial press */
+        AccessXCancelRepeatKey(xkbi, keycode);
         filter->keycode = keycode;
         filter->active = 1;
         filter->filterOthers = 0;
-        change = XkbActionCtrls(&pAction->ctrls);
+        change = (XkbActionCtrls(&pAction->ctrls) & ~ctrls->enabled_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 (pAction->ctrls.flags & XkbSA_LockNoUnlock)
+                filter->priv = 0;
+            else
+                /* The protocol specification says we should unlock controls
+                   are NOT currently enabled.  As this does not make any sense,
+                   let's assume this is a typo and do the opposite. */
+                filter->priv = (XkbActionCtrls(&pAction->ctrls) & ctrls->enabled_ctrls);
+
+            if (pAction->ctrls.flags & XkbSA_LockNoLock)
+                change = 0;
         }
 
         if (change) {
diff --git a/xkb/xkbtext.c b/xkb/xkbtext.c
index fdf1d17..fd323bc 100644
--- a/xkb/xkbtext.c
+++ b/xkb/xkbtext.c
@@ -749,8 +749,22 @@ CopyModActionArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
     }
     else
         TryCopyStr(buf, "none", sz);
-    if (act->type == XkbSA_LockMods)
+    if (act->type == XkbSA_LockMods) {
+	switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
+        case XkbSA_LockNoLock:
+            TryCopyStr(buf, ",affect=unlock", sz);
+            break;
+        case XkbSA_LockNoUnlock:
+            TryCopyStr(buf, ",affect=lock", sz);
+            break;
+        case XkbSA_LockNoUnlock|XkbSA_LockNoLock:
+            TryCopyStr(buf, ",affect=neither", sz);
+            break;
+        default:
+            break;
+	}
         return TRUE;
+    }
     if (act->flags & XkbSA_ClearLocks)
         TryCopyStr(buf, ",clearLocks", sz);
     if (act->flags & XkbSA_LatchToLock)
@@ -901,8 +915,12 @@ CopyISOLockArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
             TryCopyStr(buf, "none", sz);
     }
     TryCopyStr(buf, ",affect=", sz);
-    if ((act->affect & XkbSA_ISOAffectMask) == 0)
+    if ((act->affect & XkbSA_ISOAffectMask) == 0) {
         TryCopyStr(buf, "all", sz);
+    }
+    else if ((act->affect & XkbSA_ISOAffectMask) == XkbSA_ISOAffectMask) {
+        TryCopyStr(buf, "none", sz);
+    }
     else {
         int nOut = 0;
 
@@ -926,6 +944,18 @@ CopyISOLockArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
             nOut++;
         }
     }
+    switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
+    case XkbSA_LockNoLock:
+	TryCopyStr(buf, "+unlock", sz);
+        break;
+    case XkbSA_LockNoUnlock:
+	TryCopyStr(buf, "+lock", sz);
+        break;
+    case XkbSA_LockNoUnlock | XkbSA_LockNoLock:
+	TryCopyStr(buf, "+neither", sz);
+        break;
+    default: ;
+    }
     return TRUE;
 }
 
@@ -1037,6 +1067,20 @@ CopySetLockControlsArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
             nOut++;
         }
     }
+    if (action->type == XkbSA_LockControls) {
+	switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
+	case XkbSA_LockNoLock:
+	    TryCopyStr(buf, ",affect=unlock", sz);
+            break;
+	case XkbSA_LockNoUnlock:
+	    TryCopyStr(buf, ",affect=lock", sz);
+            break;
+	case XkbSA_LockNoUnlock | XkbSA_LockNoLock:
+	    TryCopyStr(buf, ",affect=neither", sz);
+            break;
+	default: ;
+	}
+    }
     return TRUE;
 }
 
@@ -1070,6 +1114,8 @@ CopyActionMessageArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
     TryCopyStr(buf, tbuf, sz);
     snprintf(tbuf, sizeof(tbuf), ",data[5]=0x%02x", act->message[5]);
     TryCopyStr(buf, tbuf, sz);
+    if (act->flags & XkbSA_MessageGenKeyEvent)
+	TryCopyStr(buf, ",genKeyEvent", sz);
     return TRUE;
 }
 
-- 
1.8.3.1



More information about the xorg-devel mailing list