Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xkbcomp: Fix key merge mode (keysyms, actions) #568

Merged
merged 2 commits into from
Jan 15, 2025

Conversation

wismill
Copy link
Member

@wismill wismill commented Dec 19, 2024

This also adds exhaustive tests for merge modes.

Fixes #564

TODO

TODO in follow-up MRs:

  • Merge mode propagation
  • Other fields/objects

@mahkoh

@wismill wismill added bug Indicates an unexpected problem or unintended behavior compile-keymap Indicates a need for improvements or additions to keymap compilation labels Dec 19, 2024
@wismill wismill added this to the 1.8.0 milestone Dec 19, 2024
@wismill wismill force-pushed the symbols/fix-key-merge-mode-symbols branch from b946df1 to da3ee82 Compare December 19, 2024 18:16
@wismill
Copy link
Member Author

wismill commented Dec 19, 2024

Windows Compiler Error C2026. Wonderful.

Fixed by using assert_printf instead of assert. We could also use a temp var.

@wismill
Copy link
Member Author

wismill commented Dec 19, 2024

Note to self: in order to check other key properties, we should probably just compare resulting keymap strings with a ref.

Also let's add the same tests for xkbcomp (at least where the syntax is supported: e.g. no multi keysym per level).

@wismill wismill force-pushed the symbols/fix-key-merge-mode-symbols branch 13 times, most recently from c5549d4 to 7ff4c3d Compare December 27, 2024 00:45
@bam80
Copy link

bam80 commented Dec 27, 2024

May be related: #573

@wismill wismill force-pushed the symbols/fix-key-merge-mode-symbols branch 3 times, most recently from c78c27c to 84d1cdc Compare December 27, 2024 01:09
@wismill
Copy link
Member Author

wismill commented Dec 27, 2024

Trying to fix the failing macOS pipeline. I suspect an out-of-bound in xkbcomp (see this MR) to be the origin of:

Warning:          Multiple actions for level 3/group 1 on key <AD03>
                  Using Private, ignoring SetGroup

The Private action bit above is suspicious.


The Linux pipeline is fragile too: it works without Valgrind, so I suspect race conditions with the various threads.

@wismill wismill force-pushed the symbols/fix-key-merge-mode-symbols branch 6 times, most recently from e7c94f6 to 3097e91 Compare December 28, 2024 17:57
@wismill wismill requested review from bluetech and whot December 28, 2024 19:14
@wismill wismill marked this pull request as ready for review December 28, 2024 19:14
@wismill
Copy link
Member Author

wismill commented Dec 28, 2024

@mahkoh With this MR we will have a first round of tests for the common uses of merge modes and multiple fixes.

TODO:

  • Merge mode propagation
  • Other fields/objects

@wismill wismill force-pushed the symbols/fix-key-merge-mode-symbols branch 2 times, most recently from e78560e to 322c2ee Compare December 31, 2024 07:32
@wismill wismill force-pushed the symbols/fix-key-merge-mode-symbols branch 2 times, most recently from e7a745b to ab73498 Compare January 13, 2025 15:26
@wismill
Copy link
Member Author

wismill commented Jan 13, 2025

Introduced golden tests and moved the xkkbcomp tests to the separated MR #591.

@wismill wismill force-pushed the symbols/fix-key-merge-mode-symbols branch 2 times, most recently from ca81612 to dbb8935 Compare January 13, 2025 19:53
@wismill
Copy link
Member Author

wismill commented Jan 13, 2025

Added tests for local merge mode on the keys, in addition to the previous global merge mode tests. Both local/global merge modes should lead to the same keymap , but there is some slight discrepancy on a couple of cases.

EDIT: Fixed discrepancy that was due to a typo.

@wismill wismill marked this pull request as draft January 13, 2025 19:58
@wismill wismill force-pushed the symbols/fix-key-merge-mode-symbols branch 3 times, most recently from 1263267 to 66ad48c Compare January 14, 2025 09:41
@wismill wismill marked this pull request as ready for review January 14, 2025 09:43
@wismill
Copy link
Member Author

wismill commented Jan 14, 2025

@mahkoh please find the tests for global/local merge modes with expected/got results hereinafter. Do you agree on the results? Did I miss some tests?

Detailed tests entries
////// Trivial cases //////

// base:     (empty)
// key to merge / replace result
key <T001> {  };
// override: (empty)
// augment:  (empty)

// base:     (empty)
// key to merge / replace result
key <T002> {  };
// override: (empty)
// augment:  (empty)

// base:     (empty)
// key to merge / replace result
key <T003> {  };
// override: (empty)
// augment:  (empty)

// base:     (empty)
// key to merge / replace result
key <T004> { symbols=[Greek_alpha] };
// override: symbols=[Greek_alpha]
// augment:  symbols=[Greek_alpha]

// base:     (empty)
// key to merge / replace result
key <T005> { actions=[SetGroup(group=3)] };
// override: actions=[SetGroup(group=3)]
// augment:  actions=[SetGroup(group=3)]

// base:     (empty)
// key to merge / replace result
key <T006> { symbols=[Greek_alpha], actions=[SetGroup(group=3)] };
// override: symbols=[Greek_alpha], actions=[SetGroup(group=3)]
// augment:  symbols=[Greek_alpha], actions=[SetGroup(group=3)]

// base:     symbols=[a]
// key to merge / replace result
key <T007> {  };
// override: symbols=[a]
// augment:  symbols=[a]

// base:     actions=[SetGroup(group=2)]
// key to merge / replace result
key <T008> {  };
// override: actions=[SetGroup(group=2)]
// augment:  actions=[SetGroup(group=2)]

// base:     symbols=[a], actions=[SetGroup(group=2)]
// key to merge / replace result
key <T009> {  };
// override: symbols=[a], actions=[SetGroup(group=2)]
// augment:  symbols=[a], actions=[SetGroup(group=2)]

////// Same key //////

// base:     symbols=[a]
// key to merge / replace result
key <T010> { symbols=[a] };
// override: symbols=[a]
// augment:  symbols=[a]

// base:     actions=[SetGroup(group=2)]
// key to merge / replace result
key <T011> { actions=[SetGroup(group=2)] };
// override: actions=[SetGroup(group=2)]
// augment:  actions=[SetGroup(group=2)]

// base:     symbols=[a], actions=[SetGroup(group=2)]
// key to merge / replace result
key <T012> { symbols=[a], actions=[SetGroup(group=2)] };
// override: symbols=[a], actions=[SetGroup(group=2)]
// augment:  symbols=[a], actions=[SetGroup(group=2)]

// base:     symbols=[a, {A, Y}]
// key to merge / replace result
key <T013> { symbols=[a, {A, Y}] };
// override: symbols=[a, {A, Y}]
// augment:  symbols=[a, {A, Y}]

// base:     actions=[SetGroup(group=2), {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T014> { actions=[SetGroup(group=2), {SetGroup(group=2), SetMods(mods=Control)}] };
// override: actions=[SetGroup(group=2), {SetGroup(group=2), SetMods(mods=Control)}]
// augment:  actions=[SetGroup(group=2), {SetGroup(group=2), SetMods(mods=Control)}]

// base:     symbols=[a, {A, Y}], actions=[SetGroup(group=2), {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T015> { symbols=[a, {A, Y}], actions=[SetGroup(group=2), {SetGroup(group=2), SetMods(mods=Control)}] };
// override: symbols=[a, {A, Y}], actions=[SetGroup(group=2), {SetGroup(group=2), SetMods(mods=Control)}]
// augment:  symbols=[a, {A, Y}], actions=[SetGroup(group=2), {SetGroup(group=2), SetMods(mods=Control)}]

