tizen 2.4 release
[framework/uifw/xorg/server/xorg-server.git] / xkb / xkbActions.c
index c020444..7c286e4 100644 (file)
@@ -42,133 +42,133 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <ctype.h>
 #include "mi.h"
 #include "mipointer.h"
+#include "inpututils.h"
 #define EXTENSION_EVENT_BASE 64
 
 DevPrivateKeyRec xkbDevicePrivateKeyRec;
 
-void XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button);
-static void XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y);
+static void XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags, int x,
+                                 int y);
 
 void
-xkbUnwrapProc(DeviceIntPtr device, DeviceHandleProc proc,
-                   pointer data)
+xkbUnwrapProc(DeviceIntPtr device, DeviceHandleProc proc, void *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);
+    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);
 }
 
 Bool
 XkbInitPrivates(void)
 {
-    return dixRegisterPrivateKey(&xkbDevicePrivateKeyRec, PRIVATE_DEVICE, 0);
+    return dixRegisterPrivateKey(&xkbDevicePrivateKeyRec, PRIVATE_DEVICE,
+                                 sizeof(xkbDeviceInfoRec));
 }
 
 void
 XkbSetExtension(DeviceIntPtr device, ProcessInputProc proc)
 {
-    xkbDeviceInfoPtr xkbPrivPtr;
-
-    xkbPrivPtr = (xkbDeviceInfoPtr) calloc(1, sizeof(xkbDeviceInfoRec));
-    if (!xkbPrivPtr)
-       return;
-    xkbPrivPtr->unwrapProc = NULL;
+    xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(device);
 
-    dixSetPrivate(&device->devPrivates, xkbDevicePrivateKey, xkbPrivPtr);
     WRAP_PROCESS_INPUT_PROC(device, xkbPrivPtr, proc, xkbUnwrapProc);
 }
 
 /***====================================================================***/
 
 static XkbAction
-_FixUpAction(XkbDescPtr xkb,XkbAction *act)
+_FixUpAction(XkbDescPtr xkb, XkbAction *act)
 {
-static XkbAction       fake;
+    static XkbAction fake;
 
-    if (XkbIsPtrAction(act)&&(!(xkb->ctrls->enabled_ctrls&XkbMouseKeysMask))) {
-       fake.type = XkbSA_NoAction;
-       return fake;
+    if (XkbIsPtrAction(act) &&
+        (!(xkb->ctrls->enabled_ctrls & XkbMouseKeysMask))) {
+        fake.type = XkbSA_NoAction;
+        return fake;
     }
-    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;
-       }
+    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)
+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;
+    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;
+    pActs = XkbKeyActionsPtr(xkb, key);
+    col = 0;
 
     effectiveGroup = XkbGetEffectiveGroup(xkbi, xkbState, key);
     if (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;
-           }
-       }
+    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]);
+    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)
+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;
+    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;
 }
 
 /***====================================================================***/
@@ -177,188 +177,206 @@ XkbAction fake;
 #define        BTN_ACT_FLAG            0x100
 
 static int
-_XkbFilterSetState(    XkbSrvInfoPtr   xkbi,
-                       XkbFilterPtr    filter,
-                       unsigned        keycode,
-                       XkbAction *pAction)
+_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);
-       }
+    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 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;
+        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)
+_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);
-       }
+    if (filter->keycode == 0) { /* initial press */
+        AccessXCancelRepeatKey(xkbi,keycode);
+        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 (pAction && (filter->priv == LATCH_PENDING)) {
+        if (((1 << pAction->type) & XkbSA_BreakLatch) != 0) {
+            filter->active = 0;
+            /* If one latch is broken, all latches are broken, so it's no use
+               to find out which particular latch this filter tracks. */
+            xkbi->state.latched_mods = 0;
+            xkbi->state.latched_group = 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->keycode == keycode && filter->priv != LATCH_PENDING){
+        /* The test above for LATCH_PENDING skips subsequent releases of the
+           key after it has been released first time and the latch became
+           pending. */
+        XkbControlsPtr ctrls = xkbi->desc->ctrls;
+        int needBeep = ((ctrls->enabled_ctrls & XkbStickyKeysMask) &&
+                        XkbAX_NeedFeedback(ctrls, XkbAX_StickyKeysFBMask));
+
+        if (filter->upAction.type == XkbSA_LatchMods) {
+            unsigned char mask = filter->upAction.mods.mask;
+            unsigned char common;
+
+            xkbi->clearMods = mask;
+
+            /* ClearLocks */
+            common = mask & xkbi->state.locked_mods;
+            if ((filter->upAction.mods.flags & XkbSA_ClearLocks) && common) {
+                mask &= ~common;
+                xkbi->state.locked_mods &= ~common;
+                if (needBeep)
+                    XkbDDXAccessXBeep(xkbi->device, _BEEP_STICKY_UNLOCK,
+                                      XkbStickyKeysMask);
+            }
+            /* LatchToLock */
+            common = mask & xkbi->state.latched_mods;
+            if ((filter->upAction.mods.flags & XkbSA_LatchToLock) && common) {
+                unsigned char newlocked;
+
+                mask &= ~common;
+                newlocked = common & ~xkbi->state.locked_mods;
+                if(newlocked){
+                    xkbi->state.locked_mods |= newlocked;
+                    if (needBeep)
+                        XkbDDXAccessXBeep(xkbi->device, _BEEP_STICKY_LOCK,
+                                          XkbStickyKeysMask);
+
+                }
+                xkbi->state.latched_mods &= ~common;
+            }
+            /* Latch remaining modifiers, if any. */
+            if (mask) {
+                xkbi->state.latched_mods |= mask;
+                filter->priv = LATCH_PENDING;
+                if (needBeep)
+                    XkbDDXAccessXBeep(xkbi->device, _BEEP_STICKY_LATCH,
+                                      XkbStickyKeysMask);
+            }
+        }
+        else {
+            xkbi->groupChange = -XkbSAGroup(&filter->upAction.group);
+            /* ClearLocks */
+            if ((filter->upAction.group.flags & XkbSA_ClearLocks) &&
+                (xkbi->state.locked_group)) {
+                xkbi->state.locked_group = 0;
+                if (needBeep)
+                    XkbDDXAccessXBeep(xkbi->device, _BEEP_STICKY_UNLOCK,
+                                      XkbStickyKeysMask);
+            }
+            /* LatchToLock */
+            else if ((filter->upAction.group.flags & XkbSA_LatchToLock)
+                     && (xkbi->state.latched_group)) {
+                xkbi->state.locked_group  += XkbSAGroup(&filter->upAction.group);
+                xkbi->state.latched_group -= XkbSAGroup(&filter->upAction.group);
+                if(XkbSAGroup(&filter->upAction.group) && needBeep)
+                    XkbDDXAccessXBeep(xkbi->device, _BEEP_STICKY_LOCK,
+                                      XkbStickyKeysMask);
+            }
+            /* Latch group */
+            else if(XkbSAGroup(&filter->upAction.group)){
+                xkbi->state.latched_group += XkbSAGroup(&filter->upAction.group);
+                filter->priv = LATCH_PENDING;
+                if (needBeep)
+                    XkbDDXAccessXBeep(xkbi->device, _BEEP_STICKY_LATCH,
+                                      XkbStickyKeysMask);
+            }
+        }
+
+        if (filter->priv != LATCH_PENDING)
+            filter->active = 0;
     }
-    else if (filter->priv==LATCH_KEY_DOWN) {
-       filter->priv= NO_LATCH;
-       filter->filterOthers = 0;
+    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)
+            filter->upAction.type = XkbSA_SetMods;
+        else
+            filter->upAction.type = XkbSA_SetGroup;
+        filter->filter = _XkbFilterSetState;
+        filter->priv = 0;
+        return filter->filter(xkbi, filter, keycode, pAction);
     }
     return 1;
 }
 
 static int
