From f3447d187def4aed37452d5942a11034ac1ff3b2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 28 Sep 2021 09:32:53 +0530 Subject: [PATCH] Allow handlers to ask for mouse events --- kittens/tui/handler.py | 3 ++- kittens/tui/loop.py | 9 ++++++--- kittens/tui/operations.py | 21 ++++++++++++++++++--- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/kittens/tui/handler.py b/kittens/tui/handler.py index 20a940692..951443962 100644 --- a/kittens/tui/handler.py +++ b/kittens/tui/handler.py @@ -15,7 +15,7 @@ from kitty.typing import ( KeyEventType, LoopType, MouseEvent, ScreenSize, TermManagerType ) -from .operations import pending_update +from .operations import MouseTracking, pending_update if TYPE_CHECKING: from kitty.file_transmission import FileTransmissionCommand @@ -25,6 +25,7 @@ class Handler: image_manager_class: Optional[Type[ImageManagerType]] = None use_alternate_screen = True + mouse_tracking = MouseTracking.none def _initialize( self, diff --git a/kittens/tui/loop.py b/kittens/tui/loop.py index f2af4f2e1..705e5ef1a 100644 --- a/kittens/tui/loop.py +++ b/kittens/tui/loop.py @@ -28,7 +28,7 @@ from kitty.typing import ImageManagerType, KeyEventType, Protocol from kitty.utils import ScreenSizeGetter, screen_size_function, write_all from .handler import Handler -from .operations import init_state, reset_state +from .operations import init_state, reset_state, MouseTracking class BinaryWrite(Protocol): @@ -69,7 +69,10 @@ ftc_code = str(FILE_TRANSFER_CODE) class TermManager: - def __init__(self, optional_actions: int = termios.TCSANOW, use_alternate_screen: bool = True) -> None: + def __init__( + self, optional_actions: int = termios.TCSANOW, use_alternate_screen: bool = True, + mouse_tracking: MouseTracking = MouseTracking.none + ) -> None: self.extra_finalize: Optional[str] = None self.optional_actions = optional_actions self.use_alternate_screen = use_alternate_screen @@ -421,7 +424,7 @@ class Loop: handler.on_resize(handler.screen_size) signal_manager = SignalManager(self.asycio_loop, _on_sigwinch, handler.on_interrupt, handler.on_term) - with TermManager(self.optional_actions, handler.use_alternate_screen) as term_manager, signal_manager: + with TermManager(self.optional_actions, handler.use_alternate_screen, handler.mouse_tracking) as term_manager, signal_manager: self._get_screen_size: ScreenSizeGetter = screen_size_function(term_manager.tty_fd) image_manager = None if handler.image_manager_class is not None: diff --git a/kittens/tui/operations.py b/kittens/tui/operations.py index 47e65486c..bc131f96d 100644 --- a/kittens/tui/operations.py +++ b/kittens/tui/operations.py @@ -4,8 +4,8 @@ import sys from contextlib import contextmanager +from enum import Enum, auto from functools import wraps -from enum import Enum from typing import ( IO, Any, Callable, Dict, Generator, Optional, Tuple, TypeVar, Union ) @@ -281,7 +281,14 @@ def clear_images_on_screen(delete_data: bool = False) -> str: return gc.serialize().decode('ascii') -def init_state(alternate_screen: bool = True) -> str: +class MouseTracking(Enum): + none = auto() + buttons_only = auto() + buttons_and_drag = auto() + full = auto() + + +def init_state(alternate_screen: bool = True, mouse_tracking: MouseTracking = MouseTracking.none) -> str: sc = SAVE_CURSOR if alternate_screen else '' ans = ( S7C1T + sc + SAVE_PRIVATE_MODE_VALUES + reset_mode(Mode.LNM) + @@ -296,6 +303,14 @@ def init_state(alternate_screen: bool = True) -> str: if alternate_screen: ans += set_mode(Mode.ALTERNATE_SCREEN) + reset_mode(Mode.DECOM) ans += clear_screen() + if mouse_tracking is not MouseTracking.none: + ans += set_mode(Mode.MOUSE_SGR_MODE) + if mouse_tracking is MouseTracking.buttons_only: + ans += set_mode(Mode.MOUSE_BUTTON_TRACKING) + elif mouse_tracking is MouseTracking.buttons_and_drag: + ans += set_mode(Mode.MOUSE_MOTION_TRACKING) + elif mouse_tracking is MouseTracking.full: + ans += set_mode(Mode.MOUSE_MOVE_TRACKING) ans += '\033[>31u' # extended keyboard mode return ans @@ -342,8 +357,8 @@ def alternate_screen(f: Optional[IO[str]] = None) -> Generator[None, None, None] @contextmanager def raw_mode(fd: Optional[int] = None) -> Generator[None, None, None]: - import tty import termios + import tty if fd is None: fd = sys.stdin.fileno() old = termios.tcgetattr(fd)