]> 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 c8d0c8d2324460d6814c12c8a0b9d53b14322ff8..c9d4702a7e7c1dff9bb13d0d754e4aa9e8a33109 100644 (file)
@@ -19,6 +19,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;
@@ -112,6 +113,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
@@ -178,7 +181,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;
@@ -187,6 +190,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;
@@ -194,7 +205,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 f436e808d5627a558ff2886aabdceb072d59da2d..f3d9e69da48b110e90d57378444798054a3c8fc0 100644 (file)
--- a/user/sh.c
+++ b/user/sh.c
@@ -322,6 +322,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--; }