////// Mismatch levels count //////

// base:     actions=[NoAction(), SetGroup(group=2)]
// key to merge / replace result
key <T017> { actions=[SetGroup(group=3), NoAction(), NoAction()] };
// override: actions=[SetGroup(group=3), SetGroup(group=2), NoAction()]
// augment:  actions=[SetGroup(group=3), SetGroup(group=2), NoAction()]

// base:     symbols=[NoSymbol, A], actions=[NoAction(), SetGroup(group=2)]
// key to merge / replace result
key <T018> { symbols=[Greek_alpha, NoSymbol, NoSymbol], actions=[SetGroup(group=3), NoAction(), NoAction()] };
// override: symbols=[Greek_alpha, A, NoSymbol], actions=[SetGroup(group=3), SetGroup(group=2), NoAction()]
// augment:  symbols=[Greek_alpha, A, NoSymbol], actions=[SetGroup(group=3), SetGroup(group=2), NoAction()]

// base:     symbols=[NoSymbol, A]
// key to merge / replace result
key <T016> { symbols=[Greek_alpha, NoSymbol, NoSymbol] };
// override: symbols=[Greek_alpha, A, NoSymbol]
// augment:  symbols=[Greek_alpha, A, NoSymbol]

// base:     actions=[NoAction(), SetGroup(group=2)]
// key to merge / replace result
key <T020> { actions=[SetGroup(group=3), NoAction(), NoAction()] };
// override: actions=[SetGroup(group=3), SetGroup(group=2), NoAction()]
// augment:  actions=[SetGroup(group=3), SetGroup(group=2), NoAction()]

// base:     symbols=[NoSymbol, A], actions=[NoAction(), SetGroup(group=2)]
// key to merge / replace result
key <T021> { symbols=[Greek_alpha, NoSymbol, NoSymbol], actions=[SetGroup(group=3), NoAction(), NoAction()] };
// override: symbols=[Greek_alpha, A, NoSymbol], actions=[SetGroup(group=3), SetGroup(group=2), NoAction()]
// augment:  symbols=[Greek_alpha, A, NoSymbol], actions=[SetGroup(group=3), SetGroup(group=2), NoAction()]

// base:     actions=[NoAction(), SetGroup(group=2), NoAction()]
// key to merge / replace result
key <T023> { actions=[SetGroup(group=3), NoAction()] };
// override: actions=[SetGroup(group=3), SetGroup(group=2), NoAction()]
// augment:  actions=[SetGroup(group=3), SetGroup(group=2), NoAction()]

// base:     symbols=[NoSymbol, A, NoSymbol], actions=[NoAction(), SetGroup(group=2), NoAction()]
// key to merge / replace result
key <T024> { symbols=[Greek_alpha, NoSymbol], actions=[SetGroup(group=3), NoAction()] };
// override: symbols=[Greek_alpha, A, NoSymbol], actions=[SetGroup(group=3), SetGroup(group=2), NoAction()]
// augment:  symbols=[Greek_alpha, A, NoSymbol], actions=[SetGroup(group=3), SetGroup(group=2), NoAction()]

// base:     symbols=[NoSymbol, A, NoSymbol]
// key to merge / replace result
key <T022> { symbols=[Greek_alpha, NoSymbol] };
// override: symbols=[Greek_alpha, A, NoSymbol]
// augment:  symbols=[Greek_alpha, A, NoSymbol]

// base:     symbols=[a, A]
// key to merge / replace result
key <T025> { symbols=[Greek_alpha, Greek_ALPHA, Greek_alpha] };
// override: symbols=[Greek_alpha, Greek_ALPHA, Greek_alpha]
// augment:  symbols=[a, A, Greek_alpha]

// base:     actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T026> { actions=[SetGroup(group=3), SetGroup(group=3), SetGroup(group=3)] };
// override: actions=[SetGroup(group=3), SetGroup(group=3), SetGroup(group=3)]
// augment:  actions=[SetGroup(group=2), SetGroup(group=2), SetGroup(group=3)]

// base:     symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T027> { symbols=[Greek_alpha, Greek_ALPHA, Greek_alpha], actions=[SetGroup(group=3), SetGroup(group=3), SetGroup(group=3)] };
// override: symbols=[Greek_alpha, Greek_ALPHA, Greek_alpha], actions=[SetGroup(group=3), SetGroup(group=3), SetGroup(group=3)]
// augment:  symbols=[a, A, Greek_alpha], actions=[SetGroup(group=2), SetGroup(group=2), SetGroup(group=3)]

// base:     symbols=[a, A, a]
// key to merge / replace result
key <T028> { symbols=[Greek_alpha, Greek_ALPHA] };
// override: symbols=[Greek_alpha, Greek_ALPHA, a]
// augment:  symbols=[a, A, a]

// base:     actions=[SetGroup(group=2), SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T029> { actions=[SetGroup(group=3), SetGroup(group=3)] };
// override: actions=[SetGroup(group=3), SetGroup(group=3), SetGroup(group=2)]
// augment:  actions=[SetGroup(group=2), SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A, a], actions=[SetGroup(group=2), SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T030> { symbols=[Greek_alpha, Greek_ALPHA], actions=[SetGroup(group=3), SetGroup(group=3)] };
// override: symbols=[Greek_alpha, Greek_ALPHA, a], actions=[SetGroup(group=3), SetGroup(group=3), SetGroup(group=2)]
// augment:  symbols=[a, A, a], actions=[SetGroup(group=2), SetGroup(group=2), SetGroup(group=2)]

////// Single keysyms -> single keysyms //////

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T031> { symbols=[NoSymbol, NoSymbol] };
// override: symbols=[NoSymbol, NoSymbol]
// augment:  symbols=[NoSymbol, NoSymbol]

// base:     actions=[NoAction(), NoAction()]
// key to merge / replace result
key <T032> { actions=[NoAction(), NoAction()] };
// override: actions=[NoAction(), NoAction()]
// augment:  actions=[NoAction(), NoAction()]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T033> { symbols=[NoSymbol, NoSymbol] };
// override: symbols=[NoSymbol, NoSymbol]
// augment:  symbols=[NoSymbol, NoSymbol]

// base:     actions=[NoAction(), NoAction()]
// key to merge / replace result
key <T035> { actions=[SetGroup(group=3), NoAction()] };
// override: actions=[SetGroup(group=3), NoAction()]
// augment:  actions=[SetGroup(group=3), NoAction()]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T036> { symbols=[Greek_alpha, NoSymbol], actions=[SetGroup(group=3), NoAction()] };
// override: symbols=[Greek_alpha, NoSymbol], actions=[SetGroup(group=3), NoAction()]
// augment:  symbols=[Greek_alpha, NoSymbol], actions=[SetGroup(group=3), NoAction()]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T034> { symbols=[Greek_alpha, NoSymbol] };
// override: symbols=[Greek_alpha, NoSymbol]
// augment:  symbols=[Greek_alpha, NoSymbol]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T037> { symbols=[NoSymbol, Greek_ALPHA] };
// override: symbols=[NoSymbol, Greek_ALPHA]
// augment:  symbols=[NoSymbol, Greek_ALPHA]

