]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
vt: add modifier support to cursor keys
authorNicolas Pitre <npitre@baylibre.com>
Tue, 3 Feb 2026 04:52:46 +0000 (23:52 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 12 Mar 2026 14:07:51 +0000 (15:07 +0100)
Generate xterm-style CSI sequences with modifier parameters for arrow
keys when Shift, Alt, or Ctrl are held. For example, Shift+Up produces
ESC [ 1 ; 2 A instead of plain ESC [ A.

The modifier encoding follows the standard xterm convention:
  mod = 1 + (shift ? 1 : 0) + (alt ? 2 : 0) + (ctrl ? 4 : 0)

When no modifiers are pressed, the original behavior is preserved.

Explicit keymap bindings for modified cursor keys (e.g., "shift keycode
103 = Find") take precedence over this automatic modifier encoding.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
Link: https://patch.msgid.link/20260203045457.1049793-2-nico@fluxnic.net
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/vt/keyboard.c

index 13bc048f45e869843b116dc013f3d2259fdecd24..cb907a3b9d3d9c32443f8f38c3f39f9930ff10ae 100644 (file)
@@ -765,14 +765,39 @@ static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
                pr_err("k_fn called with value=%d\n", value);
 }
 
+/*
+ * Compute xterm-style modifier parameter for CSI sequences.
+ * Returns 1 + (shift ? 1 : 0) + (alt ? 2 : 0) + (ctrl ? 4 : 0)
+ */
+static int csi_modifier_param(void)
+{
+       int mod = 1;
+
+       if (shift_state & (BIT(KG_SHIFT) | BIT(KG_SHIFTL) | BIT(KG_SHIFTR)))
+               mod += 1;
+       if (shift_state & (BIT(KG_ALT) | BIT(KG_ALTGR)))
+               mod += 2;
+       if (shift_state & (BIT(KG_CTRL) | BIT(KG_CTRLL) | BIT(KG_CTRLR)))
+               mod += 4;
+       return mod;
+}
+
 static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
 {
        static const char cur_chars[] = "BDCA";
+       int mod;
 
        if (up_flag)
                return;
 
-       applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
+       mod = csi_modifier_param();
+       if (mod > 1) {
+               char buf[] = { 0x1b, '[', '1', ';', '0' + mod, cur_chars[value], 0x00 };
+
+               puts_queue(vc, buf);
+       } else {
+               applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
+       }
 }
 
 static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)