-_XkbFilterLockState(   XkbSrvInfoPtr   xkbi,
-                       XkbFilterPtr    filter,
-                       unsigned        keycode,
-                       XkbAction *     pAction)
+_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 (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;
+    if (filter->keycode == 0) { /* initial press */
+        filter->keycode = keycode;
+        filter->active = 1;
+        filter->filterOthers = 0;
+        filter->priv = xkbi->state.locked_mods & pAction->mods.mask;
+        filter->filter = _XkbFilterLockState;
+        filter->upAction = *pAction;
+        if (!(filter->upAction.mods.flags & XkbSA_LockNoLock))
+            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;
+    else if (filter->keycode == keycode) {
+        filter->active = 0;
+        xkbi->clearMods = filter->upAction.mods.mask;
+        if (!(filter->upAction.mods.flags & XkbSA_LockNoUnlock))
+            xkbi->state.locked_mods &= ~filter->priv;
     }
     return 1;
 }
@@ -367,921 +385,1015 @@ _XkbFilterLockState(   XkbSrvInfoPtr   xkbi,
 #define        NO_ISO_LOCK             1
 
 static int
-_XkbFilterISOLock(     XkbSrvInfoPtr   xkbi,
-                       XkbFilterPtr    filter,
-                       unsigned        keycode,
-                       XkbAction *     pAction)
+_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)) {
+    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)) {
+        }
+        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 (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;
-       }
+        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)
+_XkbPtrAccelExpire(OsTimerPtr timer, CARD32 now, void *arg)
 {
-XkbSrvInfoPtr  xkbi= (XkbSrvInfoPtr)arg;
-XkbControlsPtr ctrls= xkbi->desc->ctrls;
-int            dx,dy;
+    XkbSrvInfoPtr xkbi = (XkbSrvInfoPtr) arg;
+    XkbControlsPtr ctrls = xkbi->desc->ctrls;
+    int dx, dy;
 
-    if (xkbi->mouseKey==0)
-       return 0;
+    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;
+        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;
+        dx = xkbi->mouseKeysDX;
+        dy = xkbi->mouseKeysDY;
     }
-    XkbFakePointerMotion(xkbi->device, xkbi->mouseKeysFlags,dx,dy);
+    XkbFakePointerMotion(xkbi->device, xkbi->mouseKeysFlags, dx, dy);
     return xkbi->desc->ctrls->mk_interval;
 }
 
 static int
-_XkbFilterPointerMove( XkbSrvInfoPtr   xkbi,
-                       XkbFilterPtr    filter,
-                       unsigned        keycode,
-                       XkbAction *     pAction)
+_XkbFilterPointerMove(XkbSrvInfoPtr xkbi,
+                      XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
 {
-int    x,y;
-Bool   accel;
-
-    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);
-       XkbFakePointerMotion(xkbi->device, 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);
+    int x, y;
+    Bool accel;
+
+    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);
+        XkbFakePointerMotion(xkbi->device, 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, (void *) 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);
-       }
+    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)
+_XkbFilterPointerBtn(XkbSrvInfoPtr xkbi,
+                     XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
 {
-    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);
-                   XkbFakeDeviceButton(xkbi->device, 1, 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++) {
-                           XkbFakeDeviceButton(xkbi->device, 1, button);
-                           XkbFakeDeviceButton(xkbi->device, 0, button);
-                       }
-                       filter->upAction.type= XkbSA_NoAction;
-                   }
-                   else XkbFakeDeviceButton(xkbi->device, 1, 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;
-       }
+    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);
+                XkbFakeDeviceButton(xkbi->device, 1, 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++) {
+                    XkbFakeDeviceButton(xkbi->device, 1, button);
+                    XkbFakeDeviceButton(xkbi->device, 0, button);
+                }
+                filter->upAction.type = XkbSA_NoAction;
+            }
+            else
+                XkbFakeDeviceButton(xkbi->device, 1, 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);
-
-               if (IsMaster(xkbi->device))
-               {
-                   XkbMergeLockedPtrBtns(xkbi->device);
-                    /* One SD still has lock set, don't post event */
-                   if ((xkbi->lockedPtrButtons & (1 << button)) != 0)
-                       break;
-               }
-
-               /* fallthrough */
-           case XkbSA_PtrBtn:
-               XkbFakeDeviceButton(xkbi->device, 0, button);
-               break;
-       }
-       filter->active = 0;
+    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);
+
+            if (IsMaster(xkbi->device)) {
+                XkbMergeLockedPtrBtns(xkbi->device);
+                /* One SD still has lock set, don't post event */
+                if ((xkbi->lockedPtrButtons & (1 << button)) != 0)
+                    break;
+            }
+
+            /* fallthrough */
+        case XkbSA_PtrBtn:
+            XkbFakeDeviceButton(xkbi->device, 0, button);
+            break;
+        }
+        filter->active = 0;
     }
     return 0;
 }
 
 static int