// base:     actions=[NoAction(), NoAction()]
// key to merge / replace result
key <T038> { actions=[NoAction(), SetGroup(group=3)] };
// override: actions=[NoAction(), SetGroup(group=3)]
// augment:  actions=[NoAction(), SetGroup(group=3)]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T039> { symbols=[NoSymbol, Greek_ALPHA], actions=[NoAction(), SetGroup(group=3)] };
// override: symbols=[NoSymbol, Greek_ALPHA], actions=[NoAction(), SetGroup(group=3)]
// augment:  symbols=[NoSymbol, Greek_ALPHA], actions=[NoAction(), SetGroup(group=3)]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T043> { symbols=[Greek_alpha, Greek_ALPHA] };
// override: symbols=[Greek_alpha, Greek_ALPHA]
// augment:  symbols=[Greek_alpha, Greek_ALPHA]

// base:     actions=[NoAction(), NoAction()]
// key to merge / replace result
key <T044> { actions=[SetGroup(group=3), SetGroup(group=3)] };
// override: actions=[SetGroup(group=3), SetGroup(group=3)]
// augment:  actions=[SetGroup(group=3), SetGroup(group=3)]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T045> { symbols=[Greek_alpha, Greek_ALPHA], actions=[SetGroup(group=3), SetGroup(group=3)] };
// override: symbols=[Greek_alpha, Greek_ALPHA], actions=[SetGroup(group=3), SetGroup(group=3)]
// augment:  symbols=[Greek_alpha, Greek_ALPHA], actions=[SetGroup(group=3), SetGroup(group=3)]

// base:     symbols=[a, A]
// key to merge / replace result
key <T046> { symbols=[NoSymbol, NoSymbol] };
// override: symbols=[a, A]
// augment:  symbols=[a, A]

// base:     actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T047> { actions=[NoAction(), NoAction()] };
// override: actions=[SetGroup(group=2), SetGroup(group=2)]
// augment:  actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T048> { symbols=[NoSymbol, NoSymbol] };
// override: symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]
// augment:  symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T050> { actions=[SetGroup(group=3), NoAction()] };
// override: actions=[SetGroup(group=3), SetGroup(group=2)]
// augment:  actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T051> { symbols=[Greek_alpha, NoSymbol], actions=[SetGroup(group=3), NoAction()] };
// override: symbols=[Greek_alpha, A], actions=[SetGroup(group=3), SetGroup(group=2)]
// augment:  symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A]
// key to merge / replace result
key <T049> { symbols=[Greek_alpha, NoSymbol] };
// override: symbols=[Greek_alpha, A]
// augment:  symbols=[a, A]

// base:     symbols=[a, A]
// key to merge / replace result
key <T052> { symbols=[NoSymbol, Greek_ALPHA] };
// override: symbols=[a, Greek_ALPHA]
// augment:  symbols=[a, A]

// base:     actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T053> { actions=[NoAction(), SetGroup(group=3)] };
// override: actions=[SetGroup(group=2), SetGroup(group=3)]
// augment:  actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T054> { symbols=[NoSymbol, Greek_ALPHA], actions=[NoAction(), SetGroup(group=3)] };
// override: symbols=[a, Greek_ALPHA], actions=[SetGroup(group=2), SetGroup(group=3)]
// augment:  symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A]
// key to merge / replace result
key <T055> { symbols=[Greek_alpha, Greek_ALPHA] };
// override: symbols=[Greek_alpha, Greek_ALPHA]
// augment:  symbols=[a, A]

// base:     actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T056> { actions=[SetGroup(group=3), SetGroup(group=3)] };
// override: actions=[SetGroup(group=3), SetGroup(group=3)]
// augment:  actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T057> { symbols=[Greek_alpha, Greek_ALPHA], actions=[SetGroup(group=3), SetGroup(group=3)] };
// override: symbols=[Greek_alpha, Greek_ALPHA], actions=[SetGroup(group=3), SetGroup(group=3)]
// augment:  symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, NoSymbol], actions=[NoAction(), SetGroup(group=2)]
// key to merge / replace result
key <T060> { symbols=[NoSymbol, X], actions=[SetGroup(group=3), NoAction()] };
// override: symbols=[a, X], actions=[SetGroup(group=3), SetGroup(group=2)]
// augment:  symbols=[a, X], actions=[SetGroup(group=3), SetGroup(group=2)]

////// Single keysyms -> multiple keysyms //////

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T061> { symbols=[{Greek_alpha, NoSymbol}, NoSymbol] };
// override: symbols=[{Greek_alpha, NoSymbol}, NoSymbol]
// augment:  symbols=[{Greek_alpha, NoSymbol}, NoSymbol]

// base:     actions=[NoAction(), NoAction()]
// key to merge / replace result
key <T062> { actions=[{SetGroup(group=3), NoAction()}, NoAction()] };
// override: actions=[{SetGroup(group=3), NoAction()}, NoAction()]
// augment:  actions=[{SetGroup(group=3), NoAction()}, NoAction()]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T063> { symbols=[{Greek_alpha, NoSymbol}, NoSymbol], actions=[{SetGroup(group=3), NoAction()}, NoAction()] };
// override: symbols=[{Greek_alpha, NoSymbol}, NoSymbol], actions=[{SetGroup(group=3), NoAction()}, NoAction()]
// augment:  symbols=[{Greek_alpha, NoSymbol}, NoSymbol], actions=[{SetGroup(group=3), NoAction()}, NoAction()]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T064> { symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, NoSymbol}] };
// override: symbols=[{Greek_alpha, NoSymbol}, NoSymbol]
// augment:  symbols=[{Greek_alpha, NoSymbol}, NoSymbol]

// base:     actions=[NoAction(), NoAction()]
// key to merge / replace result
key <T065> { actions=[{SetGroup(group=3), NoAction()}, {NoAction(), NoAction()}] };
// override: actions=[{SetGroup(group=3), NoAction()}, NoAction()]
// augment:  actions=[{SetGroup(group=3), NoAction()}, NoAction()]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T066> { symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, NoSymbol}], actions=[{SetGroup(group=3), NoAction()}, {NoAction(), NoAction()}] };
// override: symbols=[{Greek_alpha, NoSymbol}, NoSymbol], actions=[{SetGroup(group=3), NoAction()}, NoAction()]
// augment:  symbols=[{Greek_alpha, NoSymbol}, NoSymbol], actions=[{SetGroup(group=3), NoAction()}, NoAction()]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T067> { symbols=[NoSymbol, {Greek_ALPHA, NoSymbol}] };
// override: symbols=[NoSymbol, {Greek_ALPHA, NoSymbol}]
// augment:  symbols=[NoSymbol, {Greek_ALPHA, NoSymbol}]

// base:     actions=[NoAction(), NoAction()]
// key to merge / replace result
key <T068> { actions=[NoAction(), {SetGroup(group=3), NoAction()}] };
// override: actions=[NoAction(), {SetGroup(group=3), NoAction()}]
// augment:  actions=[NoAction(), {SetGroup(group=3), NoAction()}]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T069> { symbols=[NoSymbol, {Greek_ALPHA, NoSymbol}], actions=[NoAction(), {SetGroup(group=3), NoAction()}] };
// override: symbols=[NoSymbol, {Greek_ALPHA, NoSymbol}], actions=[NoAction(), {SetGroup(group=3), NoAction()}]
// augment:  symbols=[NoSymbol, {Greek_ALPHA, NoSymbol}], actions=[NoAction(), {SetGroup(group=3), NoAction()}]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T070> { symbols=[{NoSymbol, NoSymbol}, {Greek_ALPHA, NoSymbol}] };
// override: symbols=[NoSymbol, {Greek_ALPHA, NoSymbol}]
// augment:  symbols=[NoSymbol, {Greek_ALPHA, NoSymbol}]

