File: mouse.rst

package info (click to toggle)
python-blessed 1.25-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 8,812 kB
  • sloc: python: 14,645; makefile: 13; sh: 7
file content (208 lines) | stat: -rw-r--r-- 7,246 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
.. _`mouse input`:

Mouse Input
===========

Blessed supports mouse input in the terminal! Your applications can respond to
clicks, drags, scroll wheel, or track live mouse cursor movement, even at the
pixel-level, for creating interactive games and apps.

Overview:

* Check for support using :meth:`~blessed.Terminal.does_mouse`
* Enable mouse input with :meth:`~blessed.Terminal.mouse_enabled`
* Receive events through :meth:`~blessed.Terminal.inkey`

Mouse events work seamlessly with keyboard events - both come through the same
:meth:`~blessed.Terminal.inkey` method.

Getting Started
---------------

Here is a basic example:

.. literalinclude:: ../bin/mouse_simple.py
   :language: python
   :linenos:

The :meth:`~.Terminal.mouse_enabled` context manager enables mouse tracking
and automatically disables it when done. Mouse events arrive through
:meth:`~.Terminal.inkey` just like keyboard events.

Mouse events can be detected by checking if :attr:`~.Keystroke.name` starts
with ``'MOUSE_'``. The name includes the button and any modifiers, such as
``'MOUSE_LEFT'``, ``'MOUSE_CTRL_LEFT'``, or ``'MOUSE_SCROLL_UP'``. You can
also use magic method predicates like ``inp.is_mouse_left()``.

.. note::

   Mouse coordinates are **0-indexed**, matching blessed's terminal movement
   functions like :meth:`~.Terminal.move_yx`. The top-left corner is ``(y=0, x=0)``,
   not ``(1, 1)``. This allows direct use of mouse coordinates with movement functions.

Understanding Buttons
---------------------

Mouse events come through :meth:`~.Terminal.inkey` just like keyboard events.

You can detect mouse events using either the :attr:`~.Keystroke.name` property
or magic method predicates:

**Using the name property:**

The :attr:`~.Keystroke.name` returns button names with the ``MOUSE_`` prefix,
following the pattern ``MOUSE_[MODIFIERS_]BUTTON[_RELEASED]``:

.. code-block:: python

   inp = term.inkey()
   if inp.name == 'MOUSE_LEFT':
       print("Left button pressed")

**Using magic method predicates:**

.. code-block:: python

   inp = term.inkey()
   if inp.is_mouse_left():
       print("Left button pressed")
   elif inp.is_mouse_ctrl_left():
       print("Ctrl+Left button pressed")

**Button names include:**

- Basic events: ``MOUSE_LEFT``, ``MOUSE_MIDDLE``, ``MOUSE_RIGHT``, ``MOUSE_SCROLL_UP``,
  ``MOUSE_SCROLL_DOWN``
- Release events: ``MOUSE_LEFT_RELEASED``, ``MOUSE_MIDDLE_RELEASED``,
  ``MOUSE_RIGHT_RELEASED``
- With modifiers: ``MOUSE_CTRL_LEFT``, ``MOUSE_SHIFT_SCROLL_UP``, ``MOUSE_META_RIGHT``,
  ``MOUSE_CTRL_SHIFT_META_MIDDLE``

Modifiers are included in order ``CTRL``, ``SHIFT``, and ``META``

In this example, all possible combinations may be entered and recorded, see if
you have enough fingers for ``CTRL_SHIFT_META_MIDDLE``, imagine the
possibilities!

.. literalinclude:: ../bin/mouse_modifiers.py
   :language: python
   :linenos:

Understanding Mouse Coordinates
-------------------------------

Mouse coordinates are accessed by :attr:`~Keystroke.mouse_yx` attribute in as
tuple ``(int, int)`` of the corresponding row and column. This matches the
signature of :meth:`~Terminal.move_yx`. If :attr:`~Keystroke.mouse_yx` is used
on a keystroke that is not a mouse event, values ``(-1, -1)`` are returned.

There is also a :attr:`~Keystroke.mouse_xy` attribute that mirrors the signature
of :meth:`~Terminal.move_xy`.

