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 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
|
.. _key_bindings:
More about key bindings
=======================
This page contains a few additional notes about key bindings.
Key bindings can be defined as follows by creating a
:class:`~prompt_toolkit.key_binding.KeyBindings` instance:
.. code:: python
from prompt_toolkit.key_binding import KeyBindings
bindings = KeyBindings()
@bindings.add('a')
def _(event):
" Do something if 'a' has been pressed. "
...
@bindings.add('c-t')
def _(event):
" Do something if Control-T has been pressed. "
...
.. note::
:kbd:`c-q` (control-q) and :kbd:`c-s` (control-s) are often captured by the
terminal, because they were used traditionally for software flow control.
When this is enabled, the application will automatically freeze when
:kbd:`c-s` is pressed, until :kbd:`c-q` is pressed. It won't be possible to
bind these keys.
In order to disable this, execute the following command in your shell, or even
add it to your `.bashrc`.
.. code::
stty -ixon
Key bindings can even consist of a sequence of multiple keys. The binding is
only triggered when all the keys in this sequence are pressed.
.. code:: python
@bindings.add('a', 'b')
def _(event):
" Do something if 'a' is pressed and then 'b' is pressed. "
...
If the user presses only `a`, then nothing will happen until either a second
key (like `b`) has been pressed or until the timeout expires (see later).
List of special keys
--------------------
Besides literal characters, any of the following keys can be used in a key
binding:
+-------------------+-----------------------------------------+
| Name + Possible keys |
+===================+=========================================+
| Escape | :kbd:`escape` |
| Shift + escape | :kbd:`s-escape` |
+-------------------+-----------------------------------------+
| Arrows | :kbd:`left`, |
| | :kbd:`right`, |
| | :kbd:`up`, |
| | :kbd:`down` |
+-------------------+-----------------------------------------+
| Navigation | :kbd:`home`, |
| | :kbd:`end`, |
| | :kbd:`delete`, |
| | :kbd:`pageup`, |
| | :kbd:`pagedown`, |
| | :kbd:`insert` |
+-------------------+-----------------------------------------+
| Control+letter | :kbd:`c-a`, :kbd:`c-b`, :kbd:`c-c`, |
| | :kbd:`c-d`, :kbd:`c-e`, :kbd:`c-f`, |
| | :kbd:`c-g`, :kbd:`c-h`, :kbd:`c-i`, |
| | :kbd:`c-j`, :kbd:`c-k`, :kbd:`c-l`, |
| | |
| | :kbd:`c-m`, :kbd:`c-n`, :kbd:`c-o`, |
| | :kbd:`c-p`, :kbd:`c-q`, :kbd:`c-r`, |
| | :kbd:`c-s`, :kbd:`c-t`, :kbd:`c-u`, |
| | :kbd:`c-v`, :kbd:`c-w`, :kbd:`c-x`, |
| | |
| | :kbd:`c-y`, :kbd:`c-z` |
+-------------------+-----------------------------------------+
| Control + number | :kbd:`c-1`, :kbd:`c-2`, :kbd:`c-3`, |
| | :kbd:`c-4`, :kbd:`c-5`, :kbd:`c-6`, |
| | :kbd:`c-7`, :kbd:`c-8`, :kbd:`c-9`, |
| | :kbd:`c-0` |
+-------------------+-----------------------------------------+
| Control + arrow | :kbd:`c-left`, |
| | :kbd:`c-right`, |
| | :kbd:`c-up`, |
| | :kbd:`c-down` |
+-------------------+-----------------------------------------+
| Other control | :kbd:`c-@`, |
| keys | :kbd:`c-\\`, |
| | :kbd:`c-]`, |
| | :kbd:`c-^`, |
| | :kbd:`c-_`, |
| | :kbd:`c-delete` |
+-------------------+-----------------------------------------+
| Shift + arrow | :kbd:`s-left`, |
| | :kbd:`s-right`, |
| | :kbd:`s-up`, |
| | :kbd:`s-down` |
+-------------------+-----------------------------------------+
| Control + Shift + | :kbd:`c-s-left`, |
| arrow | :kbd:`c-s-right`, |
| | :kbd:`c-s-up`, |
| | :kbd:`c-s-down` |
+-------------------+-----------------------------------------+
| Other shift | :kbd:`s-delete`, |
| keys | :kbd:`s-tab` |
+-------------------+-----------------------------------------+
| F-keys | :kbd:`f1`, :kbd:`f2`, :kbd:`f3`, |
| | :kbd:`f4`, :kbd:`f5`, :kbd:`f6`, |
| | :kbd:`f7`, :kbd:`f8`, :kbd:`f9`, |
| | :kbd:`f10`, :kbd:`f11`, :kbd:`f12`, |
| | |
| | :kbd:`f13`, :kbd:`f14`, :kbd:`f15`, |
| | :kbd:`f16`, :kbd:`f17`, :kbd:`f18`, |
| | :kbd:`f19`, :kbd:`f20`, :kbd:`f21`, |
| | :kbd:`f22`, :kbd:`f23`, :kbd:`f24` |
+-------------------+-----------------------------------------+
There are a couple of useful aliases as well:
+-------------------+-------------------+
| :kbd:`c-h` | :kbd:`backspace` |
+-------------------+-------------------+
| :kbd:`c-@` | :kbd:`c-space` |
+-------------------+-------------------+
| :kbd:`c-m` | :kbd:`enter` |
+-------------------+-------------------+
| :kbd:`c-i` | :kbd:`tab` |
+-------------------+-------------------+
.. note::
Note that the supported keys are limited to what typical VT100 terminals
offer. Binding :kbd:`c-7` (control + number 7) for instance is not
supported.
Binding alt+something, option+something or meta+something
---------------------------------------------------------
Vt100 terminals translate the alt key into a leading :kbd:`escape` key.
For instance, in order to handle :kbd:`alt-f`, we have to handle
:kbd:`escape` + :kbd:`f`. Notice that we receive this as two individual keys.
This means that it's exactly the same as first typing :kbd:`escape` and then
typing :kbd:`f`. Something this alt-key is also known as option or meta.
In code that looks as follows:
.. code:: python
@bindings.add('escape', 'f')
def _(event):
" Do something if alt-f or meta-f have been pressed. "
Wildcards
---------
Sometimes you want to catch any key that follows after a certain key stroke.
This is possible by binding the '<any>' key:
.. code:: python
@bindings.add('a', '<any>')
def _(event):
...
This will handle `aa`, `ab`, `ac`, etcetera. The key binding can check the
`event` object for which keys exactly have been pressed.
Attaching a filter (condition)
------------------------------
In order to enable a key binding according to a certain condition, we have to
pass it a :class:`~prompt_toolkit.filters.Filter`, usually a
:class:`~prompt_toolkit.filters.Condition` instance. (:ref:`Read more about
filters <filters>`.)
.. code:: python
from prompt_toolkit.filters import Condition
@Condition
def is_active():
" Only activate key binding on the second half of each minute. "
return datetime.datetime.now().second > 30
@bindings.add('c-t', filter=is_active)
def _(event):
# ...
pass
The key binding will be ignored when this condition is not satisfied.
ConditionalKeyBindings: Disabling a set of key bindings
-------------------------------------------------------
Sometimes you want to enable or disable a whole set of key bindings according
to a certain condition. This is possible by wrapping it in a
:class:`~prompt_toolkit.key_binding.ConditionalKeyBindings` object.
.. code:: python
from prompt_toolkit.key_binding import ConditionalKeyBindings
@Condition
def is_active():
" Only activate key binding on the second half of each minute. "
return datetime.datetime.now().second > 30
bindings = ConditionalKeyBindings(
key_bindings=my_bindings,
filter=is_active)
If the condition is not satisfied, all the key bindings in `my_bindings` above
will be ignored.
Merging key bindings
--------------------
Sometimes you have different parts of your application generate a collection of
key bindings. It is possible to merge them together through the
:func:`~prompt_toolkit.key_binding.merge_key_bindings` function. This is
preferred above passing a :class:`~prompt_toolkit.key_binding.KeyBindings`
object around and having everyone populate it.
.. code:: python
from prompt_toolkit.key_binding import merge_key_bindings
bindings = merge_key_bindings([
bindings1,
bindings2,
])
Eager
-----
Usually not required, but if ever you have to override an existing key binding,
the `eager` flag can be useful.
Suppose that there is already an active binding for `ab` and you'd like to add
a second binding that only handles `a`. When the user presses only `a`,
prompt_toolkit has to wait for the next key press in order to know which
handler to call.
By passing the `eager` flag to this second binding, we are actually saying that
prompt_toolkit shouldn't wait for longer matches when all the keys in this key
binding are matched. So, if `a` has been pressed, this second binding will be
called, even if there's an active `ab` binding.
.. code:: python
@bindings.add('a', 'b')
def binding_1(event):
...
@bindings.add('a', eager=True)
def binding_2(event):
...
This is mainly useful in order to conditionally override another binding.
Asyncio coroutines
------------------
Key binding handlers can be asyncio coroutines.
.. code:: python
from prompt_toolkit.application import in_terminal
@bindings.add('x')
async def print_hello(event):
"""
Pressing 'x' will print 5 times "hello" in the background above the
prompt.
"""
for i in range(5):
# Print hello above the current prompt.
async with in_terminal():
print('hello')
# Sleep, but allow further input editing in the meantime.
await asyncio.sleep(1)
If the user accepts the input on the prompt, while this coroutine is not yet
finished , an `asyncio.CancelledError` exception will be thrown in this
coroutine.
Timeouts
--------
There are two timeout settings that effect the handling of keys.
- ``Application.ttimeoutlen``: Like Vim's `ttimeoutlen` option.
When to flush the input (For flushing escape keys.) This is important on
terminals that use vt100 input. We can't distinguish the escape key from for
instance the left-arrow key, if we don't know what follows after "\x1b". This
little timer will consider "\x1b" to be escape if nothing did follow in this
time span. This seems to work like the `ttimeoutlen` option in Vim.
- ``KeyProcessor.timeoutlen``: like Vim's `timeoutlen` option.
This can be `None` or a float. For instance, suppose that we have a key
binding AB and a second key binding A. If the uses presses A and then waits,
we don't handle this binding yet (unless it was marked 'eager'), because we
don't know what will follow. This timeout is the maximum amount of time that
we wait until we call the handlers anyway. Pass `None` to disable this
timeout.
Recording macros
----------------
Both Emacs and Vi mode allow macro recording. By default, all key presses are
recorded during a macro, but it is possible to exclude certain keys by setting
the `record_in_macro` parameter to `False`:
.. code:: python
@bindings.add('c-t', record_in_macro=False)
def _(event):
# ...
pass
Creating new Vi text objects and operators
------------------------------------------
We tried very hard to ship prompt_toolkit with as many as possible Vi text
objects and operators, so that text editing feels as natural as possible to Vi
users.
If you wish to create a new text object or key binding, that is actually
possible. Check the `custom-vi-operator-and-text-object.py` example for more
information.
Handling SIGINT
---------------
The SIGINT Unix signal can be handled by binding ``<sigint>``. For instance:
.. code:: python
@bindings.add('<sigint>')
def _(event):
# ...
pass
This will handle a SIGINT that was sent by an external application into the
process. Handling control-c should be done by binding ``c-c``. (The terminal
input is set to raw mode, which means that a ``c-c`` won't be translated into a
SIGINT.)
For a ``PromptSession``, there is a default binding for ``<sigint>`` that
corresponds to ``c-c``: it will exit the prompt, raising a
``KeyboardInterrupt`` exception.
Processing `.inputrc`
---------------------
GNU readline can be configured using an `.inputrc` configuration file. This file
contains key bindings as well as certain settings. Right now, prompt_toolkit
doesn't support `.inputrc`, but it should be possible in the future.
|