diff --git a/kitty/child.py b/kitty/child.py index 606f26e0e..e75cebb6a 100644 --- a/kitty/child.py +++ b/kitty/child.py @@ -3,6 +3,7 @@ import os import sys +import termios from collections import defaultdict from collections.abc import Generator, Sequence from contextlib import contextmanager, suppress @@ -326,6 +327,7 @@ class Child: else: stdin_read_fd = stdin_write_fd = -1 self.final_env, must_run_startup_command_via_kitten = self.get_final_env() + self.initial_termios_state = termios.tcgetattr(master) argv = list(self.argv) cwd = self.cwd pass_fds = self.pass_fds @@ -543,7 +545,6 @@ class Child: def send_signal_for_key(self, key_num: bytes) -> bool: import signal - import termios if self.child_fd is None: return False t = termios.tcgetattr(self.child_fd) @@ -561,3 +562,10 @@ class Child: pgrp = os.tcgetpgrp(self.child_fd) os.killpg(pgrp, s) return True + + def reset_termios_state(self) -> None: + if s := getattr(self, 'initial_termios_state', None): + try: + termios.tcsetattr(s, termios.TCSANOW) + except OSError: + pass diff --git a/kitty/screen.c b/kitty/screen.c index 2a6d62bb6..145681c00 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -213,6 +213,7 @@ screen_reset(Screen *self) { set_dynamic_color(self, 110, NULL); set_dynamic_color(self, 111, NULL); set_color_table_color(self, 104, NULL); + CALLBACK("on_reset", NULL) } void diff --git a/kitty/window.py b/kitty/window.py index bf21b87c0..5eeb64982 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -1333,6 +1333,9 @@ class Window: b |= b << 8 self.screen.send_escape_code_to_child(ESC_OSC, f'{code};rgb:{r:04x}/{g:04x}/{b:04x}') + def on_reset(self) -> None: + self.child.reset_termios_state() + def notify_child_of_resize(self) -> None: pty_size = self.last_reported_pty_size if pty_size[0] > -1 and self.screen.in_band_resize_notification: diff --git a/kitty_tests/__init__.py b/kitty_tests/__init__.py index 1541dafa3..1ae16fb86 100644 --- a/kitty_tests/__init__.py +++ b/kitty_tests/__init__.py @@ -60,6 +60,10 @@ class Callbacks: def notify_child_of_resize(self): self.num_of_resize_events += 1 + def on_reset(self) -> None: + if self.pty is not None: + self.pty.reset_termios_state() + def color_control(self, code, data) -> None: from kitty.window import color_control response = color_control(self.color_profile, code, data) @@ -331,6 +335,7 @@ class PTY: from kitty.child import openpty self.master_fd, self.slave_fd = openpty() self.child_pid = 0 + self.initial_termios_state = termios.tcgetattr(self.master_fd) else: self.child_pid, self.master_fd = fork() self.is_child = self.child_pid == CHILD @@ -364,6 +369,10 @@ class PTY: self.screen = Screen(self.callbacks, rows, columns, scrollback, cell_width, cell_height, 0, self.callbacks) self.received_bytes = b'' + def reset_termios_state(self): + if s := getattr(self, 'initial_termios_state', None): + termios.tcsetattr(self.master_fd, s) + def turn_off_echo(self): s = termios.tcgetattr(self.master_fd) s[3] &= ~termios.ECHO