compose: correctly parse modifier syntax As described in: http://cgit.freedesktop.org/xorg/lib/libX11/commit/?id=ddf3b09bb262d01b56fbaade421ac85b0e60a69f Signed-off-by: Ran Benita <ran234@gmail.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
diff --git a/src/compose/parser.c b/src/compose/parser.c
index 95f0fdd..9e936a9 100644
--- a/src/compose/parser.c
+++ b/src/compose/parser.c
@@ -113,8 +113,9 @@ cached_keysym_from_name(struct keysym_from_name_cache *cache,
* COMMENT ::= "#" {<any character except null or newline>}
* LHS ::= EVENT { EVENT }
* EVENT ::= [MODIFIER_LIST] "<" keysym ">"
- * MODIFIER_LIST ::= ("!" {MODIFIER} ) | "None"
- * MODIFIER ::= ["~"] modifier_name
+ * MODIFIER_LIST ::= (["!"] {MODIFIER} ) | "None"
+ * MODIFIER ::= ["~"] MODIFIER_NAME
+ * MODIFIER_NAME ::= ("Ctrl"|"Lock"|"Caps"|"Shift"|"Alt"|"Meta")
* RHS ::= ( STRING | keysym | STRING keysym )
* STRING ::= '"' { CHAR } '"'
* CHAR ::= GRAPHIC_CHAR | ESCAPED_CHAR
@@ -357,8 +358,9 @@ struct production {
bool has_keysym;
bool has_string;
- xkb_mod_mask_t mods;
+ /* The matching is as follows: (active_mods & modmask) == mods. */
xkb_mod_mask_t modmask;
+ xkb_mod_mask_t mods;
};
static uint32_t
@@ -456,6 +458,9 @@ add_production(struct xkb_compose_table *table, struct scanner *s,
}
}
+/* Should match resolve_modifier(). */
+#define ALL_MODS_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
+
static xkb_mod_index_t
resolve_modifier(const char *name)
{
@@ -587,15 +592,16 @@ lhs_tok:
}
goto rhs;
case TOK_IDENT:
- if (!streq(val.string.str, "None")) {
- scanner_err(s, "unrecognized identifier \"%s\"", val.string.str);
- goto error;
+ if (streq(val.string.str, "None")) {
+ production.mods = 0;
+ production.modmask = ALL_MODS_MASK;
+ goto lhs_keysym;
}
- production.mods = 0;
- /* XXX Should only include the mods in resolve_mods(). */
- production.modmask = 0xff;
- goto lhs_keysym;
+ goto lhs_mod_list_tok;
+ case TOK_TILDE:
+ goto lhs_mod_list_tok;
case TOK_BANG:
+ production.modmask = ALL_MODS_MASK;
goto lhs_mod_list;
default:
goto lhs_keysym_tok;
@@ -625,21 +631,22 @@ lhs_keysym_tok:
goto unexpected;
}
-lhs_mod_list: {
+lhs_mod_list:
+ tok = lex(s, &val);
+lhs_mod_list_tok: {
bool tilde = false;
xkb_mod_index_t mod;
- tok = lex(s, &val);
+ if (tok != TOK_TILDE && tok != TOK_IDENT)
+ goto lhs_keysym_tok;
+
if (tok == TOK_TILDE) {
tilde = true;
tok = lex(s, &val);
}
- if (tok != TOK_IDENT) {
- if (tilde || production.modmask == 0)
- goto unexpected;
- goto lhs_keysym_tok;
- }
+ if (tok != TOK_IDENT)
+ goto unexpected;
mod = resolve_modifier(val.string.str);
if (mod == XKB_MOD_INVALID) {
diff --git a/test/compose.c b/test/compose.c
index 9bbef18..d9f3629 100644
--- a/test/compose.c
+++ b/test/compose.c
@@ -434,6 +434,16 @@ test_modifier_syntax(struct xkb_context *ctx)
assert(test_compose_seq_buffer(ctx,
"None <A> : X \n"
+ "Shift <B> : Y \n"
+ "Ctrl <C> : Y \n"
+ "Alt <D> : Y \n"
+ "Caps <E> : Y \n"
+ "Lock <F> : Y \n"
+ "Shift Ctrl <G> : Y \n"
+ "~Shift <H> : Y \n"
+ "~Shift Ctrl <I> : Y \n"
+ "Shift ~Ctrl <J> : Y \n"
+ "Shift ~Ctrl ~Alt <K> : Y \n"
"! Shift <B> : Y \n"
"! Ctrl <C> : Y \n"
"! Alt <D> : Y \n"
@@ -454,7 +464,7 @@ test_modifier_syntax(struct xkb_context *ctx)
"! None <A> : X \n"
"! Foo <B> : X \n"
"None ! Shift <C> : X \n"
- "! <D> : X \n"
+ "! ! <D> : X \n"
"! ~ <E> : X \n"
"! ! <F> : X \n"
"! Ctrl ! Ctrl <G> : X \n"