-_XkbFilterControls(    XkbSrvInfoPtr   xkbi,
-                       XkbFilterPtr    filter,
-                       unsigned        keycode,
-                       XkbAction *     pAction)
+_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;
+    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);
-       }
+                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;
+    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)
+_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);
+    XkbMessageAction *pMsg;
+    DeviceIntPtr kbd;
+
+    if ((filter->keycode != 0) && (filter->keycode != keycode))
+       return 1;
+
+    /* This can happen if the key repeats, and the state (modifiers or group)
+       changes meanwhile. */
+    if ((filter->keycode == keycode) && pAction &&
+       (pAction->type != XkbSA_ActionMessage))
+       return 1;
+
+    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);
+    else if (filter->keycode == keycode) {
+        pMsg = &filter->upAction.msg;
+       if (pAction == NULL) {
+           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);
+       } else if (memcmp(pMsg, pAction, 8) == 0) {
+           /* Repeat: If we send the same message, avoid multiple messages
+              on release from piling up. */
+           filter->keycode = 0;
+           filter->active = 0;
+        }
     }
-    return 0;
+    return 1;
 }
 
 static int
-_XkbFilterRedirectKey( XkbSrvInfoPtr   xkbi,
-                       XkbFilterPtr    filter,
-                       unsigned        keycode,
-                       XkbAction *     pAction)
+_XkbFilterRedirectKey(XkbSrvInfoPtr xkbi,
+                      XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
 {
-DeviceEvent    ev;
-int            x,y;
-XkbStateRec    old;
-unsigned       mods,mask;
-xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(xkbi->device);
-ProcessInputProc backupproc;
+    DeviceEvent ev;
+    int x, y;
+    XkbStateRec old, old_prev;
+    unsigned mods, mask;
+    xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(xkbi->device);
+    ProcessInputProc backupproc;
+
+    if ((filter->keycode != 0) && (filter->keycode != keycode))
+        return 1;
+
+    /* This can happen if the key repeats, and the state (modifiers or group)
+       changes meanwhile. */
+    if ((filter->keycode == keycode) && pAction &&
+       (pAction->type != XkbSA_RedirectKey))
+       return 1;
 
     /* never actually used uninitialised, but gcc isn't smart enough
      * to work that out. */
     memset(&old, 0, sizeof(old));
+    memset(&old_prev, 0, sizeof(old_prev));
     memset(&ev, 0, sizeof(ev));
 
-    if ((filter->keycode!=0)&&(filter->keycode!=keycode))
-       return 1;
-
-    GetSpritePosition(xkbi->device, &x,&y);
+    GetSpritePosition(xkbi->device, &x, &y);
     ev.header = ET_Internal;
     ev.length = sizeof(DeviceEvent);
     ev.time = GetTimeInMillis();
     ev.root_x = x;
     ev.root_y = 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;
+    /* redirect actions do not work across devices, therefore the following is
+     * correct: */
+    ev.deviceid = xkbi->device->id;
+    /* filter->priv must be set up by the caller for the initial press. */
+    ev.sourceid = filter->priv;
+
+    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->filter = _XkbFilterRedirectKey;
+        filter->upAction = *pAction;
 
         ev.type = ET_KeyPress;
         ev.detail.key = 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;
-           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);
+        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;
+            old_prev = xkbi->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->prev_state = xkbi->state;
+        }
+
+        UNWRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr, backupproc);
+        xkbi->device->public.processInputProc((InternalEvent *) &ev,
+                                              xkbi->device);
+        COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr, backupproc,
+                                     xkbUnwrapProc);
+
+        if (mask || mods) {
+            xkbi->state = old;
+            xkbi->prev_state = old_prev;
+        }
+       return 0;
+    }
+    else {
+       /* If it is a key release, or we redirect to another key, release the
+          previous new_key.  Otherwise, repeat. */
+       ev.detail.key = filter->upAction.redirect.new_key;
+       if (pAction == NULL ||  ev.detail.key != pAction->redirect.new_key) {
+           ev.type = ET_KeyRelease;
+           filter->active = 0;
+       }
+       else {
+           ev.type = ET_KeyPress;
+           ev.key_repeat = TRUE;
        }
 
-       UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc);
-       xkbi->device->public.processInputProc((InternalEvent*)&ev, xkbi->device);
-       COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr,
-                                    backupproc,xkbUnwrapProc);
-       
-       if ( mask || mods )
-           xkbi->state= old;
-    }
-    else if (filter->keycode==keycode) {
-
-        ev.type = ET_KeyRelease;
-        ev.detail.key = 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;
-           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);
+       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;
+           old_prev = xkbi->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->prev_state = xkbi->state;
        }
 
-       UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc);
-       xkbi->device->public.processInputProc((InternalEvent*)&ev, xkbi->device);
-       COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr,
-                                    backupproc,xkbUnwrapProc);
+       UNWRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr, backupproc);
+       xkbi->device->public.processInputProc((InternalEvent *) &ev,
+                                             xkbi->device);
+       COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr, backupproc,
+                                    xkbUnwrapProc);
 
