1from __future__ import annotations 
    2 
    3import sys 
    4from typing import TYPE_CHECKING 
    5 
    6from prompt_toolkit.data_structures import Point 
    7from prompt_toolkit.key_binding.key_processor import KeyPress, KeyPressEvent 
    8from prompt_toolkit.keys import Keys 
    9from prompt_toolkit.mouse_events import ( 
    10    MouseButton, 
    11    MouseEvent, 
    12    MouseEventType, 
    13    MouseModifier, 
    14) 
    15 
    16from ..key_bindings import KeyBindings 
    17 
    18if TYPE_CHECKING: 
    19    from prompt_toolkit.key_binding.key_bindings import NotImplementedOrNone 
    20 
    21__all__ = [ 
    22    "load_mouse_bindings", 
    23] 
    24 
    25E = KeyPressEvent 
    26 
    27# fmt: off 
    28SCROLL_UP   = MouseEventType.SCROLL_UP 
    29SCROLL_DOWN = MouseEventType.SCROLL_DOWN 
    30MOUSE_DOWN  = MouseEventType.MOUSE_DOWN 
    31MOUSE_MOVE  = MouseEventType.MOUSE_MOVE 
    32MOUSE_UP    = MouseEventType.MOUSE_UP 
    33 
    34NO_MODIFIER      : frozenset[MouseModifier] = frozenset() 
    35SHIFT            : frozenset[MouseModifier] = frozenset({MouseModifier.SHIFT}) 
    36ALT              : frozenset[MouseModifier] = frozenset({MouseModifier.ALT}) 
    37SHIFT_ALT        : frozenset[MouseModifier] = frozenset({MouseModifier.SHIFT, MouseModifier.ALT}) 
    38CONTROL          : frozenset[MouseModifier] = frozenset({MouseModifier.CONTROL}) 
    39SHIFT_CONTROL    : frozenset[MouseModifier] = frozenset({MouseModifier.SHIFT, MouseModifier.CONTROL}) 
    40ALT_CONTROL      : frozenset[MouseModifier] = frozenset({MouseModifier.ALT, MouseModifier.CONTROL}) 
    41SHIFT_ALT_CONTROL: frozenset[MouseModifier] = frozenset({MouseModifier.SHIFT, MouseModifier.ALT, MouseModifier.CONTROL}) 
    42UNKNOWN_MODIFIER : frozenset[MouseModifier] = frozenset() 
    43 
    44LEFT           = MouseButton.LEFT 
    45MIDDLE         = MouseButton.MIDDLE 
    46RIGHT          = MouseButton.RIGHT 
    47NO_BUTTON      = MouseButton.NONE 
    48UNKNOWN_BUTTON = MouseButton.UNKNOWN 
    49 
    50xterm_sgr_mouse_events = { 
    51    ( 0, "m") : (LEFT, MOUSE_UP, NO_MODIFIER),                # left_up                       0+ + +  =0 
    52    ( 4, "m") : (LEFT, MOUSE_UP, SHIFT),                      # left_up     Shift             0+4+ +  =4 
    53    ( 8, "m") : (LEFT, MOUSE_UP, ALT),                        # left_up           Alt         0+ +8+  =8 
    54    (12, "m") : (LEFT, MOUSE_UP, SHIFT_ALT),                  # left_up     Shift Alt         0+4+8+  =12 
    55    (16, "m") : (LEFT, MOUSE_UP, CONTROL),                    # left_up               Control 0+ + +16=16 
    56    (20, "m") : (LEFT, MOUSE_UP, SHIFT_CONTROL),              # left_up     Shift     Control 0+4+ +16=20 
    57    (24, "m") : (LEFT, MOUSE_UP, ALT_CONTROL),                # left_up           Alt Control 0+ +8+16=24 
    58    (28, "m") : (LEFT, MOUSE_UP, SHIFT_ALT_CONTROL),          # left_up     Shift Alt Control 0+4+8+16=28 
    59 
    60    ( 1, "m") : (MIDDLE, MOUSE_UP, NO_MODIFIER),              # middle_up                     1+ + +  =1 
    61    ( 5, "m") : (MIDDLE, MOUSE_UP, SHIFT),                    # middle_up   Shift             1+4+ +  =5 
    62    ( 9, "m") : (MIDDLE, MOUSE_UP, ALT),                      # middle_up         Alt         1+ +8+  =9 
    63    (13, "m") : (MIDDLE, MOUSE_UP, SHIFT_ALT),                # middle_up   Shift Alt         1+4+8+  =13 
    64    (17, "m") : (MIDDLE, MOUSE_UP, CONTROL),                  # middle_up             Control 1+ + +16=17 
    65    (21, "m") : (MIDDLE, MOUSE_UP, SHIFT_CONTROL),            # middle_up   Shift     Control 1+4+ +16=21 
    66    (25, "m") : (MIDDLE, MOUSE_UP, ALT_CONTROL),              # middle_up         Alt Control 1+ +8+16=25 
    67    (29, "m") : (MIDDLE, MOUSE_UP, SHIFT_ALT_CONTROL),        # middle_up   Shift Alt Control 1+4+8+16=29 
    68 
    69    ( 2, "m") : (RIGHT, MOUSE_UP, NO_MODIFIER),               # right_up                      2+ + +  =2 
    70    ( 6, "m") : (RIGHT, MOUSE_UP, SHIFT),                     # right_up    Shift             2+4+ +  =6 
    71    (10, "m") : (RIGHT, MOUSE_UP, ALT),                       # right_up          Alt         2+ +8+  =10 
    72    (14, "m") : (RIGHT, MOUSE_UP, SHIFT_ALT),                 # right_up    Shift Alt         2+4+8+  =14 
    73    (18, "m") : (RIGHT, MOUSE_UP, CONTROL),                   # right_up              Control 2+ + +16=18 
    74    (22, "m") : (RIGHT, MOUSE_UP, SHIFT_CONTROL),             # right_up    Shift     Control 2+4+ +16=22 
    75    (26, "m") : (RIGHT, MOUSE_UP, ALT_CONTROL),               # right_up          Alt Control 2+ +8+16=26 
    76    (30, "m") : (RIGHT, MOUSE_UP, SHIFT_ALT_CONTROL),         # right_up    Shift Alt Control 2+4+8+16=30 
    77 
    78    ( 0, "M") : (LEFT, MOUSE_DOWN, NO_MODIFIER),              # left_down                     0+ + +  =0 
    79    ( 4, "M") : (LEFT, MOUSE_DOWN, SHIFT),                    # left_down   Shift             0+4+ +  =4 
    80    ( 8, "M") : (LEFT, MOUSE_DOWN, ALT),                      # left_down         Alt         0+ +8+  =8 
    81    (12, "M") : (LEFT, MOUSE_DOWN, SHIFT_ALT),                # left_down   Shift Alt         0+4+8+  =12 
    82    (16, "M") : (LEFT, MOUSE_DOWN, CONTROL),                  # left_down             Control 0+ + +16=16 
    83    (20, "M") : (LEFT, MOUSE_DOWN, SHIFT_CONTROL),            # left_down   Shift     Control 0+4+ +16=20 
    84    (24, "M") : (LEFT, MOUSE_DOWN, ALT_CONTROL),              # left_down         Alt Control 0+ +8+16=24 
    85    (28, "M") : (LEFT, MOUSE_DOWN, SHIFT_ALT_CONTROL),        # left_down   Shift Alt Control 0+4+8+16=28 
    86 
    87    ( 1, "M") : (MIDDLE, MOUSE_DOWN, NO_MODIFIER),            # middle_down                   1+ + +  =1 
    88    ( 5, "M") : (MIDDLE, MOUSE_DOWN, SHIFT),                  # middle_down Shift             1+4+ +  =5 
    89    ( 9, "M") : (MIDDLE, MOUSE_DOWN, ALT),                    # middle_down       Alt         1+ +8+  =9 
    90    (13, "M") : (MIDDLE, MOUSE_DOWN, SHIFT_ALT),              # middle_down Shift Alt         1+4+8+  =13 
    91    (17, "M") : (MIDDLE, MOUSE_DOWN, CONTROL),                # middle_down           Control 1+ + +16=17 
    92    (21, "M") : (MIDDLE, MOUSE_DOWN, SHIFT_CONTROL),          # middle_down Shift     Control 1+4+ +16=21 
    93    (25, "M") : (MIDDLE, MOUSE_DOWN, ALT_CONTROL),            # middle_down       Alt Control 1+ +8+16=25 
    94    (29, "M") : (MIDDLE, MOUSE_DOWN, SHIFT_ALT_CONTROL),      # middle_down Shift Alt Control 1+4+8+16=29 
    95 
    96    ( 2, "M") : (RIGHT, MOUSE_DOWN, NO_MODIFIER),             # right_down                    2+ + +  =2 
    97    ( 6, "M") : (RIGHT, MOUSE_DOWN, SHIFT),                   # right_down  Shift             2+4+ +  =6 
    98    (10, "M") : (RIGHT, MOUSE_DOWN, ALT),                     # right_down        Alt         2+ +8+  =10 
    99    (14, "M") : (RIGHT, MOUSE_DOWN, SHIFT_ALT),               # right_down  Shift Alt         2+4+8+  =14 
    100    (18, "M") : (RIGHT, MOUSE_DOWN, CONTROL),                 # right_down            Control 2+ + +16=18 
    101    (22, "M") : (RIGHT, MOUSE_DOWN, SHIFT_CONTROL),           # right_down  Shift     Control 2+4+ +16=22 
    102    (26, "M") : (RIGHT, MOUSE_DOWN, ALT_CONTROL),             # right_down        Alt Control 2+ +8+16=26 
    103    (30, "M") : (RIGHT, MOUSE_DOWN, SHIFT_ALT_CONTROL),       # right_down  Shift Alt Control 2+4+8+16=30 
    104 
    105    (32, "M") : (LEFT, MOUSE_MOVE, NO_MODIFIER),              # left_drag                     32+ + +  =32 
    106    (36, "M") : (LEFT, MOUSE_MOVE, SHIFT),                    # left_drag   Shift             32+4+ +  =36 
    107    (40, "M") : (LEFT, MOUSE_MOVE, ALT),                      # left_drag         Alt         32+ +8+  =40 
    108    (44, "M") : (LEFT, MOUSE_MOVE, SHIFT_ALT),                # left_drag   Shift Alt         32+4+8+  =44 
    109    (48, "M") : (LEFT, MOUSE_MOVE, CONTROL),                  # left_drag             Control 32+ + +16=48 
    110    (52, "M") : (LEFT, MOUSE_MOVE, SHIFT_CONTROL),            # left_drag   Shift     Control 32+4+ +16=52 
    111    (56, "M") : (LEFT, MOUSE_MOVE, ALT_CONTROL),              # left_drag         Alt Control 32+ +8+16=56 
    112    (60, "M") : (LEFT, MOUSE_MOVE, SHIFT_ALT_CONTROL),        # left_drag   Shift Alt Control 32+4+8+16=60 
    113 
    114    (33, "M") : (MIDDLE, MOUSE_MOVE, NO_MODIFIER),            # middle_drag                   33+ + +  =33 
    115    (37, "M") : (MIDDLE, MOUSE_MOVE, SHIFT),                  # middle_drag Shift             33+4+ +  =37 
    116    (41, "M") : (MIDDLE, MOUSE_MOVE, ALT),                    # middle_drag       Alt         33+ +8+  =41 
    117    (45, "M") : (MIDDLE, MOUSE_MOVE, SHIFT_ALT),              # middle_drag Shift Alt         33+4+8+  =45 
    118    (49, "M") : (MIDDLE, MOUSE_MOVE, CONTROL),                # middle_drag           Control 33+ + +16=49 
    119    (53, "M") : (MIDDLE, MOUSE_MOVE, SHIFT_CONTROL),          # middle_drag Shift     Control 33+4+ +16=53 
    120    (57, "M") : (MIDDLE, MOUSE_MOVE, ALT_CONTROL),            # middle_drag       Alt Control 33+ +8+16=57 
    121    (61, "M") : (MIDDLE, MOUSE_MOVE, SHIFT_ALT_CONTROL),      # middle_drag Shift Alt Control 33+4+8+16=61 
    122 
    123    (34, "M") : (RIGHT, MOUSE_MOVE, NO_MODIFIER),             # right_drag                    34+ + +  =34 
    124    (38, "M") : (RIGHT, MOUSE_MOVE, SHIFT),                   # right_drag  Shift             34+4+ +  =38 
    125    (42, "M") : (RIGHT, MOUSE_MOVE, ALT),                     # right_drag        Alt         34+ +8+  =42 
    126    (46, "M") : (RIGHT, MOUSE_MOVE, SHIFT_ALT),               # right_drag  Shift Alt         34+4+8+  =46 
    127    (50, "M") : (RIGHT, MOUSE_MOVE, CONTROL),                 # right_drag            Control 34+ + +16=50 
    128    (54, "M") : (RIGHT, MOUSE_MOVE, SHIFT_CONTROL),           # right_drag  Shift     Control 34+4+ +16=54 
    129    (58, "M") : (RIGHT, MOUSE_MOVE, ALT_CONTROL),             # right_drag        Alt Control 34+ +8+16=58 
    130    (62, "M") : (RIGHT, MOUSE_MOVE, SHIFT_ALT_CONTROL),       # right_drag  Shift Alt Control 34+4+8+16=62 
    131 
    132    (35, "M") : (NO_BUTTON, MOUSE_MOVE, NO_MODIFIER),         # none_drag                     35+ + +  =35 
    133    (39, "M") : (NO_BUTTON, MOUSE_MOVE, SHIFT),               # none_drag   Shift             35+4+ +  =39 
    134    (43, "M") : (NO_BUTTON, MOUSE_MOVE, ALT),                 # none_drag         Alt         35+ +8+  =43 
    135    (47, "M") : (NO_BUTTON, MOUSE_MOVE, SHIFT_ALT),           # none_drag   Shift Alt         35+4+8+  =47 
    136    (51, "M") : (NO_BUTTON, MOUSE_MOVE, CONTROL),             # none_drag             Control 35+ + +16=51 
    137    (55, "M") : (NO_BUTTON, MOUSE_MOVE, SHIFT_CONTROL),       # none_drag   Shift     Control 35+4+ +16=55 
    138    (59, "M") : (NO_BUTTON, MOUSE_MOVE, ALT_CONTROL),         # none_drag         Alt Control 35+ +8+16=59 
    139    (63, "M") : (NO_BUTTON, MOUSE_MOVE, SHIFT_ALT_CONTROL),   # none_drag   Shift Alt Control 35+4+8+16=63 
    140 
    141    (64, "M") : (NO_BUTTON, SCROLL_UP, NO_MODIFIER),          # scroll_up                     64+ + +  =64 
    142    (68, "M") : (NO_BUTTON, SCROLL_UP, SHIFT),                # scroll_up   Shift             64+4+ +  =68 
    143    (72, "M") : (NO_BUTTON, SCROLL_UP, ALT),                  # scroll_up         Alt         64+ +8+  =72 
    144    (76, "M") : (NO_BUTTON, SCROLL_UP, SHIFT_ALT),            # scroll_up   Shift Alt         64+4+8+  =76 
    145    (80, "M") : (NO_BUTTON, SCROLL_UP, CONTROL),              # scroll_up             Control 64+ + +16=80 
    146    (84, "M") : (NO_BUTTON, SCROLL_UP, SHIFT_CONTROL),        # scroll_up   Shift     Control 64+4+ +16=84 
    147    (88, "M") : (NO_BUTTON, SCROLL_UP, ALT_CONTROL),          # scroll_up         Alt Control 64+ +8+16=88 
    148    (92, "M") : (NO_BUTTON, SCROLL_UP, SHIFT_ALT_CONTROL),    # scroll_up   Shift Alt Control 64+4+8+16=92 
    149 
    150    (65, "M") : (NO_BUTTON, SCROLL_DOWN, NO_MODIFIER),        # scroll_down                   64+ + +  =65 
    151    (69, "M") : (NO_BUTTON, SCROLL_DOWN, SHIFT),              # scroll_down Shift             64+4+ +  =69 
    152    (73, "M") : (NO_BUTTON, SCROLL_DOWN, ALT),                # scroll_down       Alt         64+ +8+  =73 
    153    (77, "M") : (NO_BUTTON, SCROLL_DOWN, SHIFT_ALT),          # scroll_down Shift Alt         64+4+8+  =77 
    154    (81, "M") : (NO_BUTTON, SCROLL_DOWN, CONTROL),            # scroll_down           Control 64+ + +16=81 
    155    (85, "M") : (NO_BUTTON, SCROLL_DOWN, SHIFT_CONTROL),      # scroll_down Shift     Control 64+4+ +16=85 
    156    (89, "M") : (NO_BUTTON, SCROLL_DOWN, ALT_CONTROL),        # scroll_down       Alt Control 64+ +8+16=89 
    157    (93, "M") : (NO_BUTTON, SCROLL_DOWN, SHIFT_ALT_CONTROL),  # scroll_down Shift Alt Control 64+4+8+16=93 
    158} 
    159 
    160typical_mouse_events = { 
    161    32: (LEFT           , MOUSE_DOWN , UNKNOWN_MODIFIER), 
    162    33: (MIDDLE         , MOUSE_DOWN , UNKNOWN_MODIFIER), 
    163    34: (RIGHT          , MOUSE_DOWN , UNKNOWN_MODIFIER), 
    164    35: (UNKNOWN_BUTTON , MOUSE_UP   , UNKNOWN_MODIFIER), 
    165 
    166    64: (LEFT           , MOUSE_MOVE , UNKNOWN_MODIFIER), 
    167    65: (MIDDLE         , MOUSE_MOVE , UNKNOWN_MODIFIER), 
    168    66: (RIGHT          , MOUSE_MOVE , UNKNOWN_MODIFIER), 
    169    67: (NO_BUTTON      , MOUSE_MOVE , UNKNOWN_MODIFIER), 
    170 
    171    96: (NO_BUTTON      , SCROLL_UP  , UNKNOWN_MODIFIER), 
    172    97: (NO_BUTTON      , SCROLL_DOWN, UNKNOWN_MODIFIER), 
    173} 
    174 
    175urxvt_mouse_events={ 
    176    32: (UNKNOWN_BUTTON, MOUSE_DOWN , UNKNOWN_MODIFIER), 
    177    35: (UNKNOWN_BUTTON, MOUSE_UP   , UNKNOWN_MODIFIER), 
    178    96: (NO_BUTTON     , SCROLL_UP  , UNKNOWN_MODIFIER), 
    179    97: (NO_BUTTON     , SCROLL_DOWN, UNKNOWN_MODIFIER), 
    180} 
    181# fmt:on 
    182 
    183 
    184def load_mouse_bindings() -> KeyBindings: 
    185    """ 
    186    Key bindings, required for mouse support. 
    187    (Mouse events enter through the key binding system.) 
    188    """ 
    189    key_bindings = KeyBindings() 
    190 
    191    @key_bindings.add(Keys.Vt100MouseEvent) 
    192    def _(event: E) -> NotImplementedOrNone: 
    193        """ 
    194        Handling of incoming mouse event. 
    195        """ 
    196        # TypicaL:   "eSC[MaB*" 
    197        # Urxvt:     "Esc[96;14;13M" 
    198        # Xterm SGR: "Esc[<64;85;12M" 
    199 
    200        # Parse incoming packet. 
    201        if event.data[2] == "M": 
    202            # Typical. 
    203            mouse_event, x, y = map(ord, event.data[3:]) 
    204 
    205            # TODO: Is it possible to add modifiers here? 
    206            mouse_button, mouse_event_type, mouse_modifiers = typical_mouse_events[ 
    207                mouse_event 
    208            ] 
    209 
    210            # Handle situations where `PosixStdinReader` used surrogateescapes. 
    211            if x >= 0xDC00: 
    212                x -= 0xDC00 
    213            if y >= 0xDC00: 
    214                y -= 0xDC00 
    215 
    216            x -= 32 
    217            y -= 32 
    218        else: 
    219            # Urxvt and Xterm SGR. 
    220            # When the '<' is not present, we are not using the Xterm SGR mode, 
    221            # but Urxvt instead. 
    222            data = event.data[2:] 
    223            if data[:1] == "<": 
    224                sgr = True 
    225                data = data[1:] 
    226            else: 
    227                sgr = False 
    228 
    229            # Extract coordinates. 
    230            mouse_event, x, y = map(int, data[:-1].split(";")) 
    231            m = data[-1] 
    232 
    233            # Parse event type. 
    234            if sgr: 
    235                try: 
    236                    ( 
    237                        mouse_button, 
    238                        mouse_event_type, 
    239                        mouse_modifiers, 
    240                    ) = xterm_sgr_mouse_events[mouse_event, m] 
    241                except KeyError: 
    242                    return NotImplemented 
    243 
    244            else: 
    245                # Some other terminals, like urxvt, Hyper terminal, ... 
    246                ( 
    247                    mouse_button, 
    248                    mouse_event_type, 
    249                    mouse_modifiers, 
    250                ) = urxvt_mouse_events.get( 
    251                    mouse_event, (UNKNOWN_BUTTON, MOUSE_MOVE, UNKNOWN_MODIFIER) 
    252                ) 
    253 
    254        x -= 1 
    255        y -= 1 
    256 
    257        # Only handle mouse events when we know the window height. 
    258        if event.app.renderer.height_is_known and mouse_event_type is not None: 
    259            # Take region above the layout into account. The reported 
    260            # coordinates are absolute to the visible part of the terminal. 
    261            from prompt_toolkit.renderer import HeightIsUnknownError 
    262 
    263            try: 
    264                y -= event.app.renderer.rows_above_layout 
    265            except HeightIsUnknownError: 
    266                return NotImplemented 
    267 
    268            # Call the mouse handler from the renderer. 
    269 
    270            # Note: This can return `NotImplemented` if no mouse handler was 
    271            #       found for this position, or if no repainting needs to 
    272            #       happen. this way, we avoid excessive repaints during mouse 
    273            #       movements. 
    274            handler = event.app.renderer.mouse_handlers.mouse_handlers[y][x] 
    275            return handler( 
    276                MouseEvent( 
    277                    position=Point(x=x, y=y), 
    278                    event_type=mouse_event_type, 
    279                    button=mouse_button, 
    280                    modifiers=mouse_modifiers, 
    281                ) 
    282            ) 
    283 
    284        return NotImplemented 
    285 
    286    @key_bindings.add(Keys.ScrollUp) 
    287    def _scroll_up(event: E) -> None: 
    288        """ 
    289        Scroll up event without cursor position. 
    290        """ 
    291        # We don't receive a cursor position, so we don't know which window to 
    292        # scroll. Just send an 'up' key press instead. 
    293        event.key_processor.feed(KeyPress(Keys.Up), first=True) 
    294 
    295    @key_bindings.add(Keys.ScrollDown) 
    296    def _scroll_down(event: E) -> None: 
    297        """ 
    298        Scroll down event without cursor position. 
    299        """ 
    300        event.key_processor.feed(KeyPress(Keys.Down), first=True) 
    301 
    302    @key_bindings.add(Keys.WindowsMouseEvent) 
    303    def _mouse(event: E) -> NotImplementedOrNone: 
    304        """ 
    305        Handling of mouse events for Windows. 
    306        """ 
    307        # This key binding should only exist for Windows. 
    308        if sys.platform == "win32": 
    309            # Parse data. 
    310            pieces = event.data.split(";") 
    311 
    312            button = MouseButton(pieces[0]) 
    313            event_type = MouseEventType(pieces[1]) 
    314            x = int(pieces[2]) 
    315            y = int(pieces[3]) 
    316 
    317            # Make coordinates absolute to the visible part of the terminal. 
    318            output = event.app.renderer.output 
    319 
    320            from prompt_toolkit.output.win32 import Win32Output 
    321            from prompt_toolkit.output.windows10 import Windows10_Output 
    322 
    323            if isinstance(output, (Win32Output, Windows10_Output)): 
    324                screen_buffer_info = output.get_win32_screen_buffer_info() 
    325                rows_above_cursor = ( 
    326                    screen_buffer_info.dwCursorPosition.Y 
    327                    - event.app.renderer._cursor_pos.y 
    328                ) 
    329                y -= rows_above_cursor 
    330 
    331                # Call the mouse event handler. 
    332                # (Can return `NotImplemented`.) 
    333                handler = event.app.renderer.mouse_handlers.mouse_handlers[y][x] 
    334 
    335                return handler( 
    336                    MouseEvent( 
    337                        position=Point(x=x, y=y), 
    338                        event_type=event_type, 
    339                        button=button, 
    340                        modifiers=UNKNOWN_MODIFIER, 
    341                    ) 
    342                ) 
    343 
    344        # No mouse handler found. Return `NotImplemented` so that we don't 
    345        # invalidate the UI. 
    346        return NotImplemented 
    347 
    348    return key_bindings