diff --git a/kitty/boss.py b/kitty/boss.py index 63b215959..a5a65ee89 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -282,7 +282,7 @@ class Boss(Thread): if window.screen.auto_repeat_enabled or action == GLFW_PRESS: if window.char_grid.scrolled_by and key not in MODIFIER_KEYS: window.scroll_end() - data = interpret_key_event(key, scancode, mods) + data = interpret_key_event(key, scancode, mods, window) if data: window.write_to_child(data) diff --git a/kitty/data-types.h b/kitty/data-types.h index d04d3d615..aac1f4032 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -244,7 +244,7 @@ PyTypeObject ChangeTracker_Type; typedef struct { - bool mLNM, mIRM, mDECTCEM, mDECSCNM, mDECOM, mDECAWM, mDECCOLM, mDECARM, + bool mLNM, mIRM, mDECTCEM, mDECSCNM, mDECOM, mDECAWM, mDECCOLM, mDECARM, mDECCKM, mBRACKETED_PASTE, mFOCUS_TRACKING; unsigned long mouse_tracking_mode, mouse_tracking_protocol; } ScreenModes; diff --git a/kitty/keys.py b/kitty/keys.py index 4ebb7f9bf..fcf055f45 100644 --- a/kitty/keys.py +++ b/kitty/keys.py @@ -5,7 +5,7 @@ import kitty.fast_data_types as defines from .terminfo import key_as_bytes -key_map = { +smkx_key_map = { defines.GLFW_KEY_UP: 'kcuu1', defines.GLFW_KEY_DOWN: 'kcud1', defines.GLFW_KEY_LEFT: 'kcub1', @@ -17,16 +17,16 @@ key_map = { defines.GLFW_KEY_PAGE_UP: 'kpp', defines.GLFW_KEY_PAGE_DOWN: 'knp', } -key_map = {k: key_as_bytes(v) for k, v in key_map.items()} +smkx_key_map = {k: key_as_bytes(v) for k, v in smkx_key_map.items()} for f in range(1, 13): - key_map[getattr(defines, 'GLFW_KEY_F{}'.format(f))] = key_as_bytes('kf{}'.format(f)) + smkx_key_map[getattr(defines, 'GLFW_KEY_F{}'.format(f))] = key_as_bytes('kf{}'.format(f)) del f -key_map[defines.GLFW_KEY_ESCAPE] = b'\033' -key_map[defines.GLFW_KEY_ENTER] = b'\r' -key_map[defines.GLFW_KEY_KP_ENTER] = b'\r' -key_map[defines.GLFW_KEY_BACKSPACE] = key_as_bytes('kbs') -key_map[defines.GLFW_KEY_TAB] = b'\t' +smkx_key_map[defines.GLFW_KEY_ESCAPE] = b'\033' +smkx_key_map[defines.GLFW_KEY_ENTER] = b'\r' +smkx_key_map[defines.GLFW_KEY_KP_ENTER] = b'\r' +smkx_key_map[defines.GLFW_KEY_BACKSPACE] = key_as_bytes('kbs') +smkx_key_map[defines.GLFW_KEY_TAB] = b'\t' SHIFTED_KEYS = { defines.GLFW_KEY_TAB: key_as_bytes('kcbt'), @@ -49,6 +49,22 @@ control_codes[defines.GLFW_KEY_DELETE] = bytearray(key_as_bytes('kdch1').replace alt_codes = {k: (0x1b, k) for i, k in enumerate(range(defines.GLFW_KEY_SPACE, defines.GLFW_KEY_RIGHT_BRACKET + 1))} +rmkx_key_map = smkx_key_map.copy() +rmkx_key_map.update({ + defines.GLFW_KEY_UP: b'\033[A', + defines.GLFW_KEY_DOWN: b'\033[B', + defines.GLFW_KEY_LEFT: b'\033[D', + defines.GLFW_KEY_RIGHT: b'\033[C', + defines.GLFW_KEY_HOME: b'\033[H', + defines.GLFW_KEY_END: b'\033[F', +}) +cursor_key_mode_map = {True: smkx_key_map, False: rmkx_key_map} + + +def get_key_map(screen): + return cursor_key_mode_map[screen.cursor_key_mode] + + valid_localized_key_names = { k: getattr(defines, 'GLFW_KEY_' + k) for k in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' } @@ -64,7 +80,7 @@ def get_localized_key(key, scancode): return valid_localized_key_names.get((name or '').upper(), key) -def interpret_key_event(key, scancode, mods): +def interpret_key_event(key, scancode, mods, window): data = bytearray() key = get_localized_key(key, scancode) if mods == defines.GLFW_MOD_CONTROL and key in control_codes: @@ -74,6 +90,7 @@ def interpret_key_event(key, scancode, mods): # Map Alt+key to Esc-key data.extend(alt_codes[key]) else: + key_map = get_key_map(window.screen) x = key_map.get(key) if x is not None: if mods == defines.GLFW_MOD_SHIFT: diff --git a/kitty/screen.c b/kitty/screen.c index 742526768..30399f324 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -12,7 +12,7 @@ #include "modes.h" #include "wcwidth9.h" -static const ScreenModes empty_modes = {0, .mDECAWM=true, .mDECTCEM=true, .mDECARM=true}; +static const ScreenModes empty_modes = {0, .mDECAWM=true, .mDECTCEM=true, .mDECARM=true, .mDECCKM=true}; // Constructor/destructor {{{ @@ -404,10 +404,12 @@ set_mode_from_const(Screen *self, unsigned int mode, bool val) { MOUSE_MODE(MOUSE_SGR_MODE, mouse_tracking_protocol, SGR_PROTOCOL) MOUSE_MODE(MOUSE_URXVT_MODE, mouse_tracking_protocol, URXVT_PROTOCOL) - case DECCKM: case DECSCLM: case DECNRCM: break; // we ignore these modes + case DECCKM: + self->modes.mDECCKM = val; + break; case DECTCEM: self->modes.mDECTCEM = val; tracker_cursor_changed(self->change_tracker); @@ -1047,6 +1049,7 @@ MODE_GETSET(in_bracketed_paste_mode, BRACKETED_PASTE) MODE_GETSET(focus_tracking_enabled, FOCUS_TRACKING) MODE_GETSET(auto_repeat_enabled, DECARM) MODE_GETSET(cursor_visible, DECTCEM) +MODE_GETSET(cursor_key_mode, DECCKM) static PyObject* mouse_tracking_mode(Screen *self) { @@ -1250,6 +1253,7 @@ static PyGetSetDef getsetters[] = { GETSET(auto_repeat_enabled) GETSET(focus_tracking_enabled) GETSET(cursor_visible) + GETSET(cursor_key_mode) {NULL} /* Sentinel */ }; diff --git a/kitty/terminfo.py b/kitty/terminfo.py index 2ba0da86f..d3a6c7d0e 100644 --- a/kitty/terminfo.py +++ b/kitty/terminfo.py @@ -92,15 +92,15 @@ string_capabilities = { # Make cursor appear normal 'cnorm': r'\E[?12l\E[?25h', # Carriage return - 'cr': r'^M', + 'cr': r'^M', # CR (carriage return \r) # Change scroll region 'csr': r'\E[%i%p1%d;%p2%dr', # Move cursor to the left by the specified amount 'cub': r'\E[%p1%dD', - 'cub1': r'^H', + 'cub1': r'^H', # BS (backspace) # Move cursor down specified number of lines 'cud': r'\E[%p1%dB', - 'cud1': r'^J', + 'cud1': r'^J', # LF (line-feed \n) # Move cursor to the right by the specified amount 'cuf': r'\E[%p1%dC', 'cuf1': r'\E[C', @@ -203,6 +203,8 @@ string_capabilities = { 'rmcup': r'\E[?1049l', # Exit insert mode 'rmir': r'\E[4l', + # Exit application keypad mode + 'rmkx': r'\E[?1l', # Exit standout mode 'rmso': r'\E[27m', # Exit underline mode @@ -227,6 +229,8 @@ string_capabilities = { 'smcup': r'\E[?1049h', # Enster insert mode 'smir': r'\E[4h', + # Enter application keymap mode + 'smkx': r'\E[?1h', # Enter standout mode 'smso': r'\E[7m', # Enter underline mode @@ -373,6 +377,8 @@ termcap_aliases.update({ 'ZR': 'ritm', 'as': 'smacs', 'ae': 'rmacs', + 'ks': 'smkx', + 'ke': 'rmkx', '#2': 'kHOM', '#4': 'kLFT', '*7': 'kEND', diff --git a/kitty/window.py b/kitty/window.py index e04be198e..170798274 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -17,7 +17,7 @@ from .fast_data_types import ( GLFW_MOUSE_BUTTON_5, ANY_MODE, MOTION_MODE, GLFW_KEY_LEFT_SHIFT, GLFW_KEY_RIGHT_SHIFT, GLFW_KEY_UP, GLFW_KEY_DOWN, GLFW_MOUSE_BUTTON_4 ) -from .keys import key_map +from .keys import get_key_map from .mouse import encode_mouse_event, PRESS, RELEASE, MOVE, DRAG from .terminfo import get_capabilities from .utils import sanitize_title, get_primary_selection, parse_color_set, safe_print @@ -254,7 +254,7 @@ class Window: if ev: self.write_to_child(ev) else: - k = key_map[GLFW_KEY_UP if upwards else GLFW_KEY_DOWN] + k = get_key_map(self.screen)[GLFW_KEY_UP if upwards else GLFW_KEY_DOWN] self.write_to_child(k * abs(s)) def buf_toggled(self, is_main_linebuf): diff --git a/terminfo/78/xterm-kitty b/terminfo/78/xterm-kitty index 4ca761612..615403479 100644 Binary files a/terminfo/78/xterm-kitty and b/terminfo/78/xterm-kitty differ diff --git a/terminfo/kitty.terminfo b/terminfo/kitty.terminfo index 401d3c03e..fe86e0ed5 100644 --- a/terminfo/kitty.terminfo +++ b/terminfo/kitty.terminfo @@ -101,6 +101,7 @@ xterm-kitty|KovIdTTY, rmam=\E[?7l, rmcup=\E[?1049l, rmir=\E[4l, + rmkx=\E[?1l, rmso=\E[27m, rmul=\E[24m, rs1=\Ec, @@ -114,6 +115,7 @@ xterm-kitty|KovIdTTY, smam=\E[?7h, smcup=\E[?1049h, smir=\E[4h, + smkx=\E[?1h, smso=\E[7m, smul=\E[4m, tbc=\E[3g, diff --git a/terminfo/x/xterm-kitty b/terminfo/x/xterm-kitty index 4ca761612..615403479 100644 Binary files a/terminfo/x/xterm-kitty and b/terminfo/x/xterm-kitty differ