Skip to content

Commit c85c9bd

Browse files
committed
symbols: Allow levels with different keysyms and actions counts
Contrary to groups, there is no reason for levels to restrict the same count of keysyms and actions.
1 parent 27ac30b commit c85c9bd

20 files changed

+940
-808
lines changed

changes/api/486.multiple-actions-per-level.feature.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
symbols: Added support for *multiple actions per levels:*
2-
- *1 keysym == 1 action* now holds for every keysym count.
32
- When no action is specified, `interpret` statements are used to find an action corresponding for *each* keysym, as expected.
4-
- When both keysyms and actions are specified, they should have the exact same count for each level.
3+
- When both keysyms and actions are specified, they may have a different count for each level.
54
- For now, at most one action of each following categories is allowed per level:
65
- modifier actions: `SetMods`, `LatchMods`, `LockMods`;
76
- group actions: `SetGroup`, `LatchGroup`, `LockGroup`.

doc/keymap-format-text-v1.md

+11-2
Original file line numberDiff line numberDiff line change
@@ -1629,10 +1629,19 @@ result in `Control + Q`, because the actions are run sequentially: first set the
16291629
base modifiers to Control, then switch to the second layout while `Control` is
16301630
pressed.
16311631
1632+
@remark
1633+
Given a level, keysyms and actions may have a *different count*. For instance,
1634+
the following would achieve the same effect than the former example with only
1635+
1 keysym, but it requires to use 2 explicit actions:
1636+
```c
1637+
key <LCTL> {
1638+
symbols[1] = [ Control_L ],
1639+
actions[1] = [ { SetMods(modifiers=Control), SetGroup(group=+1) } ]
1640+
};
1641+
```
1642+
16321643
@note
16331644
There are some *limitations* with this extension:
1634-
- When both keysyms and actions are specified, they should have the exact
1635-
*same count* for each level.
16361645
- For now, *at most one* action of each following categories is allowed per
16371646
level:
16381647
- [modifier actions][]: `SetMods`, `LatchMods`, `LockMods`;

scripts/update-merge-modes-tests.py

+63-32
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,12 @@
228228
"CLOSE",
229229
"PLAY",
230230
"FASTFORWARD",
231+
"BASSBOOST",
232+
"PRINT",
233+
"HP",
234+
"CAMERA",
235+
"SOUND",
236+
"QUESTION",
231237
)
232238

233239

