From f68a5a7d3e1002826414166e62afca0c97003d0e Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Wed, 30 Aug 2017 17:24:44 +0100 Subject: [PATCH] Actions: Break latch on modifier/group changes Right now, only a few actions result in breaking a key latch. Add modifier/group actions to this, as presumably the effect of the latch should not last beyond already shifting the modifier/group state. This was discovered with a real-world use in an input device for the physically impaired, where shift latches, but pressing shift twice goes to caps lock (note shift vs. caps lock, so not pure latch-to-lock). This is possible to implement with current keymap files, but locking caps lock would not break the shift latch. Hence, the following key sequence: [Shift] [a -> a] [Shift] [Shift] [b -> b] [c -> C] would occur, as the modifier state when pressing b was lock locked and shift latched. With this patch, the sequence is correct: [Shift] [a -> a] [Shift] [Shift -> Lock] [b -> B] [c -> C] Signed-off-by: Daniel Stone --- src/state.c | 6 ++++ test/data/compat/testlatch | 13 +++++++++ test/data/rules/evdev | 2 ++ test/data/symbols/testlatch | 58 +++++++++++++++++++++++++++++++++++++ test/state.c | 50 ++++++++++++++++++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 test/data/compat/testlatch create mode 100644 test/data/symbols/testlatch diff --git a/src/state.c b/src/state.c index 6a88d9661..18c661593 100644 --- a/src/state.c +++ b/src/state.c @@ -430,6 +430,12 @@ xkb_action_breaks_latch(const union xkb_action *action) case ACTION_TYPE_CTRL_LOCK: case ACTION_TYPE_SWITCH_VT: case ACTION_TYPE_TERMINATE: + case ACTION_TYPE_MOD_SET: + case ACTION_TYPE_MOD_LATCH: + case ACTION_TYPE_MOD_LOCK: + case ACTION_TYPE_GROUP_SET: + case ACTION_TYPE_GROUP_LATCH: + case ACTION_TYPE_GROUP_LOCK: return true; default: return false; diff --git a/test/data/compat/testlatch b/test/data/compat/testlatch new file mode 100644 index 000000000..d4fa6431f --- /dev/null +++ b/test/data/compat/testlatch @@ -0,0 +1,13 @@ +partial default xkb_compatibility "testlatch" { + interpret Shift_L { + action= LatchMods(modifiers=Shift); + }; + + interpret Lock+Exactly(Shift) { + action= LockMods(modifiers=Lock,affect=lock); + }; + + interpret Lock+Exactly(Shift+Lock) { + action= LockMods(modifiers=Lock,affect=unlock); + }; +}; diff --git a/test/data/rules/evdev b/test/data/rules/evdev index f58e5b229..5e0140e90 100644 --- a/test/data/rules/evdev +++ b/test/data/rules/evdev @@ -205,6 +205,7 @@ * $sun_custom $sun_var = pc+sun_vndr/%l%(v) ! model layout = symbols + testlatch * = testlatch(%l) * ar = pc+ara * ben = pc+in(ben) * bs = pc+ba @@ -893,6 +894,7 @@ * jp = complete+japan olpc * = olpc olpcm * = olpc + testlatch * = complete+testlatch * * = complete ! model layout[1] = compat diff --git a/test/data/symbols/testlatch b/test/data/symbols/testlatch new file mode 100644 index 000000000..4fcac8a7f --- /dev/null +++ b/test/data/symbols/testlatch @@ -0,0 +1,58 @@ +// Latch behaviour testing + +partial default alphanumeric_keys +xkb_symbols "us" { + name[Group1] = "English"; + + include "testlatch(base)" + + + key { [ q, Q ]}; + key { [ w, W ]}; + key { [ e, E ]}; + key { [ r, R ]}; + key { [ t, T ]}; + key { [ y, Y ]}; + key { [ u, U ]}; + key { [ i, I ]}; + key { [ o, O ]}; + key { [ p, P ]}; + + key { [ a, A ]}; + key { [ s, S ]}; + key { [ d, D ]}; + key { [ f, F ]}; + key { [ g, G ]}; + key { [ h, H ]}; + key { [ j, J ]}; + key { [ k, K ]}; + key { [ l, L ]}; + + key { [ z, Z ]}; + key { [ x, X ]}; + key { [ c, C ]}; + key { [ v, V ]}; + key { [ b, B ]}; + key { [ n, N ]}; + key { [ m, M ]}; +}; + +partial alphanumeric_keys +xkb_symbols "base" { + key { [ Escape ] }; + + // We want Shift to latch normally, but also to produce caps when pressed + // twice in a row. + key { [ Shift_L, Caps_Lock ] }; + + key { [ 1, exclam ]}; + key { [ 2, quotedbl ]}; + key { [ 3, currency ]}; + key { [ 4, at ]}; + key { [ 5, percent ]}; + key { [ 6, question ]}; + key { [ 7, minus ]}; + key { [ 8, plus ]}; + key { [ 9, apostrophe ]}; + key { [ 0, equal ]}; +}; diff --git a/test/state.c b/test/state.c index 1f2c75d9c..013cd8d04 100644 --- a/test/state.c +++ b/test/state.c @@ -707,6 +707,54 @@ test_ctrl_string_transformation(struct xkb_keymap *keymap) xkb_state_unref(state); } +static void +test_latch_mod_cancel(struct xkb_context *context) +{ + struct xkb_keymap *keymap; + + keymap = test_compile_rules(context, "evdev", "testlatch", "us", + NULL, NULL); + assert(keymap); + + assert(test_key_seq(keymap, + KEY_A, BOTH, XKB_KEY_a, NEXT, /* plain a */ + KEY_1, BOTH, XKB_KEY_1, NEXT, /* plain 1 */ + + KEY_LEFTSHIFT, BOTH, XKB_KEY_Shift_L, NEXT, + KEY_A, BOTH, XKB_KEY_A, NEXT, /* shift latched */ + KEY_A, BOTH, XKB_KEY_a, NEXT, /* ... and unlatched */ + + KEY_LEFTSHIFT, BOTH, XKB_KEY_Shift_L, NEXT, + KEY_1, BOTH, XKB_KEY_exclam, NEXT, /* and again */ + KEY_1, BOTH, XKB_KEY_1, NEXT, + + KEY_LEFTSHIFT, DOWN, XKB_KEY_Shift_L, NEXT, + KEY_1, BOTH, XKB_KEY_exclam, NEXT, /* should unlatch */ + KEY_LEFTSHIFT, UP, XKB_KEY_Caps_Lock, NEXT, + KEY_1, BOTH, XKB_KEY_1, NEXT, + + KEY_LEFTSHIFT, BOTH, XKB_KEY_Shift_L, NEXT, + KEY_LEFTSHIFT, BOTH, XKB_KEY_Caps_Lock, NEXT, /* caps lock! */ + /* Without the change we fail here, as Lock is locked but Shift still latched */ + KEY_A, BOTH, XKB_KEY_A, NEXT, + KEY_1, BOTH, XKB_KEY_1, NEXT, + KEY_LEFTSHIFT, BOTH, XKB_KEY_Shift_L, NEXT, + KEY_1, BOTH, XKB_KEY_exclam, NEXT, /* shift latched */ + KEY_1, BOTH, XKB_KEY_1, NEXT, /* ... and unlatched */ + KEY_LEFTSHIFT, BOTH, XKB_KEY_Shift_L, NEXT, + KEY_A, BOTH, XKB_KEY_a, NEXT, /* shift latched, cancel */ + KEY_A, BOTH, XKB_KEY_A, NEXT, + + KEY_LEFTSHIFT, BOTH, XKB_KEY_Shift_L, NEXT, + KEY_LEFTSHIFT, BOTH, XKB_KEY_Caps_Lock, NEXT, /* caps unlock */ + + KEY_A, BOTH, XKB_KEY_a, NEXT, + KEY_A, BOTH, XKB_KEY_a, NEXT, + KEY_1, BOTH, XKB_KEY_1, FINISH)); + + xkb_keymap_unref(keymap); +} + int main(void) { @@ -738,6 +786,8 @@ main(void) test_caps_keysym_transformation(keymap); + test_latch_mod_cancel(context); + xkb_keymap_unref(keymap); xkb_context_unref(context); }