-       if ( mask || mods )
-           xkbi->state= old;
+       if (mask || mods) {
+           xkbi->state = old;
+           xkbi->prev_state = old_prev;
+       }
 
-       filter->keycode= 0;
-       filter->active= 0;
+       /* We return 1 in case we have sent a release event because the new_key
+          has changed.  Then, subsequently, we will call this function again
+          with the same pAction, which will create the press for the new
+          new_key. */
+       return (pAction && ev.detail.key != pAction->redirect.new_key);
     }
-    return 0;
 }
 
 static int
-_XkbFilterSwitchScreen(        XkbSrvInfoPtr   xkbi,
-                       XkbFilterPtr    filter,
-                       unsigned        keycode,
-                       XkbAction *     pAction)
+_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; 
+    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; 
+    else if (filter->keycode == keycode) {
+        filter->active = 0;
+        return 0;
     }
     return 1;
 }
 
 static int
-_XkbFilterXF86Private( XkbSrvInfoPtr   xkbi,
-                       XkbFilterPtr    filter,
-                       unsigned        keycode,
-                       XkbAction *     pAction)
+_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; 
+    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; 
+    else if (filter->keycode == keycode) {
+        filter->active = 0;
+        return 0;
     }
     return 1;
 }
 
-
 static int
-_XkbFilterDeviceBtn(   XkbSrvInfoPtr   xkbi,
-                       XkbFilterPtr    filter,
-                       unsigned        keycode,
-                       XkbAction *     pAction)
+_XkbFilterDeviceBtn(XkbSrvInfoPtr xkbi,
+                    XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
 {
-DeviceIntPtr   dev;
-int            button;
-
     if (xkbi->device == inputInfo.keyboard)
         return 0;
 
-    if (filter->keycode==0) {          /* initial press */
-       _XkbLookupButtonDevice(&dev, pAction->devbtn.device, serverClient,
-                              DixUnknownAccess, &button);
-       if (!dev || !dev->public.on)
-           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)||
-                   BitIsOn(dev->button->down, button))
-                   return 0;
-               XkbFakeDeviceButton(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++) {
-                       XkbFakeDeviceButton(dev,TRUE,button);
-                       XkbFakeDeviceButton(dev,FALSE,button);
-                   }
-                   filter->upAction.type= XkbSA_NoAction;
-               }
-               else XkbFakeDeviceButton(dev,TRUE,button);
-               break;
-       }
+    if (filter->keycode == 0) { /* initial press */
+        DeviceIntPtr dev;
+        int button;
+
+        _XkbLookupButtonDevice(&dev, pAction->devbtn.device, serverClient,
+                               DixUnknownAccess, &button);
+        if (!dev || !dev->public.on)
+            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) ||
+                BitIsOn(dev->button->down, button))
+                return 0;
+            XkbFakeDeviceButton(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++) {
+                    XkbFakeDeviceButton(dev, TRUE, button);
+                    XkbFakeDeviceButton(dev, FALSE, button);
+                }
+                filter->upAction.type = XkbSA_NoAction;
+            }
+            else
+                XkbFakeDeviceButton(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)
-           return 1;
-
-       button= filter->upAction.btn.button;
-       switch (filter->upAction.type) {
-           case XkbSA_LockDeviceBtn:
-               if ((filter->upAction.devbtn.flags&XkbSA_LockNoUnlock)||
-                   !BitIsOn(dev->button->down, button))
-                   return 0;
-               XkbFakeDeviceButton(dev,FALSE,button);
-               break;
-           case XkbSA_DeviceBtn:
-               XkbFakeDeviceButton(dev,FALSE,button);
-               break;
-       }
-       filter->active = 0;
+    else if (filter->keycode == keycode) {
+        DeviceIntPtr dev;
+        int button;
+
+        filter->active = 0;
+        _XkbLookupButtonDevice(&dev, filter->upAction.devbtn.device,
+                               serverClient, DixUnknownAccess, &button);
+        if (!dev || !dev->public.on)
+            return 1;
+
+        button = filter->upAction.btn.button;
+        switch (filter->upAction.type) {
+        case XkbSA_LockDeviceBtn:
+            if ((filter->upAction.devbtn.flags & XkbSA_LockNoUnlock) ||
+                !BitIsOn(dev->button->down, button))
+                return 0;
+            XkbFakeDeviceButton(dev, FALSE, button);
+            break;
+        case XkbSA_DeviceBtn:
+            XkbFakeDeviceButton(dev, FALSE, button);
+            break;
+        }
+        filter->active = 0;
     }
     return 0;
 }
 
 static XkbFilterPtr
-_XkbNextFreeFilter(
-       XkbSrvInfoPtr xkbi
-)
+_XkbNextFreeFilter(XkbSrvInfoPtr xkbi)
 {
-register int   i;
+    register int i;
 
-    if (xkbi->szFilters==0) {
-       xkbi->szFilters = 4;
-       xkbi->filters = calloc(xkbi->szFilters, sizeof(XkbFilterRec));
-       /* 6/21/93 (ef) -- XXX! deal with allocation failure */
+    if (xkbi->szFilters == 0) {
+        xkbi->szFilters = 4;
+        xkbi->filters = calloc(xkbi->szFilters, sizeof(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];
-       }
+    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= realloc(xkbi->filters,
+    xkbi->szFilters *= 2;
+    xkbi->filters = realloc(xkbi->filters,
                             xkbi->szFilters * sizeof(XkbFilterRec));
     /* 6/21/93 (ef) -- XXX! deal with allocation failure */
-    memset(&xkbi->filters[xkbi->szFilters/2], 0,
-            (xkbi->szFilters/2)*sizeof(XkbFilterRec));
-    return &xkbi->filters[xkbi->szFilters/2];
+    memset(&xkbi->filters[xkbi->szFilters / 2], 0,
+           (xkbi->szFilters / 2) * sizeof(XkbFilterRec));
+    return &xkbi->filters[xkbi->szFilters / 2];
 }
 
 static int
-_XkbApplyFilters(XkbSrvInfoPtr xkbi,unsigned kc,XkbAction *pAction)
+_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);
+    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, DeviceEvent* event)
+static int
+_XkbEnsureStateChange(XkbSrvInfoPtr xkbi)
 {
-int            key,bit,i;
-XkbSrvInfoPtr  xkbi;
-KeyClassPtr    keyc;
-int            changed,sendEvent;
-Bool           genStateNotify;
-XkbAction      act;
-XkbFilterPtr   filter;
-Bool           keyEvent;
-Bool           pressEvent;
-ProcessInputProc backupproc;
-    
-xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(dev);
-
-    keyc= kbd->key;
-    xkbi= keyc->xkbInfo;
-    key= event->detail.key;
+    Bool genStateNotify = FALSE;
+
     /* 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) {
-       xkbi->prev_state = xkbi->state;
-       xkbi->flags|= _XkbStateNotifyInProgress;
-       genStateNotify= TRUE;
+    if ((xkbi->flags & _XkbStateNotifyInProgress) == 0) {
+        xkbi->prev_state = xkbi->state;
+        xkbi->flags |= _XkbStateNotifyInProgress;
+        genStateNotify = TRUE;
+    }
+
+    return genStateNotify;
+}
+
+static void
+_XkbApplyState(DeviceIntPtr dev, Bool genStateNotify, int evtype, int key)
+{
+    XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
+    int changed;
+
+    XkbComputeDerivedState(xkbi);
+
+    changed = XkbStateChangedFlags(&xkbi->prev_state, &xkbi->state);
+    if (genStateNotify) {
+        if (changed) {
+            xkbStateNotify sn;
+
+            sn.keycode = key;
+            sn.eventType = evtype;
+            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, evtype);
+        XkbUpdateIndicators(dev, changed, FALSE, NULL, &cause);
     }
-    else genStateNotify= FALSE;
+}
+
+void
+XkbPushLockedStateToSlaves(DeviceIntPtr master, int evtype, int key)
+{
+    DeviceIntPtr dev;
+    Bool genStateNotify;
+
+    nt_list_for_each_entry(dev, inputInfo.devices, next) {
+        if (!dev->key || GetMaster(dev, MASTER_KEYBOARD) != master)
+            continue;
+
+        genStateNotify = _XkbEnsureStateChange(dev->key->xkbInfo);
+
+        dev->key->xkbInfo->state.locked_mods =
+            master->key->xkbInfo->state.locked_mods;
+
+        _XkbApplyState(dev, genStateNotify, evtype, key);
+    }
+}
+
+void
+XkbHandleActions(DeviceIntPtr dev, DeviceIntPtr kbd, DeviceEvent *event)
+{
+    int key, bit, i;
+    XkbSrvInfoPtr xkbi;
+    KeyClassPtr keyc;
+    int sendEvent;
+    Bool genStateNotify;
+    XkbAction act;
+    XkbFilterPtr filter;
+    Bool keyEvent;
+    Bool pressEvent;
+    ProcessInputProc backupproc;
+
+    xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(dev);
+
+    keyc = kbd->key;
+    xkbi = keyc->xkbInfo;
+    key = event->detail.key;
+
+    genStateNotify = _XkbEnsureStateChange(xkbi);
 
     xkbi->clearMods = xkbi->setMods = 0;
     xkbi->groupChange = 0;
 
     sendEvent = 1;
-    keyEvent= ((event->type == ET_KeyPress) || (event->type == ET_KeyRelease));
-    pressEvent= ((event->type == ET_KeyPress)|| (event->type == ET_ButtonPress));
+    keyEvent = ((event->type == ET_KeyPress) || (event->type == ET_KeyRelease));
+    pressEvent = ((event->type == ET_KeyPress) ||
+                  (event->type == ET_ButtonPress));
 
     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;
-           }
-       }
+        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);
+                /* redirect actions must create a new DeviceEvent.  The
+                 * source device id for this event cannot be obtained from
+                 * xkbi, so we pass it here explicitly. The field deviceid
+                 * equals to xkbi->device->id. */
+                filter->priv = event->sourceid;
+                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 (!keyEvent)
+            key |= BTN_ACT_FLAG;
+        sendEvent = _XkbApplyFilters(xkbi, key, NULL);
     }
 
-    if (xkbi->groupChange!=0)
-       xkbi->state.base_group+= xkbi->groupChange;
+    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;
-           }
-       }
+        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;
-           }
-       }
+        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) {
         DeviceIntPtr tmpdev;
-       if (keyEvent)
+
+        if (keyEvent)
             tmpdev = dev;
         else
-            tmpdev = GetPairedDevice(dev);
+            tmpdev = GetMaster(dev, POINTER_OR_FLOAT);
 
-        UNWRAP_PROCESS_INPUT_PROC(tmpdev,xkbPrivPtr, backupproc);
-        dev->public.processInputProc((InternalEvent*)event, tmpdev);
+        UNWRAP_PROCESS_INPUT_PROC(tmpdev, xkbPrivPtr, backupproc);
+        dev->public.processInputProc((InternalEvent *) event, tmpdev);
         COND_WRAP_PROCESS_INPUT_PROC(tmpdev, xkbPrivPtr,
-                                     backupproc,xkbUnwrapProc);
+                                     backupproc, xkbUnwrapProc);
     }
     else if (keyEvent) {
-       FixKeyState(event, dev);
+        FixKeyState(event, dev);
     }
 