@@ -1309,8 +1315,8 @@ def write_c_tests(
13091315
Level.Actions(Modifier.LevelThree, 3),
13101316
),
13111317
augment=KeyEntry(
1312-
Level.Actions(2, Modifier.LevelThree),
1313-
Level.Actions(Modifier.LevelThree, 2),
1318+
Level.Actions(2, None),
1319+
Level.Actions(None, 2),
13141320
),
13151321
override=KeyEntry(
13161322
Level.Actions(3, Modifier.LevelThree),
@@ -1344,9 +1350,7 @@ def write_c_tests(
13441350
augment=KeyEntry(
13451351
Level.Actions(2, Modifier.Control), Level.Actions(Modifier.Control, 2)
13461352
),
1347-
override=KeyEntry(
1348-
Level.Actions(3, Modifier.Control), Level.Actions(Modifier.Control, 3)
1349-
),
1353+
override=KeyEntry(Level.Actions(3, None), Level.Actions(None, 3)),
13501354
implementations=Implementation.xkbcommon,
13511355
),
13521356
TestEntry(
@@ -1490,9 +1494,13 @@ def write_c_tests(
14901494
update=KeyEntry(
14911495
Level.Actions(3, Modifier.LevelThree), Level.Keysyms("X", "Y")
14921496
),
1493-
augment=KeyEntry(Level.Keysyms("a"), Level.Actions(2)),
1497+
augment=KeyEntry(
1498+
Level.Mix(("a",), (3, Modifier.LevelThree)),
1499+
Level.Mix(("X", "Y"), (2,)),
1500+
),
14941501
override=KeyEntry(
1495-
Level.Actions(3, Modifier.LevelThree), Level.Keysyms("X", "Y")
1502+
Level.Mix(("a",), (3, Modifier.LevelThree)),
1503+
Level.Mix(("X", "Y"), (2,)),
14961504
),
14971505
implementations=Implementation.xkbcommon,
14981506
),
@@ -1502,9 +1510,13 @@ def write_c_tests(
15021510
KeyEntry(Level.Keysyms("a", "b"), Level.Actions(2, Modifier.Control)),
15031511
update=KeyEntry(Level.Actions(3), Level.Keysyms("X")),
15041512
augment=KeyEntry(
1505-
Level.Keysyms("a", "b"), Level.Actions(2, Modifier.Control)
1513+
Level.Mix(("a", "b"), (3,)),
1514+
Level.Mix(("X",), (2, Modifier.Control)),
1515+
),
1516+
override=KeyEntry(
1517+
Level.Mix(("a", "b"), (3,)),
1518+
Level.Mix(("X",), (2, Modifier.Control)),
15061519
),
1507-
override=KeyEntry(Level.Actions(3), Level.Keysyms("X")),
15081520
implementations=Implementation.xkbcommon,
15091521
),
15101522
Comment("Multiple keysyms/actions –> multiple (xor)"),
@@ -1533,8 +1545,8 @@ def write_c_tests(
15331545
Level.Mix(("X", "Y"), (3, Modifier.LevelThree)),
15341546
),
15351547
augment=KeyEntry(
1536-
Level.Mix(("a", "y"), (3, Modifier.LevelThree)),
1537-
Level.Mix(("X", "Y"), (2, Modifier.LevelThree)),
1548+
Level.Mix(("a", None), (3, Modifier.LevelThree)),
1549+
Level.Mix(("X", "Y"), (2, None)),
15381550
),
15391551
override=KeyEntry(
15401552
Level.Mix(("x", "y"), (3, Modifier.LevelThree)),
@@ -1554,8 +1566,8 @@ def write_c_tests(
15541566
Level.Mix(("X", "Y"), (2, Modifier.Control)),
15551567
),
15561568
override=KeyEntry(
1557-
Level.Mix(("x", "b"), (3, Modifier.LevelThree)),
1558-
Level.Mix(("X", "Y"), (3, Modifier.Control)),
1569+
Level.Mix(("x", None), (3, Modifier.LevelThree)),
1570+
Level.Mix(("X", "Y"), (3, None)),
15591571
),
15601572
implementations=Implementation.xkbcommon,
15611573
),
@@ -1572,8 +1584,8 @@ def write_c_tests(
15721584
Level.Mix(("A", "B"), (2, Modifier.Control)),
15731585
),
15741586
override=KeyEntry(
1575-
Level.Mix(("x", "b"), (2, Modifier.Control)),
1576-
Level.Mix(("A", "B"), (3, Modifier.Control)),
1587+
Level.Mix(("x", None), (2, Modifier.Control)),
1588+
Level.Mix(("A", "B"), (3, None)),
15771589
),
15781590
implementations=Implementation.xkbcommon,
15791591
),
@@ -1587,8 +1599,8 @@ def write_c_tests(
15871599
Level.Keysyms("x", "y"), Level.Actions(3, Modifier.LevelThree)
15881600
),
15891601
augment=KeyEntry(
1590-
Level.Mix(("a", "y"), (2, Modifier.Control)),
1591-
Level.Mix(("A", "B"), (2, Modifier.LevelThree)),
1602+
Level.Mix(("a", None), (2, Modifier.Control)),
1603+
Level.Mix(("A", "B"), (2, None)),
15921604
),
15931605
override=KeyEntry(
15941606
Level.Mix(("x", "y"), (2, Modifier.Control)),
@@ -1609,10 +1621,10 @@ def write_c_tests(
16091621
),
16101622
augment=KeyEntry(
16111623
Level.Mix(("a", "b"), (2, Modifier.Control)),
1612-
Level.Mix(("X", "B"), (2, Modifier.LevelThree)),
1624+
Level.Mix((None, "B"), (2, None)),
16131625
),
16141626
override=KeyEntry(
1615-
Level.Mix(("a", "y"), (3, Modifier.Control)),
1627+
Level.Mix((None, "y"), (3, None)),
16161628
Level.Mix(("X", "Y"), (3, Modifier.LevelThree)),
16171629
),
16181630
implementations=Implementation.xkbcommon,
@@ -1628,12 +1640,12 @@ def write_c_tests(
16281640
Level.Mix(("X", None), (3, None)),
16291641
),
16301642
augment=KeyEntry(
1631-
Level.Mix(("a", "y"), (2, Modifier.LevelThree)),
1632-
Level.Mix(("X", "B"), (3, Modifier.Control)),
1643+
Level.Mix(("a", None), (2, None)),
1644+
Level.Mix((None, "B"), (None, Modifier.Control)),
16331645
),
16341646
override=KeyEntry(
1635-
Level.Mix(("a", "y"), (2, Modifier.LevelThree)),
1636-
Level.Mix(("X", "B"), (3, Modifier.Control)),
1647+
Level.Mix((None, "y"), (None, Modifier.LevelThree)),
1648+
Level.Mix(("X", None), (3, None)),
16371649
),
16381650
implementations=Implementation.xkbcommon,
16391651
),
@@ -1649,12 +1661,12 @@ def write_c_tests(
16491661
Level.Actions(3),
16501662
),
16511663
augment=KeyEntry(
1652-
Level.Keysyms("a"),
1653-
Level.Keysyms("A", "B"),
1664+
Level.Mix(("a"), (3, Modifier.LevelThree)),
1665+
Level.Mix(("A", "B"), (3,)),
16541666
),
16551667
override=KeyEntry(
1656-
Level.Actions(3, Modifier.LevelThree),
1657-
Level.Actions(3),
1668+
Level.Mix(("a"), (3, Modifier.LevelThree)),
1669+
Level.Mix(("A", "B"), (3,)),
16581670
),
16591671
implementations=Implementation.xkbcommon,
16601672
),
@@ -1669,12 +1681,12 @@ def write_c_tests(
16691681
Level.Keysyms("a"),
16701682
),
16711683
augment=KeyEntry(
1672-
Level.Actions(3),
1673-
Level.Actions(3, Modifier.LevelThree),
1684+
Level.Mix(("A", "B"), (3,)),
1685+
Level.Mix(("a"), (3, Modifier.LevelThree)),
16741686
),
16751687
override=KeyEntry(
1676-
Level.Keysyms("A", "B"),
1677-
Level.Keysyms("a"),
1688+
Level.Mix(("A", "B"), (3,)),
1689+
Level.Mix(("a"), (3, Modifier.LevelThree)),
16781690
),
16791691
implementations=Implementation.xkbcommon,
16801692
),
@@ -1703,10 +1715,29 @@ def write_c_tests(
17031715
TestId(TestType.KeysymsAndActions),
17041716
KeyEntry(Level.Keysyms("A")),
17051717
update=KeyEntry(Level.Mix(("A", "A"), (3, Modifier.LevelThree))),
1706-
augment=KeyEntry(Level.Keysyms("A")),
1718+
augment=KeyEntry(Level.Mix(("A",), (3, Modifier.LevelThree))),
17071719
override=KeyEntry(Level.Mix(("A", "A"), (3, Modifier.LevelThree))),
17081720
implementations=Implementation.xkbcommon,
17091721
),
1722+
Comment("Drop NoSymbol/NoAction"),
1723+
TestEntry(
1724+
TestId(TestType.KeysymsAndActions),
1725+
KeyEntry(Level.Mix(("A",), (2,))),
1726+
update=KeyEntry(Level.Mix((None, "Y", None), (None, 3, None))),
1727+
augment=KeyEntry(Level.Mix(("A",), (2,))),
1728+
override=KeyEntry(Level.Mix(("Y",), (3,))),
1729+
implementations=Implementation.xkbcommon,
1730+
),
1731+
Comment("Drop NoSymbol/NoAction and invalid keysyms"),
1732+
TestEntry(
1733+
TestId(TestType.KeysymsAndActions),
1734+
KeyEntry(Level.Mix(("notAKeysym", None, "thisEither"), (None, None))),
1735+
update=KeyEntry(Level.Mix((None, None), (None, None))),
1736+
augment=KeyEntry(Level.Keysyms(None)),
1737+
override=KeyEntry(Level.Keysyms(None)),
1738+
replace=KeyEntry(Level.Keysyms(None)),
1739+
implementations=Implementation.xkbcommon,
1740+
),
17101741
),
17111742
).add_keysyms()
17121743

