2 from __future__ import print_function
5 from pathlib import Path
8 # #define XF86XK_FooBar 0x1234 /* some optional comment */
10 # #define XF86XK_FooBar _EVDEVK(0x123) /* some optional comment */
11 # We also need to match commented evdev entries:
12 # /* Use: XF86XK_FooBar _EVDEVK(0x123) some optional comment */
13 keysym_entry_pattern = re.compile(
15 (?P<define>\#define|/\*\s+Use:)\s+
16 (?P<prefix>\w*)XK_(?P<name>\w+)(?P<spacing>\s+)
17 (?P<evdev>_EVDEVK\()?(?P<value>0x[0-9A-Fa-f]+)(?(evdev)\))
22 # Match keysym guarded by #ifndef
23 keysym_ifndef_pattern = re.compile(r"^#ifndef\s+(?P<prefix>\w*)XK_(?P<name>\w+)\s*$")
25 # Match remaining XK_ references in the comments, e.g we will replace:
26 # XF86XK_CamelCaseKernelName _EVDEVK(kernel value)
27 # #define XKB_KEY_SunCompose 0x0000FF20 /* Same as XK_Multi_key */
29 # XKB_KEY_XF86CamelCaseKernelName _EVDEVK(kernel value)
30 # #define XKB_KEY_SunCompose 0x0000FF20 /* Same as XKB_KEY_Multi_key */
31 xorgproto_keysym_prefix_pattern = re.compile(r"\b(?P<prefix>\w*)XK_(?!KOREAN\b)")
34 def make_keysym_name(m: re.Match[str]) -> str:
35 return m.group("prefix") + m.group("name")
38 def make_keysym_entry(m: re.Match[str]) -> str:
40 Perform the substitutions
43 if m.group("define").startswith("#"):
44 # Replace the xorgproto _EVDEVK macro with the actual value:
45 # 0x10081000 is the base, the evdev hex code is added to that.
46 # We replace to make parsing of the keys later easier.
47 value = 0x10081000 + int(m.group("value"), 16)
48 value_str = f"{value:#x} "
50 value_str = f"""_EVDEVK({m.group('value')})"""
52 value_str = m.group("value")
53 define = m.group("define")
54 prefix = m.group("prefix") or ""
55 name = m.group("name")
56 spacing = m.group("spacing")
57 return f"""{define} XKB_KEY_{prefix}{name}{spacing}{value_str}"""
60 prefix = Path(os.environ.get("X11_HEADERS_PREFIX", "/usr"))
62 prefix / "include/X11/keysymdef.h",
63 prefix / "include/X11/XF86keysym.h",
64 prefix / "include/X11/Sunkeysym.h",
65 prefix / "include/X11/DECkeysym.h",
66 prefix / "include/X11/HPkeysym.h",
70 """#ifndef _XKBCOMMON_KEYSYMS_H
71 #define _XKBCOMMON_KEYSYMS_H
73 /* This file is autogenerated; please do not commit directly. */
77 * Key symbols (keysyms) definitions.
80 #define XKB_KEY_NoSymbol 0x000000 /* Special KeySym */
84 keysyms: set[str] = set()
86 pending_guarded_keysym: str | None = None
87 with path.open("rt", encoding="utf-8") as header:
89 # Duplicate keysym name guard
90 if m := keysym_ifndef_pattern.match(line):
91 if pending_guarded_keysym:
92 raise ValueError(f"Nested #ifndef {pending_guarded_keysym}")
93 pending_guarded_keysym = make_keysym_name(m)
96 # Ignore C macro #ifdef/#ifndef
97 elif line.startswith("#ifdef") or line.startswith("#ifndef"):
98 if pending_guarded_keysym:
99 raise ValueError(f"Nested C macro {pending_guarded_keysym}")
102 # Ignore C macro #endif and check end of keysym name guard
103 elif line.startswith("#endif"):
104 if pending_guarded_keysym:
105 pending_guarded_keysym = None
108 # Remove #define _OSF_Keysyms and such.
109 elif line.startswith("#define _"):
112 # Keysym entry: proceed various tests
113 if line.startswith("#") and (m := keysym_entry_pattern.match(line)):
114 name = make_keysym_name(m)
115 # Check expected guarded keysym, if relevant
116 if pending_guarded_keysym and name != pending_guarded_keysym:
117 raise ValueError(f"{path}: Malformed keysym name guard: {line}")
118 # Check if name already defined
119 elif name in keysyms:
120 if pending_guarded_keysym:
121 # Ignore guarded keysym
124 raise ValueError(f"{path}: Unguarded redefinition: {line}")
128 # Perform _EVDEV and XK_ substitutions
129 line = keysym_entry_pattern.sub(make_keysym_entry, line)
130 line = xorgproto_keysym_prefix_pattern.sub(r"XKB_KEY_\1", line)