]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
fix: keyboard CTRL key support for CTRL+C/CTRL+Z in shell
authorTulio A M Mendes <[email protected]>
Tue, 17 Feb 2026 07:45:06 +0000 (04:45 -0300)
committerTulio A M Mendes <[email protected]>
Tue, 17 Feb 2026 07:45:06 +0000 (04:45 -0300)
Root cause: The PS/2 keyboard driver had no CTRL key tracking.
When CTRL was held and a letter pressed, the driver sent the
plain letter character (e.g., 'c') instead of the control
character (e.g., 0x03 for CTRL+C).

Fix: Added ctrl_held state tracking in hal/x86/keyboard.c for
Left CTRL (scancode 0x1D press / 0x9D release). When CTRL is
held and a letter key is pressed, emit (c & 0x1F) — the
standard control character encoding:
  CTRL+C = 0x03, CTRL+Z = 0x1A, CTRL+D = 0x04, etc.

Shell read_line_edit() already handled these bytes correctly:
  - 0x03 (CTRL+C): prints ^C, newline, cancels current line
  - 0x1A (CTRL+Z): ignored at prompt (no foreground job)
  - 0x04 (CTRL+D): EOF on empty line

During command execution, tty_restore() re-enables ISIG, so
the TTY kernel driver intercepts CTRL+C/CTRL+Z and sends
SIGINT/SIGTSTP to the foreground process group via TIOCSPGRP.

src/hal/x86/keyboard.c
user/sh.c

index 11fbe4cefa43959c01618a4f5cb5bd844a664553..e85a14c65f94fc4b44c8e071ebeb1be659ea34c0 100644 (file)
@@ -10,6 +10,7 @@ static hal_keyboard_scan_cb_t g_scan_cb = 0;
 
 /* Modifier state */
 static volatile int shift_held = 0;
+static volatile int ctrl_held = 0;
 
 /* Extended scancode state (0xE0 prefix) */
 static volatile int e0_prefix = 0;
@@ -103,6 +104,8 @@ static void emit_escape_seq(const char* seq) {
 #define SC_RSHIFT_PRESS  0x36
 #define SC_LSHIFT_REL    0xAA
 #define SC_RSHIFT_REL    0xB6
+#define SC_LCTRL_PRESS   0x1D
+#define SC_LCTRL_REL     0x9D
 
 /* Extended (0xE0-prefixed) scancodes */
 #define SC_E0_UP    0x48
@@ -169,7 +172,7 @@ static void kbd_irq(struct registers* regs) {
         return;
     }
 
-    /* Track shift state */
+    /* Track modifier state */
     if (scancode == SC_LSHIFT_PRESS || scancode == SC_RSHIFT_PRESS) {
         shift_held = 1;
         return;
@@ -178,6 +181,14 @@ static void kbd_irq(struct registers* regs) {
         shift_held = 0;
         return;
     }
+    if (scancode == SC_LCTRL_PRESS) {
+        ctrl_held = 1;
+        return;
+    }
+    if (scancode == SC_LCTRL_REL) {
+        ctrl_held = 0;
+        return;
+    }
 
     /* Ignore key releases for normal keys */
     if (scancode & 0x80) return;
@@ -185,7 +196,13 @@ static void kbd_irq(struct registers* regs) {
     if (scancode < 128) {
         char c = shift_held ? scancode_map_shift[scancode] : scancode_map[scancode];
         if (c != 0 && g_cb) {
-            g_cb(c);
+            if (ctrl_held && c >= 'a' && c <= 'z') {
+                g_cb(c - 'a' + 1);  /* Ctrl+A=0x01 .. Ctrl+Z=0x1A */
+            } else if (ctrl_held && c >= 'A' && c <= 'Z') {
+                g_cb(c - 'A' + 1);
+            } else {
+                g_cb(c);
+            }
         }
     }
 }
index 14ff5f4e020180c127fe20c7bd4f99012c903d43..1af3ab32e12960d6757b2694f09af780cfa30b36 100644 (file)
--- a/user/sh.c
+++ b/user/sh.c
@@ -313,6 +313,11 @@ static int read_line_edit(void) {
             return 0;
         }
 
+        /* Ctrl+Z = ignored at prompt (no foreground job to suspend) */
+        if (c == 26) {
+            continue;
+        }
+
         /* Ctrl+A = beginning of line */
         if (c == 1) {
             while (pos > 0) { term_write("\b", 1); pos--; }