src/keymap-priv.c

+4-32
Original file line numberDiff line numberDiff line change
@@ -152,42 +152,14 @@ XkbLevelsSameSyms(const struct xkb_level *a, const struct xkb_level *b)
152152
return memcmp(a->s.syms, b->s.syms, sizeof(*a->s.syms) * a->num_syms) == 0;
153153
}
154154

155-
bool
156-
XkbLevelHasNoKeysym(const struct xkb_level *level)
157-
{
158-
if (level->num_syms == 0)
159-
return true;
160-
if (level->num_syms == 1)
161-
return level->s.sym == XKB_KEY_NoSymbol;
162-
for (unsigned int k = 0; k < level->num_syms; k++) {
163-
if (level->s.syms[k] != XKB_KEY_NoSymbol)
164-
return false;
165-
}
166-
return true;
167-
}
168-
169155
bool
170156
XkbLevelsSameActions(const struct xkb_level *a, const struct xkb_level *b)
171157
{
172-
if (a->num_syms != b->num_syms)
158+
if (a->num_actions != b->num_actions)
173159
return false;
174-
if (a->num_syms <= 1)
160+
if (a->num_actions <= 1)
175161
return memcmp(&a->a.action, &b->a.action, sizeof(a->a.action)) == 0;
176-
return memcmp(a->a.actions, b->a.actions, sizeof(*a->a.actions) * a->num_syms) == 0;
177-
}
178-
179-
bool
180-
XkbLevelHasNoAction(const struct xkb_level *level)
181-
{
182-
if (level->num_syms == 0)
183-
return true;
184-
if (level->num_syms == 1)
185-
return level->a.action.type == ACTION_TYPE_NONE;
186-
for (unsigned int k = 0; k < level->num_syms; k++) {
187-
if (level->a.actions[k].type != ACTION_TYPE_NONE)
188-
return false;
189-
}
190-
return true;
162+
return memcmp(a->a.actions, b->a.actions, sizeof(*a->a.actions) * a->num_actions) == 0;
191163
}
192164