// base:     actions=[NoAction(), NoAction()]
// key to merge / replace result
key <T071> { actions=[{NoAction(), NoAction()}, {SetGroup(group=3), NoAction()}] };
// override: actions=[NoAction(), {SetGroup(group=3), NoAction()}]
// augment:  actions=[NoAction(), {SetGroup(group=3), NoAction()}]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T072> { symbols=[{NoSymbol, NoSymbol}, {Greek_ALPHA, NoSymbol}], actions=[{NoAction(), NoAction()}, {SetGroup(group=3), NoAction()}] };
// override: symbols=[NoSymbol, {Greek_ALPHA, NoSymbol}], actions=[NoAction(), {SetGroup(group=3), NoAction()}]
// augment:  symbols=[NoSymbol, {Greek_ALPHA, NoSymbol}], actions=[NoAction(), {SetGroup(group=3), NoAction()}]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T073> { symbols=[{Greek_alpha, NoSymbol}, {Greek_ALPHA, NoSymbol}] };
// override: symbols=[{Greek_alpha, NoSymbol}, {Greek_ALPHA, NoSymbol}]
// augment:  symbols=[{Greek_alpha, NoSymbol}, {Greek_ALPHA, NoSymbol}]

// base:     actions=[NoAction(), NoAction()]
// key to merge / replace result
key <T074> { actions=[{SetGroup(group=3), NoAction()}, {SetGroup(group=3), NoAction()}] };
// override: actions=[{SetGroup(group=3), NoAction()}, {SetGroup(group=3), NoAction()}]
// augment:  actions=[{SetGroup(group=3), NoAction()}, {SetGroup(group=3), NoAction()}]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T075> { symbols=[{Greek_alpha, NoSymbol}, {Greek_ALPHA, NoSymbol}], actions=[{SetGroup(group=3), NoAction()}, {SetGroup(group=3), NoAction()}] };
// override: symbols=[{Greek_alpha, NoSymbol}, {Greek_ALPHA, NoSymbol}], actions=[{SetGroup(group=3), NoAction()}, {SetGroup(group=3), NoAction()}]
// augment:  symbols=[{Greek_alpha, NoSymbol}, {Greek_ALPHA, NoSymbol}], actions=[{SetGroup(group=3), NoAction()}, {SetGroup(group=3), NoAction()}]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T076> { symbols=[{Greek_alpha, Greek_upsilon}, {Greek_ALPHA, Greek_UPSILON}] };
// override: symbols=[{Greek_alpha, Greek_upsilon}, {Greek_ALPHA, Greek_UPSILON}]
// augment:  symbols=[{Greek_alpha, Greek_upsilon}, {Greek_ALPHA, Greek_UPSILON}]

// base:     actions=[NoAction(), NoAction()]
// key to merge / replace result
key <T077> { actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}]

// base:     symbols=[NoSymbol, NoSymbol]
// key to merge / replace result
key <T078> { symbols=[{Greek_alpha, Greek_upsilon}, {Greek_ALPHA, Greek_UPSILON}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: symbols=[{Greek_alpha, Greek_upsilon}, {Greek_ALPHA, Greek_UPSILON}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  symbols=[{Greek_alpha, Greek_upsilon}, {Greek_ALPHA, Greek_UPSILON}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}]

// base:     symbols=[a, A]
// key to merge / replace result
key <T079> { symbols=[{Greek_alpha, NoSymbol}, NoSymbol] };
// override: symbols=[{Greek_alpha, NoSymbol}, A]
// augment:  symbols=[a, A]

// base:     actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T080> { actions=[{SetGroup(group=3), NoAction()}, NoAction()] };
// override: actions=[{SetGroup(group=3), NoAction()}, SetGroup(group=2)]
// augment:  actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T081> { symbols=[{Greek_alpha, NoSymbol}, NoSymbol], actions=[{SetGroup(group=3), NoAction()}, NoAction()] };
// override: symbols=[{Greek_alpha, NoSymbol}, A], actions=[{SetGroup(group=3), NoAction()}, SetGroup(group=2)]
// augment:  symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A]
// key to merge / replace result
key <T085> { symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, NoSymbol}] };
// override: symbols=[{Greek_alpha, NoSymbol}, A]
// augment:  symbols=[a, A]

// base:     actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T086> { actions=[{SetGroup(group=3), NoAction()}, {NoAction(), NoAction()}] };
// override: actions=[{SetGroup(group=3), NoAction()}, SetGroup(group=2)]
// augment:  actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T087> { symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, NoSymbol}], actions=[{SetGroup(group=3), NoAction()}, {NoAction(), NoAction()}] };
// override: symbols=[{Greek_alpha, NoSymbol}, A], actions=[{SetGroup(group=3), NoAction()}, SetGroup(group=2)]
// augment:  symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A]
// key to merge / replace result
key <T088> { symbols=[NoSymbol, {Greek_ALPHA, NoSymbol}] };
// override: symbols=[a, {Greek_ALPHA, NoSymbol}]
// augment:  symbols=[a, A]

// base:     actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T089> { actions=[NoAction(), {SetGroup(group=3), NoAction()}] };
// override: actions=[SetGroup(group=2), {SetGroup(group=3), NoAction()}]
// augment:  actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T090> { symbols=[NoSymbol, {Greek_ALPHA, NoSymbol}], actions=[NoAction(), {SetGroup(group=3), NoAction()}] };
// override: symbols=[a, {Greek_ALPHA, NoSymbol}], actions=[SetGroup(group=2), {SetGroup(group=3), NoAction()}]
// augment:  symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A]
// key to merge / replace result
key <T091> { symbols=[{NoSymbol, NoSymbol}, {Greek_ALPHA, NoSymbol}] };
// override: symbols=[a, {Greek_ALPHA, NoSymbol}]
// augment:  symbols=[a, A]

// base:     actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T092> { actions=[{NoAction(), NoAction()}, {SetGroup(group=3), NoAction()}] };
// override: actions=[SetGroup(group=2), {SetGroup(group=3), NoAction()}]
// augment:  actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T093> { symbols=[{NoSymbol, NoSymbol}, {Greek_ALPHA, NoSymbol}], actions=[{NoAction(), NoAction()}, {SetGroup(group=3), NoAction()}] };
// override: symbols=[a, {Greek_ALPHA, NoSymbol}], actions=[SetGroup(group=2), {SetGroup(group=3), NoAction()}]
// augment:  symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A]
// key to merge / replace result
key <T094> { symbols=[{Greek_alpha, NoSymbol}, {Greek_ALPHA, NoSymbol}] };
// override: symbols=[{Greek_alpha, NoSymbol}, {Greek_ALPHA, NoSymbol}]
// augment:  symbols=[a, A]

// base:     actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T095> { actions=[{SetGroup(group=3), NoAction()}, {SetGroup(group=3), NoAction()}] };
// override: actions=[{SetGroup(group=3), NoAction()}, {SetGroup(group=3), NoAction()}]
// augment:  actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T096> { symbols=[{Greek_alpha, NoSymbol}, {Greek_ALPHA, NoSymbol}], actions=[{SetGroup(group=3), NoAction()}, {SetGroup(group=3), NoAction()}] };
// override: symbols=[{Greek_alpha, NoSymbol}, {Greek_ALPHA, NoSymbol}], actions=[{SetGroup(group=3), NoAction()}, {SetGroup(group=3), NoAction()}]
// augment:  symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A]
// key to merge / replace result
key <T097> { symbols=[{Greek_alpha, Greek_upsilon}, {Greek_ALPHA, Greek_UPSILON}] };
// override: symbols=[{Greek_alpha, Greek_upsilon}, {Greek_ALPHA, Greek_UPSILON}]
// augment:  symbols=[a, A]

