From 81931cc0fd4761b42603f7da7d4f50fc282cecc6 Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Fri, 26 Sep 2025 11:12:58 +0200 Subject: [PATCH] keysyms: Add missing evdev keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Keys from Linux ≤ 2.6.11. Most are TODOs made explicit. - Add `XF86XK_MonBrightnessAuto` and make `XF86XK_BrightnessAuto` its deprecated alias, for consistency with `XF86XK_BrightnessMin` - Add `XF86XK_LinkPhone` from Linux 6.14 - Add `XF86XK_PerformanceMode" from Linux 6.17 - Fix and improve the keysym generator script Co-authored-by: Pierre Le Marre Co-authored-by: Kai Uwe Broulik Part-of: --- include/X11/XF86keysym.h | 89 ++++++++++++++++++++++++++++++++++++- scripts/keysym-generator.py | 36 ++++++++------- 2 files changed, 108 insertions(+), 17 deletions(-) diff --git a/include/X11/XF86keysym.h b/include/X11/XF86keysym.h index 0ae9bcd..f637c90 100644 --- a/include/X11/XF86keysym.h +++ b/include/X11/XF86keysym.h @@ -295,10 +295,68 @@ */ #define _EVDEVK(_v) (0x10081000 + _v) /* Use: XF86XK_Eject _EVDEVK(0x0a2) KEY_EJECTCLOSECD */ +/* TODO: Use XF86XK_AudioNext? _EVDEVK(0x0a3) KEY_NEXTSONG */ +/* TODO: XF86XK_MediaPlayPause? _EVDEVK(0x0a4) KEY_PLAYPAUSE */ +/* TODO: Use XF86XK_AudioPrev? _EVDEVK(0x0a5) KEY_PREVIOUSSONG */ +/* TODO: Use XF86XK_AudioStop? _EVDEVK(0x0a6) KEY_STOPCD */ +/* TODO: Use XF86XK_AudioRecord? _EVDEVK(0x0a7) KEY_RECORD */ +/* TODO: Use XF86XK_AudioRewind? _EVDEVK(0x0a8) KEY_REWIND */ +/* Use: XF86XK_Phone _EVDEVK(0x0a9) KEY_PHONE */ +/* TODO: unclear function _EVDEVK(0x0aa) KEY_ISO */ +/* TODO: unclear function _EVDEVK(0x0ab) KEY_CONFIG */ +/* Use: XF86XK_HomePage _EVDEVK(0x0ac) KEY_HOMEPAGE */ +/* Use: XF86XK_Refresh _EVDEVK(0x0ad) KEY_REFRESH */ +/* TODO: unclear function _EVDEVK(0x0ae) KEY_EXIT */ +/* TODO: unclear function _EVDEVK(0x0af) KEY_MOVE */ +/* TODO: unclear function _EVDEVK(0x0b0) KEY_EDIT */ +/* Use: XF86XK_ScrollUp _EVDEVK(0x0b1) KEY_SCROLLUP */ +/* Use: XF86XK_ScrollDown _EVDEVK(0x0b2) KEY_SCROLLDOWN */ +/* NOTE: Unless there are special actions bound to the keys KEY_KPLEFTPAREN and + * KEY_KPRIGHTPAREN, there is no reason to introduce keypad-specific keysyms */ +/* Use: XK_parenleft _EVDEVK(0x0b3) KEY_KPLEFTPAREN */ +/* Use: XK_parenright _EVDEVK(0x0b4) KEY_KPRIGHTPAREN */ /* Use: XF86XK_New _EVDEVK(0x0b5) v2.6.14 KEY_NEW */ /* Use: XK_Redo _EVDEVK(0x0b6) v2.6.14 KEY_REDO */ -/* KEY_DASHBOARD has been mapped to LaunchB in xkeyboard-config since 2011 */ +/* Use: XK_F13 _EVDEVK(0x0b7) KEY_F13 */ +/* Use: XK_F14 _EVDEVK(0x0b8) KEY_F14 */ +/* Use: XK_F15 _EVDEVK(0x0b9) KEY_F15 */ +/* Use: XK_F16 _EVDEVK(0x0ba) KEY_F16 */ +/* Use: XK_F17 _EVDEVK(0x0bb) KEY_F17 */ +/* Use: XK_F18 _EVDEVK(0x0bc) KEY_F18 */ +/* Use: XK_F19 _EVDEVK(0x0bd) KEY_F19 */ +/* Use: XK_F20 _EVDEVK(0x0be) KEY_F20 */ +/* Use: XK_F21 _EVDEVK(0x0bf) KEY_F21 */ +/* Use: XK_F22 _EVDEVK(0x0c0) KEY_F22 */ +/* Use: XK_F23 _EVDEVK(0x0c1) KEY_F23 */ +/* Use: XK_F24 _EVDEVK(0x0c2) KEY_F24 */ +/* TODO: Use XF86XK_AudioPlay? _EVDEVK(0x0c8) KEY_PLAYCD */ +/* TODO: Use XF86XK_AudioPause? _EVDEVK(0x0c9) KEY_PAUSECD */ +/* Use: XF86XK_Launch3 _EVDEVK(0x0ca) KEY_PROG3 */ +/* Use: XF86XK_Launch4 _EVDEVK(0x0cb) KEY_PROG4 */ +/* NOTE: KEY_DASHBOARD has been mapped to LaunchB in xkeyboard-config since 2011 */ /* Use: XF86XK_LaunchB _EVDEVK(0x0cc) v2.6.28 KEY_DASHBOARD */ +/* Use: XF86XK_Suspend _EVDEVK(0x0cd) KEY_SUSPEND */ +/* Use: XF86XK_Close _EVDEVK(0x0ce) KEY_CLOSE */ +/* TODO: Use XF86XK_AudioPlay? _EVDEVK(0x0cf) KEY_PLAY */ +/* TODO: Use XF86XK_AudioForward? _EVDEVK(0x0d0) KEY_FASTFORWARD */ +/* TODO: XF86XK_AudioBassBoost? _EVDEVK(0x0d1) KEY_BASSBOOST */ +/* Use: XK_Print _EVDEVK(0x0d2) KEY_PRINT */ +/* TODO: headphone or vendor key? _EVDEVK(0x0d3) KEY_HP */ +/* Use: XF86XK_WebCam _EVDEVK(0x0d4) KEY_CAMERA */ +/* TODO: unclear function _EVDEVK(0x0d5) KEY_SOUND */ +/* TODO: unclear function _EVDEVK(0x0d6) KEY_QUESTION */ +/* Use: XF86XK_Mail _EVDEVK(0x0d7) KEY_EMAIL */ +/* Use: XF86XK_Messenger _EVDEVK(0x0d8) KEY_CHAT */ +/* Use: XF86XK_Search _EVDEVK(0x0d9) KEY_SEARCH */ +/* TODO: unclear function _EVDEVK(0x0da) KEY_CONNECT */ +/* Use: XF86XK_Finance _EVDEVK(0x0db) KEY_FINANCE */ +#define XF86XK_Sport _EVDEVK(0x0dc) /* KEY_SPORT */ +/* Use: XF86XK_Shop _EVDEVK(0x0dd) KEY_SHOP */ +/* TODO: unclear function _EVDEVK(0x0de) KEY_ALTERASE */ +/* Use: XK_Cancel _EVDEVK(0x0df) KEY_CANCEL */ +/* Use: XF86XK_MonBrightnessDown _EVDEVK(0x0e0) KEY_BRIGHTNESSDOWN */ +/* Use: XF86XK_MonBrightnessUp _EVDEVK(0x0e1) KEY_BRIGHTNESSUP */ +/* Use: XF86XK_AudioMedia _EVDEVK(0x0e2) KEY_MEDIA */ /* Use: XF86XK_Display _EVDEVK(0x0e3) v2.6.12 KEY_SWITCHVIDEOMODE */ /* Use: XF86XK_KbdLightOnOff _EVDEVK(0x0e4) v2.6.12 KEY_KBDILLUMTOGGLE */ /* Use: XF86XK_KbdBrightnessDown _EVDEVK(0x0e5) v2.6.12 KEY_KBDILLUMDOWN */ @@ -312,10 +370,12 @@ /* Use: XF86XK_Bluetooth _EVDEVK(0x0ed) v2.6.19 KEY_BLUETOOTH */ /* Use: XF86XK_WLAN _EVDEVK(0x0ee) v2.6.19 KEY_WLAN */ /* Use: XF86XK_UWB _EVDEVK(0x0ef) v2.6.24 KEY_UWB */ +/* Use: NoSymbol _EVDEVK(0x0f0) KEY_UNKNOWN */ /* Use: XF86XK_Next_VMode _EVDEVK(0x0f1) v2.6.23 KEY_VIDEO_NEXT */ /* Use: XF86XK_Prev_VMode _EVDEVK(0x0f2) v2.6.23 KEY_VIDEO_PREV */ /* Use: XF86XK_MonBrightnessCycle _EVDEVK(0x0f3) v2.6.23 KEY_BRIGHTNESS_CYCLE */ -#define XF86XK_BrightnessAuto _EVDEVK(0x0f4) /* v3.16 KEY_BRIGHTNESS_AUTO */ +#define XF86XK_BrightnessAuto _EVDEVK(0x0f4) /* Deprecated alias for XF86XK_MonBrightnessAuto */ +#define XF86XK_MonBrightnessAuto _EVDEVK(0x0f4) /* v3.16 KEY_BRIGHTNESS_AUTO */ #define XF86XK_DisplayOff _EVDEVK(0x0f5) /* v2.6.23 KEY_DISPLAY_OFF */ /* Use: XF86XK_WWAN _EVDEVK(0x0f6) v3.13 KEY_WWAN */ /* Use: XF86XK_RFKill _EVDEVK(0x0f7) v2.6.33 KEY_RFKILL */ @@ -415,8 +475,32 @@ #define XF86XK_NotificationCenter _EVDEVK(0x1bc) /* v5.10 KEY_NOTIFICATION_CENTER */ #define XF86XK_PickupPhone _EVDEVK(0x1bd) /* v5.10 KEY_PICKUP_PHONE */ #define XF86XK_HangupPhone _EVDEVK(0x1be) /* v5.10 KEY_HANGUP_PHONE */ +#define XF86XK_LinkPhone _EVDEVK(0x1bf) /* v6.14 KEY_LINK_PHONE */ +/* TODO: XF86XK_DeleteToEndOfLine? _EVDEVK(0x1c0) KEY_DEL_EOL */ +/* TODO: XF86XK_DeleteToEndOfScreen? _EVDEVK(0x1c1) KEY_DEL_EOS */ +/* TODO: XF86XK_InsertLine? _EVDEVK(0x1c2) KEY_INS_LINE */ +/* TODO: XF86XK_DeleteLine? _EVDEVK(0x1c3) KEY_DEL_LINE */ #define XF86XK_Fn _EVDEVK(0x1d0) /* KEY_FN */ #define XF86XK_Fn_Esc _EVDEVK(0x1d1) /* KEY_FN_ESC */ +#define XF86XK_Fn_F1 _EVDEVK(0x1d2) /* KEY_FN_F1 */ +#define XF86XK_Fn_F2 _EVDEVK(0x1d3) /* KEY_FN_F2 */ +#define XF86XK_Fn_F3 _EVDEVK(0x1d4) /* KEY_FN_F3 */ +#define XF86XK_Fn_F4 _EVDEVK(0x1d5) /* KEY_FN_F4 */ +#define XF86XK_Fn_F5 _EVDEVK(0x1d6) /* KEY_FN_F5 */ +#define XF86XK_Fn_F6 _EVDEVK(0x1d7) /* KEY_FN_F6 */ +#define XF86XK_Fn_F7 _EVDEVK(0x1d8) /* KEY_FN_F7 */ +#define XF86XK_Fn_F8 _EVDEVK(0x1d9) /* KEY_FN_F8 */ +#define XF86XK_Fn_F9 _EVDEVK(0x1da) /* KEY_FN_F9 */ +#define XF86XK_Fn_F10 _EVDEVK(0x1db) /* KEY_FN_F10 */ +#define XF86XK_Fn_F11 _EVDEVK(0x1dc) /* KEY_FN_F11 */ +#define XF86XK_Fn_F12 _EVDEVK(0x1dd) /* KEY_FN_F12 */ +#define XF86XK_Fn_1 _EVDEVK(0x1de) /* KEY_FN_1 */ +#define XF86XK_Fn_2 _EVDEVK(0x1df) /* KEY_FN_2 */ +#define XF86XK_Fn_D _EVDEVK(0x1e0) /* KEY_FN_D */ +#define XF86XK_Fn_E _EVDEVK(0x1e1) /* KEY_FN_E */ +#define XF86XK_Fn_F _EVDEVK(0x1e2) /* KEY_FN_F */ +#define XF86XK_Fn_S _EVDEVK(0x1e3) /* KEY_FN_S */ +#define XF86XK_Fn_B _EVDEVK(0x1e4) /* KEY_FN_B */ #define XF86XK_FnRightShift _EVDEVK(0x1e5) /* v5.10 KEY_FN_RIGHT_SHIFT */ /* Use: XK_braille_dot_1 _EVDEVK(0x1f1) v2.6.17 KEY_BRL_DOT1 */ /* Use: XK_braille_dot_2 _EVDEVK(0x1f2) v2.6.17 KEY_BRL_DOT2 */ @@ -563,4 +647,5 @@ #define XF86XK_KbdLcdMenu3 _EVDEVK(0x2ba) /* v5.5 KEY_KBD_LCD_MENU3 */ #define XF86XK_KbdLcdMenu4 _EVDEVK(0x2bb) /* v5.5 KEY_KBD_LCD_MENU4 */ #define XF86XK_KbdLcdMenu5 _EVDEVK(0x2bc) /* v5.5 KEY_KBD_LCD_MENU5 */ +#define XF86XK_PerformanceMode _EVDEVK(0x2bd) /* v6.17 KEY_PERFORMANCE */ #undef _EVDEVK diff --git a/scripts/keysym-generator.py b/scripts/keysym-generator.py index cd1a439..6cad082 100755 --- a/scripts/keysym-generator.py +++ b/scripts/keysym-generator.py @@ -42,12 +42,12 @@ def die(msg): sys.exit(1) -def all_keysyms(directory): +def all_keysyms(directory) -> set[str]: """ Extract the key names for all keysyms we have in our repo and return them as list. """ - keysym_names = [] + keysym_names: set[str] = set() pattern = re.compile( r"^#define\s+(?P\w+)\s+(0x[0-9A-Fa-f]+|_EVDEVK\(0x([0-9A-Fa-f]{3}))" ) @@ -56,7 +56,7 @@ def all_keysyms(directory): for line in fd: match = re.match(pattern, line) if match: - keysym_names.append(match.group("name")) + keysym_names.add(match.group("name")) return keysym_names @@ -193,11 +193,12 @@ def verify(ns): expected_pattern = re.compile( r"#define XF86XK_\w+ +_EVDEVK\(0x([0-9A-Fa-f]{3})\) +" r"/\* (?:(?Pv[2-6]\.[0-9]+(\.[0-9]+)?)? +KEY_\w+|" - r"(?PAlias for XF86XK_\w+)) \*/" + r"(?P(?:Deprecated a|A)lias for XF86XK_\w+)) \*/" ) # This is the comment pattern we expect expected_comment_pattern = re.compile( - r"/\* Use: (?P\w+) +_EVDEVK\(0x(?P[0-9A-Fa-f]{3})\) + " + r"/\* (?:Use: (?P\w+)|NOTE.+|TODO.*) +" + r"_EVDEVK\(0x(?P[0-9A-Fa-f]{3})\) + " r"(v[2-6]\.[0-9]+(\.[0-9]+)?)? +KEY_\w+ \*/" ) @@ -206,9 +207,10 @@ def verify(ns): name_pattern = re.compile(r"#define (XF86XK_[^\s]*)") space_check = re.compile(r"#define \w+(\s+)[^\s]+(\s+)") hex_pattern = re.compile(r".*0x([a-f0-9]+).*", re.I) - todo_pattern = re.compile(r"^/\* TODO.*\*/$") + todo_pattern = re.compile(r"^/\* (TODO|NOTE).*\*/$") comment_format = re.compile( - r".*/\* (?:(?:Deprecated a|A)lias for (\w+)|([^\s]+)?\s+(\w+))" + r".*/\* (?:(?:Deprecated a|A)lias for (?P\w+)|" + r"(?P[^\s]+)?\s+(?P\w+))" ) kver_format = re.compile(r"v[2-6]\.[0-9]+(\.[0-9]+)?") alias_format = re.compile(r"(?:Deprecated a|A)lias for XF86XK_\w+") @@ -220,6 +222,8 @@ def verify(ns): all_defines = [] all_keysym_names = all_keysyms(ns.header.parent) + # NoSymbol is define in another header + all_keysym_names.add("NoSymbol") class ParserError(Exception): pass @@ -228,6 +232,7 @@ def verify(ns): raise ParserError(f"{msg} in '{line.strip()}'") last_keycode = 0 + last_alias = False for line in open(ns.header): try: if not in_evdev_codes_section: @@ -263,9 +268,9 @@ def verify(ns): error("Duplicate keycode", line) last_keycode = keycode - name = match.group("name") - if name not in all_keysym_names: - error(f"Unknown keysym {name}", line) + if name := match.group("name"): + if name not in all_keysym_names: + error(f"Unknown keysym {name}", line) elif re.match(hex_pattern, line) and not todo_pattern.match(line): logger.warning(f"Unexpected hex code in {line}") continue @@ -298,7 +303,7 @@ def verify(ns): comment = re.match(comment_format, line) if not comment: error("Invalid comment format", line) - if alias_target := comment.group(1): + if alias_target := comment.group("alias"): alias = True else: alias = False @@ -322,7 +327,7 @@ def verify(ns): keycode = int(match.group(1), 16) if keycode < last_keycode: error("Keycode must be ascending", line) - if keycode == last_keycode and not alias: + if keycode == last_keycode and not (alias or last_keycode): error("Duplicate keycode", line) # May cause a false positive for old libevdev if KEY_MAX is bumped @@ -330,6 +335,7 @@ def verify(ns): error("Keycode outside range", line) last_keycode = keycode + last_alias = alias except ParserError as e: logger.error(e) success = False @@ -359,13 +365,13 @@ def add_keysyms(ns): # 3-digit hexcode in brackets and use that as keycode. pattern = re.compile(r".*_EVDEVK\((0x[0-9A-Fa-f]{3})\).*") max_code = max( - [ + ( c.value for c in libevdev.EV_KEY.codes if c.is_defined and c != libevdev.EV_KEY.KEY_MAX and not c.name.startswith("BTN") - ] + ) ) def defined_keycodes(path): @@ -386,7 +392,7 @@ def add_keysyms(ns): else: if re.match(r"#undef _EVDEVK\n", line): in_evdev_codes_section = False - yield max_code + yield max_code + 1 # Upper bound of range() else: match = re.match(pattern, line) if match: