Re: [PATCH 1/3] libkeymap: add support for KT_CSI keysym type

Alexey Gladkov <[email protected]> Mon, 22 Jun 2026 10:45:16 +0200
Newsgroups dev.linux.lists.kbd
Message-ID <[email protected]>
On Thu, Jun 11, 2026 at 09:48:55PM -0400, Nicolas Pitre wrote:
> Add support for the new KT_CSI keysym type which provides modifier-aware
> CSI escape sequences for navigation and function keys. This eliminates
> the need to exhaust the limited func_table string entries for modifier
> combinations.
> 
> The new Csi_* keysyms (Csi_Home, Csi_End, Csi_Delete, Csi_Insert,
> Csi_PgUp, Csi_PgDn, Csi_F1-F20) generate tilde-format CSI sequences
> with automatic modifier encoding when used with a supporting kernel.
> 
> The kernel automatically falls back to the plain keymap entry when
> modifiers are held, encoding the modifier state into the output
> sequence, so only plain map entries need to be defined.
> 
> Also add documentation for modifier-aware keys to keymaps(5), and
> update the libkeymap test fixture for the extended symbol table.
> 
> Note: Requires Linux kernel 7.1 or later for KT_CSI support. On older
> kernels these keysyms load without effect on consoles in Unicode mode
> (the affected keys produce no output), and are rejected with EINVAL on
> non-Unicode consoles (loadkeys reports an error for each such entry
> but carries on).
> 
> Signed-off-by: Nicolas Pitre <[email protected]>
> ---
>  docs/man/man5/keymaps.5        | 77 ++++++++++++++++++++++++++++++++++
>  src/libkeymap/ksyms.c          |  3 +-
>  src/libkeymap/syms.ktyp.h      | 39 +++++++++++++++++
>  tests/data/keymap0-summary.txt | 26 ++++++++++++
>  4 files changed, 144 insertions(+), 1 deletion(-)
> 
> diff --git a/docs/man/man5/keymaps.5 b/docs/man/man5/keymaps.5
> index 072afe3..bfa75aa 100644
> --- a/docs/man/man5/keymaps.5
> +++ b/docs/man/man5/keymaps.5
> @@ -353,6 +353,83 @@ and describe how two bytes are combined to form a third one
>  (when a dead accent or compose key is used).
>  This is used to get accented letters and the like on a standard
>  keyboard.
> +.SH "MODIFIER-AWARE KEYS"
> +Certain key types automatically encode the current modifier state into
> +the escape sequence they produce. This eliminates the need to define
> +separate keymap entries for each modifier combination.
> +.SS "Cursor Keys"
> +The cursor keys (Up, Down, Left, Right) automatically include modifier
> +information when Shift, Alt, or Control are held. With no modifiers,
> +they produce the standard sequences (e.g., ESC [ A for Up). With
> +modifiers, they produce extended sequences in the format ESC [ 1 ; \fImod\fP X,
> +where \fImod\fP encodes the modifier state and X is the direction letter.
> +.LP
> +The modifier value is calculated as: 1 + (Shift?1:0) + (Alt?2:0) + (Control?4:0).
> +AltGr counts as Alt for this purpose.
> +For example, Shift+Up produces ESC [ 1 ; 2 A, and Control+Alt+Up
> +produces ESC [ 1 ; 7 A.
> +.SS "CSI Keys"
> +The Csi_* keysyms provide similar modifier-aware behavior for navigation
> +and function keys, generating sequences in the CSI tilde format
> +(ESC [ \fIn\fP ~ or ESC [ \fIn\fP ; \fImod\fP ~ with modifiers).
> +.LP
> +Available CSI keysyms and their unmodified sequences:
> +.RS
> +.TP 16
> +.B Csi_Home
> +ESC [ 1 ~
> +.TP
> +.B Csi_Insert
> +ESC [ 2 ~
> +.TP
> +.B Csi_Delete
> +ESC [ 3 ~
> +.TP
> +.B Csi_End
> +ESC [ 4 ~
> +.TP
> +.B Csi_PgUp
> +ESC [ 5 ~
> +.TP
> +.B Csi_PgDn
> +ESC [ 6 ~
> +.TP
> +.B Csi_F1 \fR...\fB Csi_F12
> +ESC [ 11 ~ through ESC [ 24 ~ (skipping 16 and 22)
> +.TP
> +.B Csi_F13 \fR...\fB Csi_F20
> +ESC [ 25 ~ through ESC [ 34 ~ (skipping 27 and 30)
> +.RE
> +.LP
> +Note: The Csi_F* sequences follow the xterm numbering scheme, including
> +its gaps in the parameter numbering, which differs from the traditional
> +Linux console F1-F5 sequences (ESC [ [ A through ESC [ [ E).
> +.SS "Fallback Behavior"
> +When a cursor or CSI key is pressed with modifiers, and no explicit binding
> +exists for that modifier combination, the kernel automatically falls back
> +to the plain (unmodified) keymap entry. The modifier state is still encoded
> +in the output sequence.
> +.LP
> +This means you only need to define the plain keymap entry:
> +.LP
> +.RS
> +.nf
> +keycode 102 = Csi_Home
> +.fi
> +.RE
> +.LP
> +and all modifier combinations (Shift+Home, Control+Home, etc.) will
> +automatically produce the correct modified sequences without additional
> +keymap entries.
> +.LP
> +.B Note:
> +Modifier-aware key behavior requires Linux kernel 7.1 or later.
> +On older kernels, cursor keys produce their traditional unmodified
> +sequences, and Csi_* keysyms have no effect: on a console in Unicode
> +mode the corresponding keys produce no output, while on a non-Unicode
> +console
> +.BR loadkeys (1)
> +reports an error for each Csi_* entry.
>  .SH ABBREVIATIONS
>  Various abbreviations can be used with kbd-0.96 and later.
>  .TP
> diff --git a/src/libkeymap/ksyms.c b/src/libkeymap/ksyms.c
> index 219e5f2..98d1cf3 100644
> --- a/src/libkeymap/ksyms.c
> +++ b/src/libkeymap/ksyms.c
> @@ -52,7 +52,8 @@ static const syms_entry syms[] = {
>  	{ NULL, 0 },    /* KT_LETTER */
>  	E(sticky_syms), /* KT_SLOCK */
>  	{ NULL, 0 },    /* KT_DEAD2 */
> -	E(brl_syms)     /* KT_BRL */
> +	E(brl_syms),    /* KT_BRL */
> +	E(csi_syms)     /* KT_CSI */
>  };

In src/libkeymap/summary.c:81, you forgot to change the value of NR_TYPES.
As a result, the new KT_CSI == 15 will not appear in the output of
`dumpkeys --long-info`.

>  
>  #undef E
> diff --git a/src/libkeymap/syms.ktyp.h b/src/libkeymap/syms.ktyp.h
> index 504d67e..aca0fc6 100644
> --- a/src/libkeymap/syms.ktyp.h
> +++ b/src/libkeymap/syms.ktyp.h
> @@ -588,3 +588,42 @@ static const char *const brl_syms[] = {
>  	"Brl_dot9",
>  	"Brl_dot10"
>  };
> +
> +/*
> + * Keysyms whose KTYP is KT_CSI.
> + * Index is the CSI parameter number for ESC [ <index> ~ sequences.
> + */
> +static const char *const csi_syms[] = {
> +	"",           /* 0: unused */
> +	"Csi_Home",   /* 1: ESC [ 1 ~ */
> +	"Csi_Insert", /* 2: ESC [ 2 ~ */
> +	"Csi_Delete", /* 3: ESC [ 3 ~ */
> +	"Csi_End",    /* 4: ESC [ 4 ~ */
> +	"Csi_PgUp",   /* 5: ESC [ 5 ~ */
> +	"Csi_PgDn",   /* 6: ESC [ 6 ~ */
> +	"", "", "", "",   /* 7-10: unused */
> +	"Csi_F1",     /* 11: ESC [ 11 ~ */
> +	"Csi_F2",     /* 12: ESC [ 12 ~ */
> +	"Csi_F3",     /* 13: ESC [ 13 ~ */
> +	"Csi_F4",     /* 14: ESC [ 14 ~ */
> +	"Csi_F5",     /* 15: ESC [ 15 ~ */
> +	"",           /* 16: unused */
> +	"Csi_F6",     /* 17: ESC [ 17 ~ */
> +	"Csi_F7",     /* 18: ESC [ 18 ~ */
> +	"Csi_F8",     /* 19: ESC [ 19 ~ */
> +	"Csi_F9",     /* 20: ESC [ 20 ~ */
> +	"Csi_F10",    /* 21: ESC [ 21 ~ */
> +	"",           /* 22: unused */
> +	"Csi_F11",    /* 23: ESC [ 23 ~ */
> +	"Csi_F12",    /* 24: ESC [ 24 ~ */
> +	"Csi_F13",    /* 25: ESC [ 25 ~ */
> +	"Csi_F14",    /* 26: ESC [ 26 ~ */
> +	"",           /* 27: unused */
> +	"Csi_F15",    /* 28: ESC [ 28 ~ */
> +	"Csi_F16",    /* 29: ESC [ 29 ~ */
> +	"",           /* 30: unused */
> +	"Csi_F17",    /* 31: ESC [ 31 ~ */
> +	"Csi_F18",    /* 32: ESC [ 32 ~ */
> +	"Csi_F19",    /* 33: ESC [ 33 ~ */
> +	"Csi_F20",    /* 34: ESC [ 34 ~ */
> +};
> diff --git a/tests/data/keymap0-summary.txt b/tests/data/keymap0-summary.txt
> index 0b66c06..6f757fd 100644
> --- a/tests/data/keymap0-summary.txt
> +++ b/tests/data/keymap0-summary.txt
> @@ -810,6 +810,32 @@ nr of compose definitions in actual use: 0
>  0x0e08	Brl_dot8
>  0x0e09	Brl_dot9
>  0x0e0a	Brl_dot10
> +0x0f01	Csi_Home
> +0x0f02	Csi_Insert
> +0x0f03	Csi_Delete
> +0x0f04	Csi_End
> +0x0f05	Csi_PgUp
> +0x0f06	Csi_PgDn
> +0x0f0b	Csi_F1
> +0x0f0c	Csi_F2
> +0x0f0d	Csi_F3
> +0x0f0e	Csi_F4
> +0x0f0f	Csi_F5
> +0x0f11	Csi_F6
> +0x0f12	Csi_F7
> +0x0f13	Csi_F8
> +0x0f14	Csi_F9
> +0x0f15	Csi_F10
> +0x0f17	Csi_F11
> +0x0f18	Csi_F12
> +0x0f19	Csi_F13
> +0x0f1a	Csi_F14
> +0x0f1c	Csi_F15
> +0x0f1d	Csi_F16
> +0x0f1f	Csi_F17
> +0x0f20	Csi_F18
> +0x0f21	Csi_F19
> +0x0f22	Csi_F20
>  
>  The following synonyms are recognized:
>  
> -- 
> 2.54.0
> 

-- 
Rgrds, legion