Several fixes to ISOLock: - Use the proper byte to access the "affect" flags. - When changing a Set/Latch action to a Lock action, also change the flags for the action. - Respect NoLock/NoUnlock. - Add the missing transformation of actions that occurred before the ISOLock was pressed.
Support NoLock/NoUnlock for "Controls". Output changes: - support flag "genKeyEvent" flag for message actions. - Output "affect" flags for control locks, modifier locks, and ISOLock. Furthermore, prevent autorepeat for Set/Lock actions. This serves mainly to reduce the number of cases that can occur in connection with ISOLock. Also note that the code did not properly check whether a key is released, so autorepeat handling was incorrect anyway. Signed-off-by: Andreas Wettstein <[email protected]> --- xkb/xkbActions.c | 177 ++++++++++++++++++++++++++++++++++++++++--------------- xkb/xkbtext.c | 50 +++++++++++++++- 2 files changed, 179 insertions(+), 48 deletions(-) diff --git a/xkb/xkbActions.c b/xkb/xkbActions.c index e32005c..f726775 100644 --- a/xkb/xkbActions.c +++ b/xkb/xkbActions.c @@ -181,6 +181,7 @@ _XkbFilterSetState(XkbSrvInfoPtr xkbi, XkbFilterPtr filter, unsigned keycode, XkbAction *pAction) { if (filter->keycode == 0) { /* initial press */ + AccessXCancelRepeatKey(xkbi, keycode); filter->keycode = keycode; filter->active = 1; filter->filterOthers = ((pAction->mods.mask & XkbSA_ClearLocks) != 0); @@ -189,6 +190,8 @@ _XkbFilterSetState(XkbSrvInfoPtr xkbi, if (pAction->type == XkbSA_SetMods) { filter->upAction = *pAction; xkbi->setMods = pAction->mods.mask; + /* This is used in case an ISOLock comes up. */ + filter->priv = xkbi->state.locked_mods & pAction->mods.mask; } else { xkbi->groupChange = XkbSAGroup(&pAction->group); @@ -339,12 +342,14 @@ _XkbFilterLatchState(XkbSrvInfoPtr xkbi, else if (pAction && (filter->priv == LATCH_KEY_DOWN)) { /* Latch was broken before it became pending: degrade to a SetMods/SetGroup. */ - if (filter->upAction.type == XkbSA_LatchMods) + if (filter->upAction.type == XkbSA_LatchMods) { filter->upAction.type = XkbSA_SetMods; - else + filter->priv = xkbi->state.locked_mods & filter->upAction.mods.mask; + } else { filter->upAction.type = XkbSA_SetGroup; + filter->priv = 0; + } filter->filter = _XkbFilterSetState; - filter->priv = 0; return filter->filter(xkbi, filter, keycode, pAction); } return 1; @@ -354,6 +359,9 @@ static int _XkbFilterLockState(XkbSrvInfoPtr xkbi, XkbFilterPtr filter, unsigned keycode, XkbAction *pAction) { + if (filter->keycode == 0) /* initial press */ + AccessXCancelRepeatKey(xkbi, keycode); + if (pAction && (pAction->type == XkbSA_LockGroup)) { if (pAction->group.flags & XkbSA_GroupAbsolute) xkbi->state.locked_group = XkbSAGroup(&pAction->group); @@ -381,6 +389,47 @@ _XkbFilterLockState(XkbSrvInfoPtr xkbi, return 1; } + +static Bool +_XkbTransformActionForISOLock(XkbAction* pAction, + CARD8 flags, CARD8 affect) +{ + switch (pAction->type) { + case XkbSA_SetMods: + case XkbSA_LatchMods: + if (!(affect & XkbSA_ISONoAffectMods)) { + pAction->type = XkbSA_LockMods; + pAction->mods.flags &= ~(XkbSA_ClearLocks | XkbSA_LatchToLock); + pAction->mods.flags |= flags & (XkbSA_LockNoLock | XkbSA_LockNoUnlock); + return 1; + } + break; + case XkbSA_SetGroup: + case XkbSA_LatchGroup: + if (!(affect & XkbSA_ISONoAffectGroup)) { + pAction->type = XkbSA_LockGroup; + pAction->group.flags &= ~(XkbSA_ClearLocks | XkbSA_LatchToLock); + return 1; + } + break; + case XkbSA_PtrBtn: + if (!(affect & XkbSA_ISONoAffectPtr)) { + pAction->type = XkbSA_LockPtrBtn; + pAction->btn.flags |= flags & (XkbSA_LockNoLock | XkbSA_LockNoUnlock); + return 1; + } + break; + case XkbSA_SetControls: + if (!(affect & XkbSA_ISONoAffectCtrls)) { + pAction->type = XkbSA_LockControls; + pAction->ctrls.flags |= flags & (XkbSA_LockNoLock | XkbSA_LockNoUnlock); + return 1; + } + break; + } + return 0; +} + #define ISO_KEY_DOWN 0 #define NO_ISO_LOCK 1 @@ -388,9 +437,12 @@ static int _XkbFilterISOLock(XkbSrvInfoPtr xkbi, XkbFilterPtr filter, unsigned keycode, XkbAction *pAction) { + int i; if (filter->keycode == 0) { /* initial press */ + AccessXCancelRepeatKey(xkbi, keycode); CARD8 flags = pAction->iso.flags; + CARD8 affect = pAction->iso.affect; filter->keycode = keycode; filter->active = 1; @@ -406,15 +458,56 @@ _XkbFilterISOLock(XkbSrvInfoPtr xkbi, xkbi->setMods = pAction->iso.mask; xkbi->groupChange = 0; } - if ((!(flags & XkbSA_ISONoAffectMods)) && (xkbi->state.base_mods)) { - filter->priv = NO_ISO_LOCK; - xkbi->state.locked_mods ^= xkbi->state.base_mods; - } - if ((!(flags & XkbSA_ISONoAffectGroup)) && (xkbi->state.base_group)) { -/* 6/22/93 (ef) -- lock groups if group key is down first */ - } - if (!(flags & XkbSA_ISONoAffectPtr)) { -/* 6/22/93 (ef) -- lock mouse buttons if they're down */ + + for (i = 0; i < xkbi->szFilters; i++) { + if ((xkbi->filters[i].active) && (xkbi->filters[i].filter)) { + XkbAction *upAction = &xkbi->filters[i].upAction; + unsigned char oldtype = upAction->type; + + if (_XkbTransformActionForISOLock(upAction, flags, affect)) { + switch (oldtype) { + /* Latches cannot occur, as they have been tranformed by their own filter */ + case XkbSA_SetMods: + xkbi->filters[i].filter = _XkbFilterLockState; + if (!(flags & XkbSA_LockNoLock)) + xkbi->state.locked_mods |= upAction->mods.mask; + break; + case XkbSA_SetGroup: + xkbi->filters[i].active = 0; + xkbi->groupChange -= XkbSAGroup(&upAction->group); + xkbi->state.locked_group += XkbSAGroup(&upAction->group); + break; + case XkbSA_PtrBtn: + /* We miss actions with nonzero click count. */ + if (!(xkbi->lockedPtrButtons & (1 << upAction->btn.button)) && + !(flags & XkbSA_LockNoLock)) { + xkbi->lockedPtrButtons |= (1 << upAction->btn.button); + upAction->type = XkbSA_NoAction; + } + /* Unlocking is handled by the already transformed filter. */ + break; + case XkbSA_SetControls: + if (flags & XkbSA_LockNoUnlock) { + if (!(flags & XkbSA_LockNoLock)) + xkbi->filters[i].priv = 0; + } + else { + /* priv contains the controls that have been + enabled by the SetControl action. From those, + we can obtain the controls that had already been + enabled before. */ + int setByAction = xkbi->filters[i].priv; + int setBefore = XkbActionCtrls(&upAction->ctrls) & ~setByAction; + if (!flags & XkbSA_LockNoLock) + xkbi->filters[i].priv = XkbActionCtrls(&upAction->ctrls); + else + xkbi->filters[i].priv = setBefore; + } + break; + } + filter->priv = NO_ISO_LOCK; + } + } } } else if (filter->keycode == keycode) { @@ -429,42 +522,23 @@ _XkbFilterISOLock(XkbSrvInfoPtr xkbi, else { xkbi->clearMods = filter->upAction.iso.mask; xkbi->groupChange = 0; - if (filter->priv == ISO_KEY_DOWN) - xkbi->state.locked_mods ^= filter->upAction.iso.mask; + if (filter->priv == ISO_KEY_DOWN) { + unsigned char common = + xkbi->state.locked_mods & filter->upAction.iso.mask; + if (!(flags & XkbSA_LockNoLock)) + xkbi->state.locked_mods |= filter->upAction.iso.mask; + if (!(flags & XkbSA_LockNoUnlock)) + xkbi->state.locked_mods &= ~common; + } } filter->active = 0; } else if (pAction) { CARD8 flags = filter->upAction.iso.flags; + CARD8 affect = filter->upAction.iso.affect; - switch (pAction->type) { - case XkbSA_SetMods: - case XkbSA_LatchMods: - if (!(flags & XkbSA_ISONoAffectMods)) { - pAction->type = XkbSA_LockMods; - filter->priv = NO_ISO_LOCK; - } - break; - case XkbSA_SetGroup: - case XkbSA_LatchGroup: - if (!(flags & XkbSA_ISONoAffectGroup)) { - pAction->type = XkbSA_LockGroup; - filter->priv = NO_ISO_LOCK; - } - break; - case XkbSA_PtrBtn: - if (!(flags & XkbSA_ISONoAffectPtr)) { - pAction->type = XkbSA_LockPtrBtn; - filter->priv = NO_ISO_LOCK; - } - break; - case XkbSA_SetControls: - if (!(flags & XkbSA_ISONoAffectCtrls)) { - pAction->type = XkbSA_LockControls; - filter->priv = NO_ISO_LOCK; - } - break; - } + if (_XkbTransformActionForISOLock(pAction, flags, affect)) + filter->priv = NO_ISO_LOCK; } return 1; } @@ -635,6 +709,7 @@ _XkbFilterPointerBtn(XkbSrvInfoPtr xkbi, } break; } + return 0; } else if (filter->keycode == keycode) { int button = filter->upAction.btn.button; @@ -660,8 +735,9 @@ _XkbFilterPointerBtn(XkbSrvInfoPtr xkbi, break; } filter->active = 0; + return 0; } - return 0; + return 1; } static int @@ -678,17 +754,26 @@ _XkbFilterControls(XkbSrvInfoPtr xkbi, ctrls = xkbi->desc->ctrls; old = *ctrls; if (filter->keycode == 0) { /* initial press */ + AccessXCancelRepeatKey(xkbi, keycode); filter->keycode = keycode; filter->active = 1; filter->filterOthers = 0; - change = XkbActionCtrls(&pAction->ctrls); + change = (XkbActionCtrls(&pAction->ctrls) & ~ctrls->enabled_ctrls); filter->priv = change; filter->filter = _XkbFilterControls; filter->upAction = *pAction; if (pAction->type == XkbSA_LockControls) { - filter->priv = (ctrls->enabled_ctrls & change); - change &= ~ctrls->enabled_ctrls; + if (pAction->ctrls.flags & XkbSA_LockNoUnlock) + filter->priv = 0; + else + /* The protocol specification says we should unlock controls + are NOT currently enabled. As this does not make any sense, + let's assume this is a typo and do the opposite. */ + filter->priv = (XkbActionCtrls(&pAction->ctrls) & ctrls->enabled_ctrls); + + if (pAction->ctrls.flags & XkbSA_LockNoLock) + change = 0; } if (change) { diff --git a/xkb/xkbtext.c b/xkb/xkbtext.c index fdf1d17..fd323bc 100644 --- a/xkb/xkbtext.c +++ b/xkb/xkbtext.c @@ -749,8 +749,22 @@ CopyModActionArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz) } else TryCopyStr(buf, "none", sz); - if (act->type == XkbSA_LockMods) + if (act->type == XkbSA_LockMods) { + switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) { + case XkbSA_LockNoLock: + TryCopyStr(buf, ",affect=unlock", sz); + break; + case XkbSA_LockNoUnlock: + TryCopyStr(buf, ",affect=lock", sz); + break; + case XkbSA_LockNoUnlock|XkbSA_LockNoLock: + TryCopyStr(buf, ",affect=neither", sz); + break; + default: + break; + } return TRUE; + } if (act->flags & XkbSA_ClearLocks) TryCopyStr(buf, ",clearLocks", sz); if (act->flags & XkbSA_LatchToLock) @@ -901,8 +915,12 @@ CopyISOLockArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz) TryCopyStr(buf, "none", sz); } TryCopyStr(buf, ",affect=", sz); - if ((act->affect & XkbSA_ISOAffectMask) == 0) + if ((act->affect & XkbSA_ISOAffectMask) == 0) { TryCopyStr(buf, "all", sz); + } + else if ((act->affect & XkbSA_ISOAffectMask) == XkbSA_ISOAffectMask) { + TryCopyStr(buf, "none", sz); + } else { int nOut = 0; @@ -926,6 +944,18 @@ CopyISOLockArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz) nOut++; } } + switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) { + case XkbSA_LockNoLock: + TryCopyStr(buf, "+unlock", sz); + break; + case XkbSA_LockNoUnlock: + TryCopyStr(buf, "+lock", sz); + break; + case XkbSA_LockNoUnlock | XkbSA_LockNoLock: + TryCopyStr(buf, "+neither", sz); + break; + default: ; + } return TRUE; } @@ -1037,6 +1067,20 @@ CopySetLockControlsArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz) nOut++; } } + if (action->type == XkbSA_LockControls) { + switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) { + case XkbSA_LockNoLock: + TryCopyStr(buf, ",affect=unlock", sz); + break; + case XkbSA_LockNoUnlock: + TryCopyStr(buf, ",affect=lock", sz); + break; + case XkbSA_LockNoUnlock | XkbSA_LockNoLock: + TryCopyStr(buf, ",affect=neither", sz); + break; + default: ; + } + } return TRUE; } @@ -1070,6 +1114,8 @@ CopyActionMessageArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz) TryCopyStr(buf, tbuf, sz); snprintf(tbuf, sizeof(tbuf), ",data[5]=0x%02x", act->message[5]); TryCopyStr(buf, tbuf, sz); + if (act->flags & XkbSA_MessageGenKeyEvent) + TryCopyStr(buf, ",genKeyEvent", sz); return TRUE; } -- 1.8.3.1 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
