kittens: Dont discard pending input on startup

Fixes #3012
This commit is contained in:
Kovid Goyal 2020-10-06 16:39:00 +05:30
parent a3bbad0060
commit dab555ea3b
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 13 additions and 9 deletions

View File

@ -10,6 +10,7 @@ import re
import selectors import selectors
import signal import signal
import sys import sys
import termios
from contextlib import contextmanager from contextlib import contextmanager
from functools import partial from functools import partial
from typing import Any, Callable, Dict, Generator, List, NamedTuple, Optional from typing import Any, Callable, Dict, Generator, List, NamedTuple, Optional
@ -61,8 +62,9 @@ debug = Debug()
class TermManager: class TermManager:
def __init__(self) -> None: def __init__(self, optional_actions: int = termios.TCSANOW) -> None:
self.extra_finalize: Optional[str] = None self.extra_finalize: Optional[str] = None
self.optional_actions = optional_actions
def set_state_for_loop(self, set_raw: bool = True) -> None: def set_state_for_loop(self, set_raw: bool = True) -> None:
if set_raw: if set_raw:
@ -82,7 +84,7 @@ class TermManager:
self.set_state_for_loop() self.set_state_for_loop()
def __enter__(self) -> 'TermManager': def __enter__(self) -> 'TermManager':
self.tty_fd, self.original_termios = open_tty() self.tty_fd, self.original_termios = open_tty(False, self.optional_actions)
self.set_state_for_loop(set_raw=False) self.set_state_for_loop(set_raw=False)
return self return self
@ -183,7 +185,8 @@ class Loop:
def __init__( def __init__(
self, self,
sanitize_bracketed_paste: str = '[\x03\x04\x0e\x0f\r\x07\x7f\x8d\x8e\x8f\x90\x9b\x9d\x9e\x9f]' sanitize_bracketed_paste: str = '[\x03\x04\x0e\x0f\r\x07\x7f\x8d\x8e\x8f\x90\x9b\x9d\x9e\x9f]',
optional_actions: int = termios.TCSADRAIN
): ):
if is_macos: if is_macos:
# On macOS PTY devices are not supported by the KqueueSelector and # On macOS PTY devices are not supported by the KqueueSelector and
@ -193,6 +196,7 @@ class Loop:
else: else:
self.asycio_loop = asyncio.get_event_loop() self.asycio_loop = asyncio.get_event_loop()
self.return_code = 0 self.return_code = 0
self.optional_actions = optional_actions
self.read_buf = '' self.read_buf = ''
self.decoder = codecs.getincrementaldecoder('utf-8')('ignore') self.decoder = codecs.getincrementaldecoder('utf-8')('ignore')
try: try:
@ -388,7 +392,7 @@ class Loop:
handler.on_resize(handler.screen_size) handler.on_resize(handler.screen_size)
signal_manager = SignalManager(self.asycio_loop, _on_sigwinch, handler.on_interrupt, handler.on_term) signal_manager = SignalManager(self.asycio_loop, _on_sigwinch, handler.on_interrupt, handler.on_term)
with TermManager() as term_manager, signal_manager: with TermManager(self.optional_actions) as term_manager, signal_manager:
self._get_screen_size: ScreenSizeGetter = screen_size_function(term_manager.tty_fd) self._get_screen_size: ScreenSizeGetter = screen_size_function(term_manager.tty_fd)
image_manager = None image_manager = None
if handler.image_manager_class is not None: if handler.image_manager_class is not None:

View File

@ -105,8 +105,8 @@ put_tty_in_raw_mode(int fd, const struct termios* termios_p, bool read_with_time
static PyObject* static PyObject*
open_tty(PyObject *self UNUSED, PyObject *args) { open_tty(PyObject *self UNUSED, PyObject *args) {
int read_with_timeout = 0; int read_with_timeout = 0, optional_actions = TCSAFLUSH;
if (!PyArg_ParseTuple(args, "|p", &read_with_timeout)) return NULL; if (!PyArg_ParseTuple(args, "|pi", &read_with_timeout, &optional_actions)) return NULL;
int flags = O_RDWR | O_CLOEXEC | O_NOCTTY; int flags = O_RDWR | O_CLOEXEC | O_NOCTTY;
if (!read_with_timeout) flags |= O_NONBLOCK; if (!read_with_timeout) flags |= O_NONBLOCK;
static char ctty[L_ctermid+1]; static char ctty[L_ctermid+1];
@ -115,13 +115,13 @@ open_tty(PyObject *self UNUSED, PyObject *args) {
struct termios *termios_p = calloc(1, sizeof(struct termios)); struct termios *termios_p = calloc(1, sizeof(struct termios));
if (!termios_p) return PyErr_NoMemory(); if (!termios_p) return PyErr_NoMemory();
if (tcgetattr(fd, termios_p) != 0) { free(termios_p); PyErr_SetFromErrno(PyExc_OSError); return NULL; } if (tcgetattr(fd, termios_p) != 0) { free(termios_p); PyErr_SetFromErrno(PyExc_OSError); return NULL; }
if (!put_tty_in_raw_mode(fd, termios_p, read_with_timeout != 0, TCSAFLUSH)) { free(termios_p); return NULL; } if (!put_tty_in_raw_mode(fd, termios_p, read_with_timeout != 0, optional_actions)) { free(termios_p); return NULL; }
return Py_BuildValue("iN", fd, PyLong_FromVoidPtr(termios_p)); return Py_BuildValue("iN", fd, PyLong_FromVoidPtr(termios_p));
} }
#define TTY_ARGS \ #define TTY_ARGS \
PyObject *tp; int fd; int optional_actions = TCSAFLUSH; \ PyObject *tp; int fd; int optional_actions = TCSAFLUSH; \
if (!PyArg_ParseTuple(args, "iO!|", &fd, &PyLong_Type, &tp, &optional_actions)) return NULL; \ if (!PyArg_ParseTuple(args, "iO!|i", &fd, &PyLong_Type, &tp, &optional_actions)) return NULL; \
struct termios *termios_p = PyLong_AsVoidPtr(tp); struct termios *termios_p = PyLong_AsVoidPtr(tp);
static PyObject* static PyObject*

View File

@ -878,7 +878,7 @@ def normal_tty(fd: int, termios_ptr: TermiosPtr, optional_actions: int = termios
pass pass
def open_tty(read_with_timeout: bool = False) -> Tuple[int, TermiosPtr]: def open_tty(read_with_timeout: bool = False, optional_actions: int = termios.TCSAFLUSH) -> Tuple[int, TermiosPtr]:
pass pass