@@ -295,7 +295,9 @@ xkb_filter_group_lock_func(struct xkb_state *state,
295
295
}
296
296
297
297
static bool
298
- xkb_action_breaks_latch (const union xkb_action * action )
298
+ xkb_action_breaks_latch (const union xkb_action * action ,
299
+ enum xkb_internal_action_flags flag ,
300
+ xkb_mod_mask_t mask )
299
301
{
300
302
switch (action -> type ) {
301
303
case ACTION_TYPE_NONE :
@@ -306,6 +308,9 @@ xkb_action_breaks_latch(const union xkb_action *action)
306
308
case ACTION_TYPE_SWITCH_VT :
307
309
case ACTION_TYPE_TERMINATE :
308
310
return true;
311
+ case ACTION_TYPE_INTERNAL :
312
+ return (action -> internal .flags & flag ) &&
313
+ ((action -> internal .clear_latched_mods & mask ) == mask );
309
314
default :
310
315
return false;
311
316
}
@@ -389,7 +394,8 @@ xkb_filter_group_latch_func(struct xkb_state *state,
389
394
*/
390
395
continue ;
391
396
}
392
- else if (xkb_action_breaks_latch (& (actions [k ]))) {
397
+ else if (xkb_action_breaks_latch (& (actions [k ]),
398
+ INTERNAL_BREAKS_GROUP_LATCH , 0 )) {
393
399
/* Breaks the latch */
394
400
state -> components .latched_group -= priv .group_delta ;
395
401
filter -> func = NULL ;
@@ -547,9 +553,11 @@ xkb_filter_mod_latch_func(struct xkb_state *state,
547
553
/* XXX beep beep! */
548
554
return XKB_FILTER_CONSUME ;
549
555
}
550
- else if (xkb_action_breaks_latch (& (actions [k ]))) {
556
+ else if (xkb_action_breaks_latch (& (actions [k ]),
557
+ INTERNAL_BREAKS_MOD_LATCH ,
558
+ filter -> action .mods .mods .mask )) {
551
559
/* XXX: This may be totally broken, we might need to break the
552
- * latch in the next run after this press? */
560
+ * latch in the next run after this press? */
553
561
state -> components .latched_mods &= ~filter -> action .mods .mods .mask ;
554
562
filter -> func = NULL ;
555
563
return XKB_FILTER_CONTINUE ;
@@ -892,6 +900,114 @@ xkb_state_update_key(struct xkb_state *state, xkb_keycode_t kc,
892
900
return get_state_component_changes (& prev_components , & state -> components );
893
901
}
894
902
903
+ /* We need fake keys for `update_latch_modifiers` and `update_latch_group`.
904
+ * These keys must have at least one level in order to break latches. We need 2
905
+ * keys with specific actions in order to update group/mod latches without
906
+ * affecting each other. */
907
+ static struct xkb_key_type_entry synthetic_key_level_entry = { 0 };
908
+ static struct xkb_key_type synthetic_key_type = {
909
+ .num_entries = 1 ,
910
+ .num_levels = 1 ,
911
+ .entries = & synthetic_key_level_entry
912
+ };
913
+ static const struct xkb_key synthetic_key = { 0 };
914
+
915
+ /* Transcription from xserver: XkbLatchModifiers */
916
+ static void
917
+ update_latch_modifiers (struct xkb_state * state ,
918
+ xkb_mod_mask_t mask , xkb_mod_mask_t latches )
919
+ {
920
+ /* Clear affected latched modifiers */
921
+ const xkb_mod_mask_t clear = mask & ~latches ;
922
+ state -> components .latched_mods &= ~clear ;
923
+
924
+ /* Clear any pending latch to locks using ad hoc action:
925
+ * only affect corresponding modifier latches and no group latch. */
926
+ struct xkb_level synthetic_key_level_break_mod_latch = {
927
+ .num_syms = 0 ,
928
+ .num_actions = 1 ,
929
+ .upper = XKB_KEY_NoSymbol ,
930
+ .s .sym = XKB_KEY_NoSymbol ,
931
+ .a .action .internal = {
932
+ .type = ACTION_TYPE_INTERNAL ,
933
+ .flags = INTERNAL_BREAKS_MOD_LATCH ,
934
+ .clear_latched_mods = clear
935
+ }
936
+ };
937
+ struct xkb_group synthetic_key_group_break_mod_latch = {
938
+ .type = & synthetic_key_type ,
939
+ .levels = & synthetic_key_level_break_mod_latch
940
+ };
941
+ const struct xkb_key synthetic_key_break_mod_latch = {
942
+ .num_groups = 1 ,
943
+ .groups = & synthetic_key_group_break_mod_latch
944
+ };
945
+ xkb_filter_apply_all (state , & synthetic_key_break_mod_latch , XKB_KEY_DOWN );
946
+
947
+ /* Finally set the latched mods by simulate tapping a key with the
948
+ * corresponding action */
949
+ const struct xkb_key * const key = & synthetic_key ;
950
+ const union xkb_action latch_mods = {
951
+ .mods = {
952
+ .type = ACTION_TYPE_MOD_LATCH ,
953
+ .mods = { .mask = mask & latches },
954
+ .flags = 0 ,
955
+ },
956
+ };
957
+ struct xkb_filter * const filter = xkb_filter_new (state );
958
+ filter -> key = key ;
959
+ filter -> func = xkb_filter_mod_latch_func ;
960
+ filter -> action = latch_mods ;
961
+ xkb_filter_mod_latch_new (state , filter );
962
+ /* We added the filter manually, so only fire “up” event */
963
+ xkb_filter_mod_latch_func (state , filter , key , XKB_KEY_UP );
964
+ }
965
+
966
+ /* Transcription from xserver: XkbLatchGroup */
967
+ static void
968
+ update_latch_group (struct xkb_state * state , int32_t group )
969
+ {
970
+ /* Clear any pending latch to locks. */
971
+ static struct xkb_level synthetic_key_level_break_group_latch = {
972
+ .num_syms = 0 ,
973
+ .num_actions = 1 ,
974
+ .upper = XKB_KEY_NoSymbol ,
975
+ .s .sym = XKB_KEY_NoSymbol ,
976
+ .a .action .internal = {
977
+ .type = ACTION_TYPE_INTERNAL ,
978
+ .flags = INTERNAL_BREAKS_GROUP_LATCH ,
979
+ .clear_latched_mods = 0
980
+ }
981
+ };
982
+ static struct xkb_group synthetic_key_group_break_group_latch = {
983
+ .type = & synthetic_key_type ,
984
+ .levels = & synthetic_key_level_break_group_latch
985
+ };
986
+ static const struct xkb_key synthetic_key_break_group_latch = {
987
+ .num_groups = 1 ,
988
+ .groups = & synthetic_key_group_break_group_latch
989
+ };
990
+ xkb_filter_apply_all (state , & synthetic_key_break_group_latch , XKB_KEY_DOWN );
991
+
992
+ /* Simulate tapping a key with a group latch action, but in isolation: i.e.
993
+ * without affecting the other filters. */
994
+ const struct xkb_key * const key = & synthetic_key ;
995
+ const union xkb_action latch_group = {
996
+ .group = {
997
+ .type = ACTION_TYPE_GROUP_LATCH ,
998
+ .flags = ACTION_ABSOLUTE_SWITCH ,
999
+ .group = group ,
1000
+ },
1001
+ };
1002
+ struct xkb_filter * const filter = xkb_filter_new (state );
1003
+ filter -> key = key ;
1004
+ filter -> func = xkb_filter_group_latch_func ;
1005
+ filter -> action = latch_group ;
1006
+ xkb_filter_group_latch_new (state , filter );
1007
+ /* We added the filter manually, so only fire “up” event */
1008
+ xkb_filter_group_latch_func (state , filter , key , XKB_KEY_UP );
1009
+ }
1010
+
895
1011
/**
896
1012
* Compute the resolved effective mask of an arbitrary input.
897
1013
*
@@ -913,6 +1029,46 @@ resolve_to_canonical_mods(struct xkb_keymap *keymap, xkb_mod_mask_t mods)
913
1029
mods & ~keymap -> canonical_state_mask );
914
1030
}
915
1031
1032
+ enum xkb_state_component
1033
+ xkb_state_update_latched_locked (struct xkb_state * state ,
1034
+ xkb_mod_mask_t affect_latched_mods ,
1035
+ xkb_mod_mask_t latched_mods ,
1036
+ bool affect_latched_layout ,
1037
+ int32_t latched_layout ,
1038
+ xkb_mod_mask_t affect_locked_mods ,
1039
+ xkb_mod_mask_t locked_mods ,
1040
+ bool affect_locked_layout ,
1041
+ int32_t locked_layout )
1042
+ {
1043
+ const struct state_components prev_components = state -> components ;
1044
+
1045
+ /* Update locks */
1046
+ affect_locked_mods =
1047
+ resolve_to_canonical_mods (state -> keymap , affect_locked_mods );
1048
+ if (affect_locked_mods ) {
1049
+ locked_mods = resolve_to_canonical_mods (state -> keymap , locked_mods );
1050
+ state -> components .locked_mods &= ~affect_locked_mods ;
1051
+ state -> components .locked_mods |= locked_mods & affect_locked_mods ;
1052
+ }
1053
+ if (affect_locked_layout ) {
1054
+ state -> components .locked_group = locked_layout ;
1055
+ }
1056
+
1057
+ /* Update latches */
1058
+ affect_latched_mods =
1059
+ resolve_to_canonical_mods (state -> keymap , affect_latched_mods );
1060
+ if (affect_latched_mods ) {
1061
+ latched_mods = resolve_to_canonical_mods (state -> keymap , latched_mods );
1062
+ update_latch_modifiers (state , affect_latched_mods , latched_mods );
1063
+ }
1064
+ if (affect_latched_layout ) {
1065
+ update_latch_group (state , latched_layout );
1066
+ }
1067
+
1068
+ xkb_state_update_derived (state );
1069
+ return get_state_component_changes (& prev_components , & state -> components );
1070
+ }
1071
+
916
1072
/**
917
1073
* Updates the state from a set of explicit masks as gained from
918
1074
* xkb_state_serialize_mods and xkb_state_serialize_groups. As noted in the
0 commit comments