- :attr:`~.Keystroke.mouse_yx` - position as a ``(y, x)`` tuple
- :attr:`~.Keystroke.mouse_xy` - position as an ``(x, y)`` tuple

.. literalinclude:: ../bin/mouse_coords.py
   :language: python
   :linenos:

Checking Support
----------------

Not all terminals support mouse tracking or all kinds of mouse tracking.

Use :meth:`~blessed.Terminal.does_mouse` to check before enabling:

.. literalinclude:: ../bin/mouse_query.py
   :language: python
   :linenos:

The :meth:`~.Terminal.does_mouse` method accepts the same parameters as
:meth:`~.Terminal.mouse_enabled` and returns ``True`` if all of given modes are
supported.

Using mouse_enabled()
---------------------

The :meth:`~blessed.Terminal.mouse_enabled` context manager enables the appropriate
:ref:`dec private modes` depending on the simplified arguments given.

:meth:`~blessed.Terminal.mouse_enabled` accepts these keyword-only parameters:

* ``clicks=True`` - Enable basic click reporting (default).
* ``report_drag=False`` - Report motion while a button is held.
* ``report_motion=False`` - Report all mouse movement.
* ``report_pixels=False`` - Report position in pixels instead of cells.
* ``timeout=1.0`` - Timeout for mode queries, in seconds.

**Parameter Precedence**

The tracking modes have precedence: ``report_motion`` > ``report_drag`` > ``clicks``.
When you enable a higher-precedence mode, it automatically includes the functionality
of lower modes. For example, ``report_motion=True`` will also track drags and clicks.

report_drag
~~~~~~~~~~~

Reports motion only while a button is held down:

.. literalinclude:: ../bin/mouse_drag.py
   :language: python
   :linenos:

When using ``report_drag=True`` or ``report_motion=True``, you'll receive motion
events in the :attr:`~Keystroke.name` attribute with a ``_MOTION`` suffix:

- ``MOUSE_MOTION`` - Motion without any button pressed (``report_motion``)
- ``MOUSE_LEFT_MOTION``, ``MOUSE_MIDDLE_MOTION``, ``MOUSE_RIGHT_MOTION`` -
  Dragging with a button held, usually follows click, eg. ``MOUSE_LEFT``.

Motion events include modifiers just like click events, for example ``MOUSE_CTRL_LEFT_MOTION``.

.. _report_motion:

report_motion
~~~~~~~~~~~~~

Reports all mouse clicks movement, even without buttons pressed. The
:attr:`~Keystroke.name` attribute of ``MOUSE_MOTION`` is given when no button or
scroll wheel events have occurred, only an updated :attr:`~Keystroke.mouse_yx`
position.

In this example, the terminal cursor tracks with the mouse pointer because the
:meth:`~Terminal.move_yx` sequence is displayed following any mouse event,
especially ``MOUSE_MOTION``, tracking the :attr:`Keystroke.mouse_yx` coordinate.

.. literalinclude:: ../bin/mouse_paint.py
   :language: python
   :linenos:

.. figure:: https://dxtz6bzwq9sxx.cloudfront.net/mouse_paint.gif

Painting is done while the left mouse button is held down, tracking both
``MOUSE_LEFT`` and ``MOUSE_LEFT_MOTION``, erased with ``MOUSE_RIGHT``, and color
selection changed by ``MOUSE_SCROLL_UP`` and ``MOUSE_SCROLL_DOWN``.

.. note::

   When using ``report_motion=True``, process events quickly! Mouse movement
   generates many events that can fill the input buffer if not consumed promptly.

report_pixels
~~~~~~~~~~~~~

By default, mouse positions are reported in character cell coordinates - each
position corresponds to a single character in the terminal grid.

For higher precision, use ``report_pixels=True`` to get pixel coordinates instead.
This is especially useful when combined with graphics protocols like Sixel:

.. literalinclude:: ../bin/mouse_pixels.py
   :language: python
   :linenos:

When using pixel mode, mouse events still use the same :attr:`~.Keystroke.name`
pattern (e.g., ``'MOUSE_LEFT'``) and magic method predicates (e.g.,
``inp.is_mouse_left()``). The :attr:`~.Keystroke.x` and :attr:`~.Keystroke.y`
properties represent pixels instead of character cells.