From d13f3f0619f9c6db3d1edac1c4c4e584148baf97 Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Thu, 8 Feb 2024 17:28:10 +0100 Subject: [PATCH] keymap: Add option "unlockOnPress" for LockMods action This is an extensions to XKB. It intends to allow to deactivate CapsLock on press rather than on release, as in other platforms such as Windows. --- src/keymap.h | 1 + src/state.c | 14 +++++++++++--- src/xkbcomp/action.c | 15 +++++++++++---- src/xkbcomp/keymap-dump.c | 3 ++- test/data/compat/caps | 6 ++++++ test/data/rules/evdev | 1 + 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/keymap.h b/src/keymap.h index b375b7f40..abf04bacc 100644 --- a/src/keymap.h +++ b/src/keymap.h @@ -152,6 +152,7 @@ enum xkb_action_flags { ACTION_ACCEL = (1 << 8), ACTION_SAME_SCREEN = (1 << 9), ACTION_LOCK_ON_RELEASE = (1 << 10), + ACTION_UNLOCK_ON_PRESS = (1 << 11), }; enum xkb_action_controls { diff --git a/src/state.c b/src/state.c index 03351f693..bce8b0746 100644 --- a/src/state.c +++ b/src/state.c @@ -395,9 +395,17 @@ xkb_filter_mod_lock_new(struct xkb_state *state, struct xkb_filter *filter) { filter->priv = (state->components.locked_mods & filter->action.mods.mods.mask); - state->set_mods |= filter->action.mods.mods.mask; - if (!(filter->action.mods.flags & ACTION_LOCK_NO_LOCK)) - state->components.locked_mods |= filter->action.mods.mods.mask; + if (filter->priv && (filter->action.mods.flags & ACTION_UNLOCK_ON_PRESS)) { + /* XKB extension: Unlock on second press */ + state->clear_mods |= filter->action.mods.mods.mask; + if (!(filter->action.mods.flags & ACTION_LOCK_NO_UNLOCK)) + state->components.locked_mods &= ~filter->priv; + filter->priv = 0; + } else { + state->set_mods |= filter->action.mods.mods.mask; + if (!(filter->action.mods.flags & ACTION_LOCK_NO_LOCK)) + state->components.locked_mods |= filter->action.mods.mods.mask; + } } static bool diff --git a/src/xkbcomp/action.c b/src/xkbcomp/action.c index 03eee22ee..35cc60ffc 100644 --- a/src/xkbcomp/action.c +++ b/src/xkbcomp/action.c @@ -101,6 +101,7 @@ enum action_field { ACTION_FIELD_KEYCODE, ACTION_FIELD_MODS_TO_CLEAR, ACTION_FIELD_LOCK_ON_RELEASE, + ACTION_FIELD_UNLOCK_ON_PRESS, }; ActionsInfo * @@ -168,6 +169,7 @@ static const LookupEntry fieldStrings[] = { { "clearmods", ACTION_FIELD_MODS_TO_CLEAR }, { "clearmodifiers", ACTION_FIELD_MODS_TO_CLEAR }, { "lockOnRelease", ACTION_FIELD_LOCK_ON_RELEASE }, + { "unlockOnPress", ACTION_FIELD_UNLOCK_ON_PRESS }, { NULL, 0 } }; @@ -334,10 +336,15 @@ HandleSetLatchLockMods(struct xkb_context *ctx, const struct xkb_mod_set *mods, return CheckBooleanFlag(ctx, action->type, field, ACTION_LATCH_TO_LOCK, array_ndx, value, &act->flags); - if (type == ACTION_TYPE_MOD_LOCK && - field == ACTION_FIELD_AFFECT) - return CheckAffectField(ctx, action->type, array_ndx, value, - &act->flags); + if (type == ACTION_TYPE_MOD_LOCK) { + if (field == ACTION_FIELD_AFFECT) + return CheckAffectField(ctx, action->type, array_ndx, value, + &act->flags); + if (field == ACTION_FIELD_UNLOCK_ON_PRESS) + return CheckBooleanFlag(ctx, action->type, field, + ACTION_UNLOCK_ON_PRESS, array_ndx, value, + &act->flags); + } return ReportIllegal(ctx, action->type, field); } diff --git a/src/xkbcomp/keymap-dump.c b/src/xkbcomp/keymap-dump.c index c4e0fc764..04d1d8a4f 100644 --- a/src/xkbcomp/keymap-dump.c +++ b/src/xkbcomp/keymap-dump.c @@ -316,10 +316,11 @@ write_action(struct xkb_keymap *keymap, struct buf *buf, else args = ModMaskText(keymap->ctx, &keymap->mods, action->mods.mods.mods); - write_buf(buf, "%s%s(modifiers=%s%s%s%s)%s", prefix, type, args, + write_buf(buf, "%s%s(modifiers=%s%s%s%s%s)%s", prefix, type, args, (action->type != ACTION_TYPE_MOD_LOCK && (action->mods.flags & ACTION_LOCK_CLEAR)) ? ",clearLocks" : "", (action->type != ACTION_TYPE_MOD_LOCK && (action->mods.flags & ACTION_LATCH_TO_LOCK)) ? ",latchToLock" : "", (action->type == ACTION_TYPE_MOD_LOCK) ? affect_lock_text(action->mods.flags, false) : "", + (action->type == ACTION_TYPE_MOD_LOCK && (action->mods.flags & ACTION_UNLOCK_ON_PRESS)) ? ",unlockOnPress" : "", suffix); break; diff --git a/test/data/compat/caps b/test/data/compat/caps index 4793051ec..af375d9e5 100644 --- a/test/data/compat/caps +++ b/test/data/compat/caps @@ -9,3 +9,9 @@ partial xkb_compatibility "caps_lock" { action = LockMods(modifiers = Lock); }; }; + +partial xkb_compatibility "caps_lock_unlock_on_press" { + interpret Caps_Lock { + action = LockMods(modifiers = Lock, unlockOnPress); + }; +}; diff --git a/test/data/rules/evdev b/test/data/rules/evdev index 32c8ed3ef..e76317910 100644 --- a/test/data/rules/evdev +++ b/test/data/rules/evdev @@ -1160,6 +1160,7 @@ mod_led:compose = +ledcompose(compose) japan:kana_lock = +japan(kana_lock) caps:shiftlock = +ledcaps(shift_lock) + caps:unlock_on_press = +caps(caps_lock_unlock_on_press) grab:break_actions = +xfree86(grab_break)