// base:     actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T098> { actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  actions=[SetGroup(group=2), SetGroup(group=2)]

// base:     symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]
// key to merge / replace result
key <T099> { symbols=[{Greek_alpha, Greek_upsilon}, {Greek_ALPHA, Greek_UPSILON}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: symbols=[{Greek_alpha, Greek_upsilon}, {Greek_ALPHA, Greek_UPSILON}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  symbols=[a, A], actions=[SetGroup(group=2), SetGroup(group=2)]

////// Multiple keysyms -> multiple keysyms //////

// base:     symbols=[{NoSymbol, NoSymbol}, {NoSymbol, NoSymbol}]
// key to merge / replace result
key <T103> { symbols=[{NoSymbol, NoSymbol}, {Greek_ALPHA, Greek_UPSILON}] };
// override: symbols=[{NoSymbol, NoSymbol}, {Greek_ALPHA, Greek_UPSILON}]
// augment:  symbols=[{NoSymbol, NoSymbol}, {Greek_ALPHA, Greek_UPSILON}]

// base:     actions=[{NoAction(), NoAction()}, {NoAction(), NoAction()}]
// key to merge / replace result
key <T104> { actions=[{NoAction(), NoAction()}, {SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: actions=[{NoAction(), NoAction()}, {SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  actions=[{NoAction(), NoAction()}, {SetGroup(group=3), SetMods(mods=Mod5)}]

// base:     symbols=[{NoSymbol, NoSymbol}, {NoSymbol, NoSymbol}]
// key to merge / replace result
key <T105> { symbols=[{NoSymbol, NoSymbol}, {Greek_ALPHA, Greek_UPSILON}], actions=[{NoAction(), NoAction()}, {SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: symbols=[{NoSymbol, NoSymbol}, {Greek_ALPHA, Greek_UPSILON}], actions=[{NoAction(), NoAction()}, {SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  symbols=[{NoSymbol, NoSymbol}, {Greek_ALPHA, Greek_UPSILON}], actions=[{NoAction(), NoAction()}, {SetGroup(group=3), SetMods(mods=Mod5)}]

// base:     symbols=[{NoSymbol, NoSymbol}, {NoSymbol, NoSymbol}]
// key to merge / replace result
key <T106> { symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, Greek_BETA}] };
// override: symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, Greek_BETA}]
// augment:  symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, Greek_BETA}]

// base:     actions=[{NoAction(), NoAction()}, {NoAction(), NoAction()}]
// key to merge / replace result
key <T107> { actions=[{SetGroup(group=3), NoAction()}, {NoAction(), SetGroup(group=3)}] };
// override: actions=[{SetGroup(group=3), NoAction()}, {NoAction(), SetGroup(group=3)}]
// augment:  actions=[{SetGroup(group=3), NoAction()}, {NoAction(), SetGroup(group=3)}]

// base:     symbols=[{NoSymbol, NoSymbol}, {NoSymbol, NoSymbol}]
// key to merge / replace result
key <T108> { symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, Greek_BETA}], actions=[{SetGroup(group=3), NoAction()}, {NoAction(), SetGroup(group=3)}] };
// override: symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, Greek_BETA}], actions=[{SetGroup(group=3), NoAction()}, {NoAction(), SetGroup(group=3)}]
// augment:  symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, Greek_BETA}], actions=[{SetGroup(group=3), NoAction()}, {NoAction(), SetGroup(group=3)}]

// base:     symbols=[{NoSymbol, NoSymbol}, {A, Y}]
// key to merge / replace result
key <T109> { symbols=[{Greek_alpha, Greek_upsilon}, {Greek_ALPHA, Greek_UPSILON}] };
// override: symbols=[{Greek_alpha, Greek_upsilon}, {Greek_ALPHA, Greek_UPSILON}]
// augment:  symbols=[{Greek_alpha, Greek_upsilon}, {A, Y}]

// base:     actions=[{NoAction(), NoAction()}, {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T110> { actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=2), SetMods(mods=Control)}]

// base:     symbols=[{NoSymbol, NoSymbol}, {A, Y}], actions=[{NoAction(), NoAction()}, {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T111> { symbols=[{Greek_alpha, Greek_upsilon}, {Greek_ALPHA, Greek_UPSILON}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: symbols=[{Greek_alpha, Greek_upsilon}, {Greek_ALPHA, Greek_UPSILON}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  symbols=[{Greek_alpha, Greek_upsilon}, {A, Y}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=2), SetMods(mods=Control)}]

// base:     symbols=[{a, NoSymbol}, {NoSymbol, B}]
// key to merge / replace result
key <T112> { symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, Greek_BETA}] };
// override: symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, Greek_BETA}]
// augment:  symbols=[{a, NoSymbol}, {NoSymbol, B}]

// base:     actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]
// key to merge / replace result
key <T113> { actions=[{SetGroup(group=3), NoAction()}, {NoAction(), SetGroup(group=3)}] };
// override: actions=[{SetGroup(group=3), NoAction()}, {NoAction(), SetGroup(group=3)}]
// augment:  actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]

// base:     symbols=[{a, NoSymbol}, {NoSymbol, B}], actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]
// key to merge / replace result
key <T114> { symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, Greek_BETA}], actions=[{SetGroup(group=3), NoAction()}, {NoAction(), SetGroup(group=3)}] };
// override: symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, Greek_BETA}], actions=[{SetGroup(group=3), NoAction()}, {NoAction(), SetGroup(group=3)}]
// augment:  symbols=[{a, NoSymbol}, {NoSymbol, B}], actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]

// base:     symbols=[{a, NoSymbol}, {NoSymbol, B}]
// key to merge / replace result
key <T115> { symbols=[{Greek_alpha, Greek_upsilon}, {Greek_XI, Greek_BETA}] };
// override: symbols=[{Greek_alpha, Greek_upsilon}, {Greek_XI, Greek_BETA}]
// augment:  symbols=[{a, Greek_upsilon}, {Greek_XI, B}]

// base:     actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]
// key to merge / replace result
key <T116> { actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=3)}] };
// override: actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=3)}]
// augment:  actions=[{SetGroup(group=2), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=2)}]

// base:     symbols=[{a, NoSymbol}, {NoSymbol, B}], actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]
// key to merge / replace result
key <T117> { symbols=[{Greek_alpha, Greek_upsilon}, {Greek_XI, Greek_BETA}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=3)}] };
// override: symbols=[{Greek_alpha, Greek_upsilon}, {Greek_XI, Greek_BETA}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=3)}]
// augment:  symbols=[{a, Greek_upsilon}, {Greek_XI, B}], actions=[{SetGroup(group=2), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=2)}]

// base:     symbols=[{a, y}, {A, Y}]
// key to merge / replace result
key <T118> { symbols=[{NoSymbol, NoSymbol}, {Greek_ALPHA, Greek_UPSILON}] };
// override: symbols=[{a, y}, {Greek_ALPHA, Greek_UPSILON}]
// augment:  symbols=[{a, y}, {A, Y}]

// base:     actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T119> { actions=[{NoAction(), NoAction()}, {SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetGroup(group=2), SetMods(mods=Control)}]

// base:     symbols=[{a, y}, {A, Y}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T120> { symbols=[{NoSymbol, NoSymbol}, {Greek_ALPHA, Greek_UPSILON}], actions=[{NoAction(), NoAction()}, {SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: symbols=[{a, y}, {Greek_ALPHA, Greek_UPSILON}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  symbols=[{a, y}, {A, Y}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetGroup(group=2), SetMods(mods=Control)}]

