diff --git a/docs/changelog.rst b/docs/changelog.rst index 76a97c1a2..d6bd11c66 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,6 +4,12 @@ Changelog |kitty| is a feature-rich, cross-platform, *fast*, GPU based terminal. To update |kitty|, :doc:`follow the instructions `. +0.20.3 [future] +---------------------- + +- A new ``show_key`` kitten to easily see the bytes generated by the terminal + for key presses in the various keyboard modes (:pull:`3556`) + 0.20.2 [2021-04-28] ---------------------- diff --git a/docs/faq.rst b/docs/faq.rst index bcd9e765a..bb1a60a69 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -229,23 +229,11 @@ For example:: map alt+s send_text all \x13 This maps :kbd:`alt+s` to :kbd:`ctrl+s`. To figure out what bytes to use for -the :sc:`send_text ` you can use the ``showkey`` utility. Run:: +the :sc:`send_text ` you can use the ``show_key`` kitten. Run:: - showkey -a + kitty +kitten show_key -Then press the key you want to emulate. On macOS, this utility is currently not -available. The manual way to figure it out is: - - 1. Look up your key's decimal value in the table at the bottom of `this - page `_ or any - ANSI escape sequence table. There are different modifiers for :kbd:`ctrl`, - :kbd:`alt`, etc. For e.g., for :kbd:`ctrl+s`, find the ``S`` row and look at - the third column value, ``19``. - - 2. Convert the decimal value to hex with ``kitty +runpy "print(hex(19))"``. - This shows the hex value, ``13`` in this case. - - 3. Use ``\x(hexval)`` in your ``send_text`` command in kitty. So in this example, ``\x13`` +Then press the key you want to emulate. How do I open a new window or tab with the same working directory as the current window? -------------------------------------------------------------------------------------------- diff --git a/docs/keyboard-protocol.rst b/docs/keyboard-protocol.rst index 9bd15d4d8..6a09b8995 100644 --- a/docs/keyboard-protocol.rst +++ b/docs/keyboard-protocol.rst @@ -28,7 +28,7 @@ issues in that proposal, listed at the :ref:`bottom of this document You can see this protocol with all enhancements in action by running:: - kitty +kitten key_demo + kitty +kitten show_key -m kitty inside the kitty terminal to report key events. diff --git a/kittens/key_demo/__init__.py b/kittens/show_key/__init__.py similarity index 100% rename from kittens/key_demo/__init__.py rename to kittens/show_key/__init__.py diff --git a/kittens/key_demo/main.py b/kittens/show_key/kitty_mode.py similarity index 92% rename from kittens/key_demo/main.py rename to kittens/show_key/kitty_mode.py index 85f4ac9c8..2df8aef28 100644 --- a/kittens/key_demo/main.py +++ b/kittens/show_key/kitty_mode.py @@ -2,16 +2,13 @@ # vim:fileencoding=utf-8 # License: GPL v3 Copyright: 2018, Kovid Goyal -import sys -from typing import List - from kitty.key_encoding import ( ALT, CAPS_LOCK, CTRL, HYPER, META, NUM_LOCK, PRESS, RELEASE, REPEAT, SHIFT, SUPER, KeyEvent, encode_key_event ) -from ..tui.handler import Handler -from ..tui.loop import Loop +from kittens.tui.handler import Handler +from kittens.tui.loop import Loop class KeysHandler(Handler): @@ -69,12 +66,8 @@ class KeysHandler(Handler): self.quit_loop(0) -def main(args: List[str]) -> None: +def main() -> None: loop = Loop() handler = KeysHandler() loop.loop(handler) raise SystemExit(loop.return_code) - - -if __name__ == '__main__': - main(sys.argv) diff --git a/kittens/show_key/main.py b/kittens/show_key/main.py new file mode 100644 index 000000000..24c32ce7b --- /dev/null +++ b/kittens/show_key/main.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +# License: GPLv3 Copyright: 2021, Kovid Goyal + + +import os +import sys +from typing import List + +from kitty.cli import parse_args +from kitty.cli_stub import ShowKeyCLIOptions +from kittens.tui.operations import raw_mode, styled + +ctrl_keys = '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_' + + +def print_key(raw: bytearray) -> None: + unix = '' + for ch in raw: + if ch < len(ctrl_keys): + unix += '^' + ctrl_keys[ch] + elif ch == 127: + unix += '^?' + else: + unix += chr(ch) + print(unix + '\t\t', end='') + for ch in raw: + x = chr(ch).encode('ascii') + print(styled(repr(x)[2:-1], fg='yellow'), end='') + print(end='\r\n', flush=True) + + +def read_keys() -> None: + fd = sys.stdin.fileno() + while True: + try: + raw = bytearray(os.read(fd, 64)) + except OSError as err: + print(err, file=sys.stderr, flush=True) + break + if not raw: + break + print_key(raw) + if len(raw) == 1 and raw[0] == 4: + break + + +def legacy_main() -> None: + print('Press any keys - Ctrl-D will terminate this program', end='\r\n', flush=True) + print(styled('UNIX', italic=True, fg='green'), styled('send_text', italic=True, fg='green'), sep='\t\t', end='\r\n') + + with raw_mode(): + read_keys() + + +OPTIONS = r''' +--key-mode -m +default=normal +type=choices +choices=normal,application,kitty,unchanged +The keyboard mode to use when showing keys. "normal" mode is with DECCKM reset and "application" mode is with +DECCKM set. "kitty" is the full kitty extended keyboard protocol. +'''.format + + +def main(args: List[str]) -> None: + cli_opts, items = parse_args(args[1:], OPTIONS, '', '', 'kitty +kitten clipboard', result_class=ShowKeyCLIOptions) + if cli_opts.key_mode == 'kitty': + from .kitty_mode import main as kitty_main + return kitty_main() + if cli_opts.key_mode != 'unchanged': + print(end='\x1b[?1' + ('l' if cli_opts.key_mode == 'normal' else 'h'), flush=True) + try: + return legacy_main() + finally: + if cli_opts.key_mode != 'unchanged': + print(end='\x1b[?1l', flush=True) + + +if __name__ == '__main__': + main(sys.argv) diff --git a/kitty/cli_stub.py b/kitty/cli_stub.py index 39951865b..bf27545e8 100644 --- a/kitty/cli_stub.py +++ b/kitty/cli_stub.py @@ -13,7 +13,7 @@ class CLIOptions: LaunchCLIOptions = AskCLIOptions = ClipboardCLIOptions = DiffCLIOptions = CLIOptions HintsCLIOptions = IcatCLIOptions = PanelCLIOptions = ResizeCLIOptions = CLIOptions ErrorCLIOptions = UnicodeCLIOptions = RCOptions = RemoteFileCLIOptions = CLIOptions -QueryTerminalCLIOptions = BroadcastCLIOptions = CLIOptions +QueryTerminalCLIOptions = BroadcastCLIOptions = ShowKeyCLIOptions = CLIOptions def generate_stub() -> None: @@ -42,6 +42,9 @@ def generate_stub() -> None: from kittens.clipboard.main import OPTIONS do(OPTIONS(), 'ClipboardCLIOptions') + from kittens.show_key.main import OPTIONS + do(OPTIONS(), 'ShowKeyCLIOptions') + from kittens.diff.main import OPTIONS do(OPTIONS(), 'DiffCLIOptions')