193165
xkb_layout_index_t
@@ -247,7 +219,7 @@ xkb_keymap_key_get_actions_by_level(struct xkb_keymap *keymap,
247219
if (level >= XkbKeyNumLevels(key, layout))
248220
goto err;
249221

250-
const unsigned int count = key->groups[layout].levels[level].num_syms;
222+
const unsigned int count = key->groups[layout].levels[level].num_actions;
251223
switch (count) {
252224
case 0:
253225
goto err;

src/keymap.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,12 @@ xkb_keymap_unref(struct xkb_keymap *keymap)
7474
if (key->groups) {
7575
for (unsigned i = 0; i < key->num_groups; i++) {
7676
if (key->groups[i].levels) {
77-
for (unsigned j = 0; j < XkbKeyNumLevels(key, i); j++)
78-
if (key->groups[i].levels[j].num_syms > 1) {
77+
for (unsigned j = 0; j < XkbKeyNumLevels(key, i); j++) {
78+
if (key->groups[i].levels[j].num_syms > 1)
7979
free(key->groups[i].levels[j].s.syms);
80+
if (key->groups[i].levels[j].num_actions > 1)
8081
free(key->groups[i].levels[j].a.actions);
81-
}
82+
}
8283
free(key->groups[i].levels);
8384
}
8485
}

src/keymap.h

+5-9
Original file line numberDiff line numberDiff line change
@@ -316,17 +316,19 @@ enum xkb_explicit_components {
316316
};
317317

318318
struct xkb_level {
319-
/* Count of keysyms/actions */
319+
/* Count of keysyms */
320320
unsigned int num_syms;
321+
/* Count of actions */
322+
unsigned int num_actions;
321323
/* Keysyms */
322324
union {
323325
xkb_keysym_t sym; /* num_syms == 1 */
324326
xkb_keysym_t *syms; /* num_syms > 1 */
325327
} s;
326328
/* Actions */
327329
union {
328-
union xkb_action action; /* num_syms == 1 */
329-
union xkb_action *actions; /* num_syms > 1 */
330+
union xkb_action action; /* num_actions == 1 */
331+
union xkb_action *actions; /* num_actions > 1 */
330332
} a;
331333
};
332334

@@ -505,15 +507,9 @@ XkbModNameToIndex(const struct xkb_mod_set *mods, xkb_atom_t name,
505507
bool
506508
XkbLevelsSameSyms(const struct xkb_level *a, const struct xkb_level *b);
507509

508-
bool
509-
XkbLevelHasNoKeysym(const struct xkb_level *level);
510-
511510
bool
512511
XkbLevelsSameActions(const struct xkb_level *a, const struct xkb_level *b);
513512

514-
bool
515-
XkbLevelHasNoAction(const struct xkb_level *level);
516-
517513
xkb_layout_index_t
518514
XkbWrapGroupIntoRange(int32_t group,
519515
xkb_layout_index_t num_groups,

src/x11/keymap.c

+2
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ get_actions(struct xkb_keymap *keymap, xcb_connection_t *conn,
534534
xcb_xkb_action_t *wire_action = acts_iter.data;
535535

536536
if (level < key->groups[group].type->num_levels) {
537+
key->groups[group].levels[level].num_actions = 1;
537538
union xkb_action *action = &key->groups[group].levels[level].a.action;
538539

539540
translate_action(action, wire_action);
@@ -542,6 +543,7 @@ get_actions(struct xkb_keymap *keymap, xcb_connection_t *conn,
542543
if (action->type == ACTION_TYPE_NONE &&
543544
key->groups[group].levels[level].s.sym == XKB_KEY_NoSymbol) {
544545
key->groups[group].levels[level].num_syms = 0;
546+
key->groups[group].levels[level].num_actions = 0;
545547
}
546548
}
547549

0 commit comments

Comments
 (0)