// base:     symbols=[{a, y}, {X, B}]
// key to merge / replace result
key <T121> { symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, Greek_BETA}] };
// override: symbols=[{Greek_alpha, y}, {X, Greek_BETA}]
// augment:  symbols=[{a, y}, {X, B}]

// base:     actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetMods(mods=Control), SetGroup(group=2)}]
// key to merge / replace result
key <T122> { actions=[{SetGroup(group=3), NoAction()}, {NoAction(), SetGroup(group=3)}] };
// override: actions=[{SetGroup(group=3), SetMods(mods=Control)}, {SetMods(mods=Control), SetGroup(group=3)}]
// augment:  actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetMods(mods=Control), SetGroup(group=2)}]

// base:     symbols=[{a, y}, {X, B}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetMods(mods=Control), SetGroup(group=2)}]
// key to merge / replace result
key <T123> { symbols=[{Greek_alpha, NoSymbol}, {NoSymbol, Greek_BETA}], actions=[{SetGroup(group=3), NoAction()}, {NoAction(), SetGroup(group=3)}] };
// override: symbols=[{Greek_alpha, y}, {X, Greek_BETA}], actions=[{SetGroup(group=3), SetMods(mods=Control)}, {SetMods(mods=Control), SetGroup(group=3)}]
// augment:  symbols=[{a, y}, {X, B}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetMods(mods=Control), SetGroup(group=2)}]

// base:     symbols=[{NoSymbol, NoSymbol}, {NoSymbol, NoSymbol, NoSymbol}]
// key to merge / replace result
key <T124> { symbols=[{NoSymbol, NoSymbol, NoSymbol}, {NoSymbol, NoSymbol}] };
// override: symbols=[{NoSymbol, NoSymbol}, {NoSymbol, NoSymbol, NoSymbol}]
// augment:  symbols=[{NoSymbol, NoSymbol}, {NoSymbol, NoSymbol, NoSymbol}]

// base:     actions=[{NoAction(), NoAction()}, {NoAction(), NoAction(), NoAction()}]
// key to merge / replace result
key <T125> { actions=[{NoAction(), NoAction(), NoAction()}, {NoAction(), NoAction()}] };
// override: actions=[{NoAction(), NoAction()}, {NoAction(), NoAction(), NoAction()}]
// augment:  actions=[{NoAction(), NoAction()}, {NoAction(), NoAction(), NoAction()}]

// base:     symbols=[{NoSymbol, NoSymbol}, {NoSymbol, NoSymbol, NoSymbol}]
// key to merge / replace result
key <T126> { symbols=[{NoSymbol, NoSymbol, NoSymbol}, {NoSymbol, NoSymbol}] };
// override: symbols=[{NoSymbol, NoSymbol}, {NoSymbol, NoSymbol, NoSymbol}]
// augment:  symbols=[{NoSymbol, NoSymbol}, {NoSymbol, NoSymbol, NoSymbol}]

// base:     symbols=[{NoSymbol, NoSymbol}, {NoSymbol, NoSymbol, NoSymbol}]
// key to merge / replace result
key <T127> { symbols=[{Greek_alpha, NoSymbol, Greek_xi}, {Greek_XI, Greek_BETA}] };
// override: symbols=[{Greek_alpha, NoSymbol, Greek_xi}, {Greek_XI, Greek_BETA}]
// augment:  symbols=[{Greek_alpha, NoSymbol, Greek_xi}, {Greek_XI, Greek_BETA}]

// base:     actions=[{NoAction(), NoAction()}, {NoAction(), NoAction(), NoAction()}]
// key to merge / replace result
key <T128> { actions=[{SetGroup(group=3), NoAction(), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=3)}] };
// override: actions=[{SetGroup(group=3), NoAction(), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=3)}]
// augment:  actions=[{SetGroup(group=3), NoAction(), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=3)}]

// base:     symbols=[{NoSymbol, NoSymbol}, {NoSymbol, NoSymbol, NoSymbol}]
// key to merge / replace result
key <T129> { symbols=[{Greek_alpha, NoSymbol, Greek_xi}, {Greek_XI, Greek_BETA}], actions=[{SetGroup(group=3), NoAction(), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=3)}] };
// override: symbols=[{Greek_alpha, NoSymbol, Greek_xi}, {Greek_XI, Greek_BETA}], actions=[{SetGroup(group=3), NoAction(), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=3)}]
// augment:  symbols=[{Greek_alpha, NoSymbol, Greek_xi}, {Greek_XI, Greek_BETA}], actions=[{SetGroup(group=3), NoAction(), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=3)}]

// base:     symbols=[{a, y}, {X, NoSymbol, A}]
// key to merge / replace result
key <T130> { symbols=[{NoSymbol, NoSymbol, NoSymbol}, {NoSymbol, NoSymbol}] };
// override: symbols=[{a, y}, {X, NoSymbol, A}]
// augment:  symbols=[{a, y}, {X, NoSymbol, A}]

// base:     actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetMods(mods=Control), NoAction(), SetGroup(group=2)}]
// key to merge / replace result
key <T131> { actions=[{NoAction(), NoAction(), NoAction()}, {NoAction(), NoAction()}] };
// override: actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetMods(mods=Control), NoAction(), SetGroup(group=2)}]
// augment:  actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetMods(mods=Control), NoAction(), SetGroup(group=2)}]

// base:     symbols=[{a, y}, {X, NoSymbol, A}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetMods(mods=Control), NoAction(), SetGroup(group=2)}]
// key to merge / replace result
key <T132> { symbols=[{NoSymbol, NoSymbol, NoSymbol}, {NoSymbol, NoSymbol}] };
// override: symbols=[{a, y}, {X, NoSymbol, A}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetMods(mods=Control), NoAction(), SetGroup(group=2)}]
// augment:  symbols=[{a, y}, {X, NoSymbol, A}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetMods(mods=Control), NoAction(), SetGroup(group=2)}]

// base:     symbols=[{a, y}, {X, NoSymbol, A}]
// key to merge / replace result
key <T133> { symbols=[{Greek_alpha, NoSymbol, Greek_xi}, {Greek_XI, Greek_BETA}] };
// override: symbols=[{Greek_alpha, NoSymbol, Greek_xi}, {Greek_XI, Greek_BETA}]
// augment:  symbols=[{a, y}, {X, NoSymbol, A}]

// base:     actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetMods(mods=Control), NoAction(), SetGroup(group=2)}]
// key to merge / replace result
key <T134> { actions=[{SetGroup(group=3), NoAction(), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=3)}] };
// override: actions=[{SetGroup(group=3), NoAction(), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=3)}]
// augment:  actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetMods(mods=Control), NoAction(), SetGroup(group=2)}]

// base:     symbols=[{a, y}, {X, NoSymbol, A}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetMods(mods=Control), NoAction(), SetGroup(group=2)}]
// key to merge / replace result
key <T135> { symbols=[{Greek_alpha, NoSymbol, Greek_xi}, {Greek_XI, Greek_BETA}], actions=[{SetGroup(group=3), NoAction(), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=3)}] };
// override: symbols=[{Greek_alpha, NoSymbol, Greek_xi}, {Greek_XI, Greek_BETA}], actions=[{SetGroup(group=3), NoAction(), SetMods(mods=Mod5)}, {SetMods(mods=Mod5), SetGroup(group=3)}]
// augment:  symbols=[{a, y}, {X, NoSymbol, A}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetMods(mods=Control), NoAction(), SetGroup(group=2)}]