-    XkbComputeDerivedState(xkbi);
-    changed = XkbStateChangedFlags(&xkbi->prev_state,&xkbi->state);
-    if (genStateNotify) {
-       if (changed) {
-           xkbStateNotify      sn;
-           sn.keycode= key;
-           sn.eventType= event->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, event->type);
-       XkbUpdateIndicators(dev,changed,FALSE,NULL,&cause);
-    }
-    return;
+    _XkbApplyState(dev, genStateNotify, event->type, key);
+    XkbPushLockedStateToSlaves(dev, event->type, key);
 }
 
 int
-XkbLatchModifiers(DeviceIntPtr pXDev,CARD8 mask,CARD8 latches)
+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;
+    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)
+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;
+    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;
 }
@@ -1289,46 +1401,45 @@ XkbAction       act;
 /***====================================================================***/
 
 void
-XkbClearAllLatchesAndLocks(    DeviceIntPtr            dev,
-                               XkbSrvInfoPtr           xkbi,
-                               Bool                    genEv,
-                               XkbEventCausePtr        cause)
+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;
+    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;
+        XkbLatchGroup(dev, 0);
+        sn.changed |= XkbGroupLatchMask;
     }
     if (os.locked_mods) {
-       xkbi->state.locked_mods= 0;
-       sn.changed|= XkbModifierLockMask;
+        xkbi->state.locked_mods = 0;
+        sn.changed |= XkbModifierLockMask;
     }
     if (os.locked_group) {
-       xkbi->state.locked_group= 0;
-       sn.changed|= XkbGroupLockMask;
+        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);
-       }
+    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;
 }
@@ -1354,49 +1465,51 @@ xkbStateNotify  sn;
  * First one on drinking island wins!
  */
 static void
