diff --git a/kittens/tui/loop.py b/kittens/tui/loop.py index 45aa29694..f334ce919 100644 --- a/kittens/tui/loop.py +++ b/kittens/tui/loop.py @@ -6,13 +6,16 @@ import codecs import fcntl import io import os +import re import selectors import sys import termios import tty from contextlib import closing, contextmanager +from functools import partial from kitty.fast_data_types import parse_input_from_terminal +from kitty.key_encoding import decode_key_event, enter_key, backspace_key from .operations import init_state, reset_state @@ -71,6 +74,8 @@ class Loop: self.iov_limit = os.sysconf('SC_IOV_MAX') - 1 except Exception: self.iov_limit = 255 + self.parse_input_from_terminal = partial(parse_input_from_terminal, self.on_text, self.on_dcs, self.on_csi, self.on_osc, self.on_pm, self.on_apc) + self.ebs_pat = re.compile('([\177\r])') def _read_ready(self, handler): if not self.read_allowed: @@ -83,9 +88,19 @@ class Loop: data = self.read_buf + data self.read_buf = data self.handler = handler - self.read_buf = parse_input_from_terminal( - handler.on_text, self.on_dcs, self.on_csi, self.on_osc, self.on_pm, self.on_apc, self.read_buf) - del self.handler + try: + self.read_buf = self.parse_input_from_terminal(self.read_buf) + finally: + del self.handler + + def on_text(self, text): + for chunk in self.ebs_pat.split(text): + if chunk == '\r': + self.handler.on_key(enter_key) + elif chunk == '\177': + self.handler.on_key(backspace_key) + else: + self.handler.on_text(chunk) def on_dcs(self, dcs): pass @@ -97,7 +112,13 @@ class Loop: pass def on_apc(self, apc): - pass + if apc.startswith('K'): + try: + k = decode_key_event(apc) + except Exception: + pass + else: + self.handler.on_key(k) def _write_ready(self, handler): if len(handler.write_buf) > self.iov_limit: diff --git a/kitty/key_encoding.py b/kitty/key_encoding.py index 3082fc7ed..60fbc9ba0 100644 --- a/kitty/key_encoding.py +++ b/kitty/key_encoding.py @@ -3,6 +3,7 @@ # License: GPL v3 Copyright: 2017, Kovid Goyal import string +from collections import namedtuple from . import fast_data_types as defines @@ -302,3 +303,26 @@ def update_encoding(): f.seek(0), f.truncate() f.write(nraw) subprocess.check_call(['yapf', '-i', __file__]) + + +PRESS, REPEAT, RELEASE = 'ptr' +SHIFT, ALT, CTRL, SUPER = 1, 2, 4, 8 +KeyEvent = namedtuple('KeyEvent', 'type mods key') +type_map = {'p': PRESS, 't': REPEAT, 'r': RELEASE} +mod_map = {c: i for i, c in enumerate('ABCDEFGHIJKLMNOP')} +key_rmap = {} +g = globals() +for key_name, enc in ENCODING.items(): + key_name = key_name.replace(' ', '_') + g[key_name] = key_name + key_rmap[enc] = key_name +del key_name, enc, g +enter_key = KeyEvent(PRESS, 0, ENCODING['ENTER']) +backspace_key = KeyEvent(PRESS, 0, ENCODING['BACKSPACE']) + + +def decode_key_event(text): + typ = type_map[text[1]] + mods = mod_map[text[2]] + key = key_rmap[text[3:5]] + return KeyEvent(typ, mods, key)