////// Multiple keysyms -> single keysyms //////

// base:     symbols=[{NoSymbol, NoSymbol}, {A, Y}]
// key to merge / replace result
key <T136> { symbols=[NoSymbol, NoSymbol] };
// override: symbols=[{NoSymbol, NoSymbol}, {A, Y}]
// augment:  symbols=[{NoSymbol, NoSymbol}, {A, Y}]

// base:     actions=[{NoAction(), NoAction()}, {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T137> { actions=[NoAction(), NoAction()] };
// override: actions=[{NoAction(), NoAction()}, {SetGroup(group=2), SetMods(mods=Control)}]
// augment:  actions=[{NoAction(), NoAction()}, {SetGroup(group=2), SetMods(mods=Control)}]

// base:     symbols=[{NoSymbol, NoSymbol}, {A, Y}], actions=[{NoAction(), NoAction()}, {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T138> { symbols=[NoSymbol, NoSymbol] };
// override: symbols=[{NoSymbol, NoSymbol}, {A, Y}], actions=[{NoAction(), NoAction()}, {SetGroup(group=2), SetMods(mods=Control)}]
// augment:  symbols=[{NoSymbol, NoSymbol}, {A, Y}], actions=[{NoAction(), NoAction()}, {SetGroup(group=2), SetMods(mods=Control)}]

// base:     symbols=[{NoSymbol, NoSymbol}, {A, Y}]
// key to merge / replace result
key <T139> { symbols=[Greek_alpha, Greek_ALPHA] };
// override: symbols=[Greek_alpha, Greek_ALPHA]
// augment:  symbols=[Greek_alpha, {A, Y}]

// base:     actions=[{NoAction(), NoAction()}, {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T140> { actions=[SetGroup(group=3), SetGroup(group=3)] };
// override: actions=[SetGroup(group=3), SetGroup(group=3)]
// augment:  actions=[SetGroup(group=3), {SetGroup(group=2), SetMods(mods=Control)}]

// base:     symbols=[{NoSymbol, NoSymbol}, {A, Y}], actions=[{NoAction(), NoAction()}, {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T141> { symbols=[Greek_alpha, Greek_ALPHA], actions=[SetGroup(group=3), SetGroup(group=3)] };
// override: symbols=[Greek_alpha, Greek_ALPHA], actions=[SetGroup(group=3), SetGroup(group=3)]
// augment:  symbols=[Greek_alpha, {A, Y}], actions=[SetGroup(group=3), {SetGroup(group=2), SetMods(mods=Control)}]

// base:     symbols=[{a, NoSymbol}, {NoSymbol, B}]
// key to merge / replace result
key <T142> { symbols=[NoSymbol, NoSymbol] };
// override: symbols=[{a, NoSymbol}, {NoSymbol, B}]
// augment:  symbols=[{a, NoSymbol}, {NoSymbol, B}]

// base:     actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]
// key to merge / replace result
key <T143> { actions=[NoAction(), NoAction()] };
// override: actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]
// augment:  actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]

// base:     symbols=[{a, NoSymbol}, {NoSymbol, B}], actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]
// key to merge / replace result
key <T144> { symbols=[NoSymbol, NoSymbol] };
// override: symbols=[{a, NoSymbol}, {NoSymbol, B}], actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]
// augment:  symbols=[{a, NoSymbol}, {NoSymbol, B}], actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]

// base:     symbols=[{a, NoSymbol}, {NoSymbol, B}]
// key to merge / replace result
key <T145> { symbols=[Greek_alpha, Greek_ALPHA] };
// override: symbols=[Greek_alpha, Greek_ALPHA]
// augment:  symbols=[{a, NoSymbol}, {NoSymbol, B}]

// base:     actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]
// key to merge / replace result
key <T146> { actions=[SetGroup(group=3), SetGroup(group=3)] };
// override: actions=[SetGroup(group=3), SetGroup(group=3)]
// augment:  actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]

// base:     symbols=[{a, NoSymbol}, {NoSymbol, B}], actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]
// key to merge / replace result
key <T147> { symbols=[Greek_alpha, Greek_ALPHA], actions=[SetGroup(group=3), SetGroup(group=3)] };
// override: symbols=[Greek_alpha, Greek_ALPHA], actions=[SetGroup(group=3), SetGroup(group=3)]
// augment:  symbols=[{a, NoSymbol}, {NoSymbol, B}], actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetGroup(group=2)}]

////// Mix //////

