diff --git a/interfaces/tui/keycodes.py b/interfaces/tui/keycodes.py index 5793661..631ea87 100644 --- a/interfaces/tui/keycodes.py +++ b/interfaces/tui/keycodes.py @@ -94,6 +94,12 @@ _CSI_NAV = { "5~": KEY_PPAGE, "6~": KEY_NPAGE, } +# F1-F4 bentuk huruf (kitty protocol aktif): CSI P/Q/S = F1/F2/F4. +# F3 (huruf R) dihapus dari spec (bentrok Cursor Position Report) → pakai [13~. +_CSI_LETTER_F = { + "P": KEY_F1, "Q": KEY_F2, "S": KEY_F4, +} + def _csi_mod(mod_str: str) -> int: # Modifier CSI-u: 1=default, 2=Shift, 3=Alt, 4=Shift+Alt, 5=Ctrl, @@ -139,6 +145,11 @@ def _parse_csi(data: bytes) -> int: m2 = re.match(r"^\[(?:\d+;)?(\d*)([ABCDHF])$", text) if m2 and m2.group(2) in _CSI_NAV: return _CSI_NAV[m2.group(2)] + # F1/F2/F4 bentuk huruf (kitty protocol aktif): \x1b[P / \x1b[Q / \x1b[S. + # Modifier boleh ada (misal [1;2Q = Shift+F2); kode huruf tetap jadi patokan. + mF = re.match(r"^\[(?:\d+;)*(\d*)([PQRS])$", text) + if mF and mF.group(2) in _CSI_LETTER_F: + return _CSI_LETTER_F[mF.group(2)] return KEY_ESC code = int(m27.group(2)) mod = _csi_mod(m27.group(1)) @@ -214,6 +225,23 @@ def read_key(stdscr, timeout_ms: int = -1) -> int: break return _parse_csi(bytes(seq)) + if nxt == ord("O"): + # SS3 (application keypad): F1-F4 = \x1bOP..\x1bOS, + # panah = \x1bOA..\x1bOD, Home/End = \x1bOH/\x1bOF. + stdscr.timeout(ESC_PEEK_MS) + try: + c = stdscr.getch() + finally: + stdscr.timeout(timeout_ms) + ss3 = { + "P": KEY_F1, "Q": KEY_F2, "R": KEY_F3, "S": KEY_F4, + "A": KEY_UP, "B": KEY_DOWN, "C": KEY_RIGHT, "D": KEY_LEFT, + "H": KEY_HOME, "F": KEY_END, + } + if c != -1 and chr(c) in ss3: + return ss3[chr(c)] + return KEY_ALT("O") # Alt+Shift+O (bukan SS3) + if 32 <= nxt <= 126: return KEY_ALT(chr(nxt)) # Alt+ = "\x1b "