-InjectPointerKeyEvents(DeviceIntPtr dev, int type, int button, int flags, int num_valuators, int *valuators)
+InjectPointerKeyEvents(DeviceIntPtr dev, int type, int button, int flags,
+                       ValuatorMask *mask)
 {
-    ScreenPtr           pScreen;
-    EventListPtr        events;
-    int                 nevents, i;
-    DeviceIntPtr        ptr, mpointer, lastSlave = NULL;
-    Bool                saveWait;
+    ScreenPtr pScreen;
+    InternalEvent *events;
+    int nevents, i;
+    DeviceIntPtr ptr, mpointer, lastSlave = NULL;
+    Bool saveWait;
 
     if (IsMaster(dev)) {
         mpointer = GetMaster(dev, MASTER_POINTER);
-        lastSlave = mpointer->u.lastSlave;
+        lastSlave = mpointer->lastSlave;
         ptr = GetXTestDevice(mpointer);
-    } else if (!dev->u.master)
+    }
+    else if (IsFloating(dev))
         ptr = dev;
     else
         return;
 
-
     events = InitEventList(GetMaximumEventsNum() + 1);
     OsBlockSignals();
     pScreen = miPointerGetScreen(ptr);
     saveWait = miPointerSetWaitForUpdate(pScreen, FALSE);
-    nevents = GetPointerEvents(events, ptr, type, button, flags, 0,
-                               num_valuators, valuators);
+    nevents = GetPointerEvents(events, ptr, type, button, flags, mask);
     if (IsMaster(dev) && (lastSlave && lastSlave != ptr))
-        UpdateFromMaster(&events[nevents], lastSlave, DEVCHANGE_POINTER_EVENT, &nevents);
+        UpdateFromMaster(&events[nevents], lastSlave, DEVCHANGE_POINTER_EVENT,
+                         &nevents);
     miPointerSetWaitForUpdate(pScreen, saveWait);
     OsReleaseSignals();
 
     for (i = 0; i < nevents; i++)
-        mieqProcessDeviceEvent(ptr, (InternalEvent*)events[i].event, NULL);
+        mieqProcessDeviceEvent(ptr, &events[i], NULL);
 
     FreeEventList(events, GetMaximumEventsNum());
 
 }
 
 static void
-XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y)
+XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags, int x, int y)
 {
-    int                 gpe_flags = 0;
+    ValuatorMask mask;
+    int gpe_flags = 0;
 
     /* ignore attached SDs */
-    if (!IsMaster(dev) && GetMaster(dev, MASTER_POINTER) != NULL)
+    if (!IsMaster(dev) && !IsFloating(dev))
         return;
 
     if (flags & XkbSA_MoveAbsoluteX || flags & XkbSA_MoveAbsoluteY)
@@ -1404,14 +1517,17 @@ XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y)
     else
         gpe_flags = POINTER_RELATIVE;
 
-    InjectPointerKeyEvents(dev, MotionNotify, 0, gpe_flags, 2, (int[]){x, y});
+    valuator_mask_set_range(&mask, 0, 2, (int[]) {
+                            x, y});
+
+    InjectPointerKeyEvents(dev, MotionNotify, 0, gpe_flags, &mask);
 }
 
 void
-XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button)
+XkbFakeDeviceButton(DeviceIntPtr dev, Bool press, int button)
 {
-    DeviceIntPtr        ptr;
-    int                 down;
+    DeviceIntPtr ptr;
+    int down;
 
     /* If dev is a slave device, and the SD is attached, do nothing. If we'd
      * post through the attached master pointer we'd get duplicate events.
@@ -1423,16 +1539,23 @@ XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button)
 
     if (IsMaster(dev)) {
         DeviceIntPtr mpointer = GetMaster(dev, MASTER_POINTER);
+
         ptr = GetXTestDevice(mpointer);
-    } else if (!dev->u.master)
+    }
+    else if (IsFloating(dev))
         ptr = dev;
     else
         return;
 
+#ifdef _F_DO_NULL_CHECK_AT_XKBFAKEDEVICEBUTTON_
+    if (!ptr)
+        return;                
+#endif /* #ifdef _F_DO_NULL_CHECK_AT_XKBFAKEDEVICEBUTTON_ */
+
     down = button_is_down(ptr, button, BUTTON_PROCESSED);
     if (press == down)
         return;
 
     InjectPointerKeyEvents(dev, press ? ButtonPress : ButtonRelease,
-                           button, 0, 0, NULL);
+                           button, 0, NULL);
 }