// base:     actions=[SetGroup(group=2)]
// key to merge / replace result
key <T150> { actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  actions=[SetGroup(group=2), {SetGroup(group=3), SetMods(mods=Mod5)}]

// base:     actions=[{SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T153> { actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, SetGroup(group=3)] };
// override: actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, SetGroup(group=3)]
// augment:  actions=[{SetGroup(group=2), SetMods(mods=Control)}, SetGroup(group=3)]

// base:     actions=[SetGroup(group=2), {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T156> { actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, SetGroup(group=3)] };
// override: actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, SetGroup(group=3)]
// augment:  actions=[SetGroup(group=2), {SetGroup(group=2), SetMods(mods=Control)}]

////// Mix //////

// base:     symbols=[a, NoSymbol], actions=[NoAction(), SetGroup(group=2)]
// key to merge / replace result
key <T159> { symbols=[NoSymbol, {X, Y}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, NoAction()] };
// override: symbols=[NoSymbol, {X, Y}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, NoAction()]
// augment:  symbols=[a, NoSymbol], actions=[NoAction(), SetGroup(group=2)]

////// Multiple keysyms/actions –> single //////

// base:     symbols=[{a, b}, NoSymbol], actions=[NoAction(), {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T162> { symbols=[NoSymbol, X], actions=[SetGroup(group=3), NoAction()] };
// override: symbols=[NoSymbol, X], actions=[SetGroup(group=3), NoAction()]
// augment:  symbols=[{a, b}, NoSymbol], actions=[NoAction(), {SetGroup(group=2), SetMods(mods=Control)}]

////// Multiple keysyms/actions –> multiple (xor) //////

// base:     symbols=[{a, b}, NoSymbol], actions=[NoAction(), {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T165> { symbols=[NoSymbol, {X, Y}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, NoAction()] };
// override: symbols=[{a, b}, {X, Y}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=2), SetMods(mods=Control)}]
// augment:  symbols=[{a, b}, {X, Y}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=2), SetMods(mods=Control)}]

////// Multiple keysyms/actions –> multiple (mix) //////

// base:     symbols=[{a, NoSymbol}, NoSymbol], actions=[NoAction(), {SetGroup(group=2), NoAction()}]
// key to merge / replace result
key <T168> { symbols=[{x, y}, {X, Y}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: symbols=[{x, y}, {X, Y}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  symbols=[{a, y}, {X, Y}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=2), SetMods(mods=Mod5)}]

// base:     symbols=[{a, b}, NoSymbol], actions=[NoAction(), {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T171> { symbols=[{x, NoSymbol}, {X, Y}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), NoAction()}] };
// override: symbols=[{x, b}, {X, Y}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Control)}]
// augment:  symbols=[{a, b}, {X, Y}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, {SetGroup(group=2), SetMods(mods=Control)}]

////// Multiple (mix) –> multiple keysyms/actions //////

// base:     symbols=[{a, b}, {A, B}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T174> { symbols=[{x, NoSymbol}, NoSymbol], actions=[NoAction(), {SetGroup(group=3), NoAction()}] };
// override: symbols=[{x, b}, {A, B}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetGroup(group=3), SetMods(mods=Control)}]
// augment:  symbols=[{a, b}, {A, B}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetGroup(group=2), SetMods(mods=Control)}]

// base:     symbols=[{a, NoSymbol}, {A, B}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetGroup(group=2), NoAction()}]
// key to merge / replace result
key <T177> { symbols=[{x, y}, NoSymbol], actions=[NoAction(), {SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: symbols=[{x, y}, {A, B}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  symbols=[{a, y}, {A, B}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetGroup(group=2), SetMods(mods=Mod5)}]

////// Multiple (mix) –> multiple (mix) //////

// base:     symbols=[{a, b}, {NoSymbol, B}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetGroup(group=2), NoAction()}]
// key to merge / replace result
key <T180> { symbols=[{NoSymbol, y}, {X, Y}], actions=[{SetGroup(group=3), NoAction()}, {SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: symbols=[{a, y}, {X, Y}], actions=[{SetGroup(group=3), SetMods(mods=Control)}, {SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  symbols=[{a, b}, {X, B}], actions=[{SetGroup(group=2), SetMods(mods=Control)}, {SetGroup(group=2), SetMods(mods=Mod5)}]

// base:     symbols=[{a, NoSymbol}, {NoSymbol, B}], actions=[{SetGroup(group=2), NoAction()}, {NoAction(), SetMods(mods=Control)}]
// key to merge / replace result
key <T183> { symbols=[{NoSymbol, y}, {X, NoSymbol}], actions=[{NoAction(), SetMods(mods=Mod5)}, {SetGroup(group=3), NoAction()}] };
// override: symbols=[{a, y}, {X, B}], actions=[{SetGroup(group=2), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Control)}]
// augment:  symbols=[{a, y}, {X, B}], actions=[{SetGroup(group=2), SetMods(mods=Mod5)}, {SetGroup(group=3), SetMods(mods=Control)}]

////// Mismatch count with mix //////

// base:     symbols=[a, {A, B}]
// key to merge / replace result
key <T186> { actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, SetGroup(group=3)] };
// override: actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, SetGroup(group=3)]
// augment:  symbols=[a, {A, B}]

// base:     actions=[SetGroup(group=3), {SetGroup(group=3), SetMods(mods=Mod5)}]
// key to merge / replace result
key <T189> { symbols=[{A, B}, a] };
// override: symbols=[{A, B}, a]
// augment:  actions=[SetGroup(group=3), {SetGroup(group=3), SetMods(mods=Mod5)}]

// base:     symbols=[a, {A, B}], actions=[SetGroup(group=2), {SetGroup(group=2), SetMods(mods=Control)}]
// key to merge / replace result
key <T192> { symbols=[{x, y}, X], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, SetGroup(group=3)] };
// override: symbols=[{x, y}, X], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}, SetGroup(group=3)]
// augment:  symbols=[a, {A, B}], actions=[SetGroup(group=2), {SetGroup(group=2), SetMods(mods=Control)}]

////// Issue #564 //////

// base:     symbols=[A]
// key to merge / replace result
key <T204> { symbols=[{A, A}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}] };
// override: symbols=[{A, A}], actions=[{SetGroup(group=3), SetMods(mods=Mod5)}]
// augment:  symbols=[A]

@wismill wismill mentioned this pull request Jan 14, 2025
3 tasks
@wismill wismill force-pushed the symbols/fix-key-merge-mode-symbols branch 2 times, most recently from 6d63757 to ac1aca4 Compare January 15, 2025 06:26
This commit adds tests for merging various key configurations:

- With/without keysyms/actions
- Single/multiple keysyms/actions per level

We test all the merge modes for including a map (global) as well as
directly on the keys (local):

- default (global: include, local: implicit)
- augment
- override
- replace

The tests data are generated with:

- A Python script `scripts/update-merge-modes-tests.py` for keycodes
  and symbols data. Use `--debug` for extra comments to help debugging.
  The script can optionally generate C headers for alternative key
  sequence tests, that were used before implementing golden tests.
  The latter tests are not used anymore (duplicate with golden tests)
  but their generator is kept for now, as they can still be useful for
  debugging or writing similar tests.
- The `merge-modes` test generates its own keymap files for golden
  tests, using: `build/test-merge-modes update`. It can also replace
  them with the obtained output rather than the expected one using
  `build/test-merge-modes update-obtained`, which is very useful for
  debugging.
- Fixed field for defined keysyms/actions
- Fixed regression introduced by fdf2c52
@wismill wismill force-pushed the symbols/fix-key-merge-mode-symbols branch from ac1aca4 to 5f82d35 Compare January 15, 2025 12:33
@wismill wismill merged commit d43bb95 into xkbcommon:master Jan 15, 2025
4 checks passed
@wismill wismill deleted the symbols/fix-key-merge-mode-symbols branch January 15, 2025 12:35
@mahkoh
Copy link

mahkoh commented Jan 15, 2025

I've compared the test cases and the only significant differences between this and my implementation are as follows:

  • The symbols in a level are either all applied or none are applied. { a, NoSymbol } and { NoSymbol, b } do not merge to { a, b }.
  • Symbols and actions are merged independently with no requirement that they have the same cardinality.

@wismill
Copy link
Member Author

wismill commented Jan 15, 2025

  • The symbols in a level are either all applied or none are applied. { a, NoSymbol } and { NoSymbol, b } do not merge to { a, b }.

@mahkoh It means that with your implementation one cannot partially update a keysym list for one level, correct? Why not allowing it?

  • Symbols and actions are merged independently with no requirement that they have the same cardinality.

Usually the actions mirror the keysyms; is it not counter-intuitive to handle them completely separately? Multiple actions per levels are pretty new, but the idea was to have keysyms count = actions count, to make it more intuitive. Do you have a use case for different keysyms and actions count?

@mahkoh
Copy link

mahkoh commented Jan 15, 2025

@mahkoh It means that with your implementation one cannot partially update a keysym list for one level, correct? Why not allowing it?

I'm already a bit concerned about allowing symbols and actions of the same level to be updated independently. For example, consider

key <a> { [ a ] };
augment key <a> { [ Shift_L ], [ SetMods(mods = Shift) ] };

This produces

key <a> { [ a ], [ SetMods(mods = Shift) ] };

which is a bit confusing. Ideally both the symbols and actions of a single level would remain consistent. But since xkbcomp updates them separately, I went with that.

Since xkbcomp doesn't handle multiple objects per level, I decided to be a bit more conservative here.

Usually the actions mirror the keysyms; is it not counter-intuitive to handle them completely separately? Multiple actions per levels are pretty new, but the idea was to have keysyms count = actions count, to make it more intuitive. Do you have a use case for different keysyms and actions count?

I assume that this notion comes from the interpret declarations which connect keysyms and actions. As long as there is this close relationship, it makes sense for things to be symmetric.

However, I believe that this whole interpret stuff is unnecessary complexity. When reading a keymap, I very much prefer the key declarations to contain their actions directly instead of going via the interpret indirection. This makes it much easier to se what is happening when a key is pressed. And once you sever this connection, I don't believe that there is any reason for there to be any symmetry between symbols and actions.

In particular, when formatting keymaps, I always list all actions explicitly and only emit a single interpret statement to work around https://gitlab.freedesktop.org/xorg/lib/libxkbfile/-/issues/12.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Indicates an unexpected problem or unintended behavior compile-keymap Indicates a need for improvements or additions to keymap compilation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Abort when augmenting key definition
3 participants