Keyboard Input

Python’s built-in input() function is great for simple prompts, but it has one limitation: it waits for the Enter key. This makes it unsuitable for interactive applications that need to respond to individual keystrokes, arrow keys, or function keys.

Blessed provides a solution with inkey(), which returns keystrokes as they are pressed, as Keystroke objects.

Overview

The cbreak() context manager enables immediate key detection.

The inkey() method returns a Keystroke object representing the key that was immediately pressed.

Getting Started

Here’s a simple example that reads a single keystroke:

1#!/usr/bin/env python3
2from blessed import Terminal
3
4term = Terminal()
5with term.cbreak():
6    key = term.inkey()
7    print(f"You pressed: {key!r}")

The inkey() method also accepts a timeout parameter that defaults to 1 second. When timeout is exceeded without input, an empty Keystroke is returned, ''.

In this example, a 10Hz animation is displayed by timeout=0.1, stopped by pressing any key:

 1#!/usr/bin/env python3
 2from blessed import Terminal
 3
 4term = Terminal()
 5print("Cross animation, press any key to stop: ", end="", flush=True)
 6with term.cbreak(), term.hidden_cursor():
 7    cross = '|'
 8
 9    while True:
10        key = term.inkey(timeout=0.1)
11        if key:
12            print(f'STOP by {key!r}')
13            break
14
15        cross = {'|': '-', '-': '|'}[cross]
16        print(f'{cross}\b', end='', flush=True)

Keystroke

The Keystroke class makes it easy to work with keyboard input. It inherits from str, so you can compare it directly to other strings, but it also provides special properties for detecting modifier keys and special sequences.

  • Use is_sequence to detect special keys

  • Use name to identify special keys by name (e.g., KEY_F1, KEY_CTRL_Q)

  • Or, by using magic methods like keystroke.is_f1() or keystroke.is_key_ctrl('q').

Be careful printing Keystroke objects directly. Our examples uses format string, f'{ks!r}' for repr(), because str(ks) may contain control characters or escape sequences beginning with (KEY_ESCAPE) and are generally unprintable.

Special Keys

The is_sequence property returns True for arrow keys, function keys, and any character key combined with modifiers (Ctrl, Alt, Shift).

 1#!/usr/bin/env python3
 2from blessed import Terminal
 3
 4term = Terminal()
 5with term.cbreak():
 6    key = term.inkey()
 7
 8    if key.is_sequence:
 9        print(f"Special key: {key.name} ({key!r})")
10    else:
11        print(f"Regular character: {key}")

The str(key) value for Keystroke should not be directly printed when is_sequence is True as done in this and other examples.

The name property provides a readable name for special keys, and can be used for basic equality tests, like in this “paint by arrow key” example:

 1#!/usr/bin/env python3
 2from blessed import Terminal
 3
 4header_msg = "Press arrow keys (or 'q' to quit): "
 5term = Terminal()
 6position = [term.height // 2, term.width // 2]
 7with term.cbreak(), term.fullscreen(), term.hidden_cursor():
 8    print(term.home + header_msg + term.clear_eos)
 9
10    while True:
11        # show arrow-controlled block
12        print(term.move_yx(*position) + '█', end='', flush=True)
13
14        # get key,
15        key = term.inkey()
16
17        # take action,
18        if key == 'q':
19            break
20        if key.name == 'KEY_UP':
21            position[0] = max(0, position[0] - 1)
22        elif key.name == 'KEY_LEFT':
23            position[1] = max(0, position[1] - 1)
24        elif key.name == 'KEY_DOWN':
25            position[0] = min(term.height, position[0] + 1)
26        elif key.name == 'KEY_RIGHT':
27            position[1] = min(term.width, position[1] + 1)

Common key names include:

  • KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT - Arrow keys

  • KEY_ENTER - Enter/Return key

  • KEY_BACKSPACE, KEY_DELETE - Backspace and Delete keys

  • KEY_TAB - Tab key

  • KEY_ESCAPE - Escape key

  • KEY_F1 through KEY_F12 - Function keys

  • KEY_PGUP, KEY_PGDOWN - Page Up and Page Down

  • KEY_HOME, KEY_END - Home and End keys

For regular characters without modifiers, name returns None in legacy mode. In Kitty keyboard protocol mode, all ASCII alphanumeric and punctuation keys receive synthesized names – see Key Name Synthesis.

Feel free to try the demonstration program, keymatrix.py to experiment with possible keyboard inputs and combinations.

Modifiers

Alphanumeric keys with modifiers follow the pattern:

  • KEY_CTRL_A

  • KEY_ALT_Q

  • KEY_CTRL_ALT_Y

For alphanumeric keys, SHIFT is not represented in the key name. Instead, case is handled through the character itself and the ignore_case parameter in Magic Methods. Control characters are case-insensitive at the protocol level (Ctrl+A and Ctrl+Shift+A are identical). For Alt modifiers, use ignore_case=False to distinguish case: key.is_alt('a', ignore_case=False) matches only lowercase, while key.is_alt('A', ignore_case=False) matches only uppercase.

Application keys (arrows, function keys, etc.) support SHIFT in their names:

  • KEY_SHIFT_LEFT

  • KEY_CTRL_ALT_BACKSPACE

  • KEY_ALT_DELETE

  • KEY_CTRL_SHIFT_F3

  • KEY_CTRL_ALT_SHIFT_F9

When multiple modifiers are specified in application key names, they are always in the following order:

  • CTRL

  • ALT

  • SHIFT

The escape sequence '\x1b[' is always decoded as name CSI in legacy mode when it arrives without any known matching sequence.

The value property returns the text character for keys that produce text, stripping away modifier information.

Special keys like KEY_UP, KEY_F1, KEY_BACKSPACE have an empty value string.

Control characters like KEY_CTRL_C are value c (lowercase). Similarly for alt, KEY_ALT_a is value a.

Event Types

The Keystroke class provides properties about key events:

  • pressed - True if this is a key press event

  • repeated - True if this is a key repeat event

  • released - True if this is a key release event

For press/release tracking, two additional properties provide stable identifiers across event types:

  • key_name - like name, but without the _RELEASED or _REPEATED suffix, so that the same key always returns the same name regardless of event type.

  • key_value - like value, but returns the character even for release events (where value returns '').

Note: These event types can only be distinguished when using the Kitty Keyboard Protocol. Without it, all keystrokes will have pressed=True and repeated=False, released=False.

See Kitty Keyboard Protocol for more information about enabling and using the Kitty Keyboard Protocol.

Magic Methods

The Keystroke class provides convenient “magic methods” for checking keys with modifiers. These methods all start with is_:

 1#!/usr/bin/env python3
 2from blessed import Terminal
 3
 4term = Terminal()
 5print("Press 'q' or F10 to exit! Press F1 for help")
 6with term.cbreak():
 7    while True:
 8        key = term.inkey()
 9
10        # Check for specific character with modifier
11        if key.is_ctrl('q') or key.is_f10():
12            print(f"Exit by key named {key.name}")
13            break
14
15        # Check for function key
16        elif key.is_f1():
17            print("* don't panic")

Some examples, given key object of Keystroke:

  • key.is_ctrl('x')

  • key.is_alt('q')

  • key.is_ctrl_alt('s')

  • key.is_ctrl_shift_alt('a')

  • key.is_f1()

  • key.is_up()

  • key.is_enter()

  • key.is_backspace()

  • key.is_ctrl_left()

  • key.is_alt_backspace()

  • key.is_shift_f5()

By default, character matching is case-insensitive. You can change this with the ignore_case parameter. For example, “Alt” with capital letter U matches both methods:

  • key.is_alt('u')

  • key.is_alt_shift('u')

To explicitly match only “Alt + u” (lowercase ‘U’), set ignore_case argument to False:

  • key.is_alt('u', ignore_case=False)

All Names

These are duplicated from the key names found in curses(3), or those constants in curses beginning with phrase KEY_, as follows:

All Terminal class attribute Keyboard codes, by name

Name

Value

Example Sequence(s)

KEY_BACKSPACE

263

‘\x08’, ‘\x7f’

KEY_BEGIN

354

KEY_BTAB

353

KEY_CANCEL

355

KEY_CAPS_LOCK

57358

KEY_CATAB

342

KEY_CENTER

350

‘\x1b[E’

KEY_CLEAR

333

KEY_CLOSE

356

KEY_COMMAND

357

KEY_COPY

358

KEY_CREATE

359

KEY_CTAB

341

KEY_DELETE

330

‘\x1b[3~’

KEY_DL

328

KEY_DOWN

258

‘\x1b[B’, ‘\x1b[OB’

KEY_DOWN_LEFT

351

KEY_DOWN_RIGHT

352

KEY_EIC

332

KEY_END

360

‘\x1b[F’, ‘\x1b[K’, ‘\x1b[4~’, ‘\x1b[8~’, ‘\x1b[OF’

KEY_ENTER

343

‘\n’, ‘\r’, ‘\x1bOM’

KEY_EOL

335

KEY_EOS

334

KEY_ESCAPE

361

‘\x1b’

KEY_F0

264

KEY_F1

265

‘\x1bOP’, ‘\x1b[P’

KEY_F10

274

KEY_F11

275

KEY_F12

276

KEY_F13

57376

KEY_F14

57377

KEY_F15

57378

KEY_F16

57379

KEY_F17

57380

KEY_F18

57381

KEY_F19

57382

KEY_F2

266

‘\x1bOQ’, ‘\x1b[Q’

KEY_F20

57383

KEY_F21

57384

KEY_F22

57385

KEY_F23

57386

KEY_F3

267

‘\x1bOR’, ‘\x1b[13~’

KEY_F4

268

‘\x1bOS’, ‘\x1b[S’

KEY_F5

269

KEY_F6

270

KEY_F7

271

KEY_F8

272

KEY_F9

273

KEY_FIND

362

KEY_HELP

363

KEY_HOME

262

‘\x1b[H’, ‘\x1b[1~’, ‘\x1b[7~’, ‘\x1b[OH’

KEY_IL

329

KEY_INSERT

331

‘\x1b[2~’

KEY_ISO_LEVEL3_SHIFT

57453

KEY_ISO_LEVEL5_SHIFT

57454

KEY_KP_0

520

‘\x1bOp’

KEY_KP_1

521

‘\x1bOq’

KEY_KP_2

522

‘\x1bOr’

KEY_KP_3

523

‘\x1bOs’

KEY_KP_4

524

‘\x1bOt’

KEY_KP_5

525

‘\x1bOu’

KEY_KP_6

526

‘\x1bOv’

KEY_KP_7

527

‘\x1bOw’

KEY_KP_8

528

‘\x1bOx’

KEY_KP_9

529

‘\x1bOy’

KEY_KP_ADD

514

‘\x1bOk’

KEY_KP_BEGIN

57427

KEY_KP_DECIMAL

517

‘\x1bOn’

KEY_KP_DELETE

57426

KEY_KP_DIVIDE

518

‘\x1bOo’

KEY_KP_DOWN

57420

KEY_KP_END

57424

KEY_KP_ENTER

57414

KEY_KP_EQUAL

519

‘\x1bOX’

KEY_KP_HOME

57423

KEY_KP_INSERT

57425

KEY_KP_LEFT

57417

KEY_KP_MULTIPLY

513

‘\x1bOj’

KEY_KP_PAGE_DOWN

57422

KEY_KP_PAGE_UP

57421

KEY_KP_RIGHT

57418

KEY_KP_SEPARATOR

515

‘\x1bOl’

KEY_KP_SUBTRACT

516

‘\x1bOm’

KEY_KP_UP

57419

KEY_LEFT

260

‘\x1b[D’, ‘\x1b[OD’

KEY_LEFT_ALT

57443

KEY_LEFT_CONTROL

57442

KEY_LEFT_HYPER

57445

KEY_LEFT_META

57446

KEY_LEFT_SHIFT

57441

KEY_LEFT_SUPER

57444

KEY_LL

347

KEY_LOWER_VOLUME

57438

KEY_MARK

364

KEY_MAX

511

KEY_MEDIA_FAST_FORWARD

57433

KEY_MEDIA_PAUSE

57429

KEY_MEDIA_PLAY

57428

KEY_MEDIA_PLAY_PAUSE

57430

KEY_MEDIA_RECORD

57437

KEY_MEDIA_REVERSE

57431

KEY_MEDIA_REWIND

57434

KEY_MEDIA_STOP

57432

KEY_MEDIA_TRACK_NEXT

57435

KEY_MEDIA_TRACK_PREVIOUS

57436

KEY_MENU

57363

KEY_MESSAGE

365

KEY_MIN

257

KEY_MOUSE

409

KEY_MOVE

366

KEY_MUTE_VOLUME

57440

KEY_NEXT

367

KEY_NUM_LOCK

57360

KEY_OPEN

368

KEY_OPTIONS

369

KEY_PAUSE

57362

KEY_PGDOWN

338

‘\x1b[U’, ‘\x1b[6~’

KEY_PGUP

339

‘\x1b[V’, ‘\x1b[5~’

KEY_PREVIOUS

370

KEY_PRINT

346

KEY_PRINT_SCREEN

57361

KEY_RAISE_VOLUME

57439

KEY_REDO

371

KEY_REFERENCE

372

KEY_REFRESH

373

KEY_REPLACE

374

KEY_RESET

345

KEY_RESIZE

410

KEY_RESTART

375

KEY_RESUME

376

KEY_RIGHT

261

‘\x1b[C’, ‘\x1b[OC’

KEY_RIGHT_ALT

57449

KEY_RIGHT_CONTROL

57448

KEY_RIGHT_HYPER

57451

KEY_RIGHT_META

57452

KEY_RIGHT_SHIFT

57447

KEY_RIGHT_SUPER

57450

KEY_SAVE

377

KEY_SBEG

378

KEY_SCANCEL

379

KEY_SCOMMAND

380

KEY_SCOPY

381

KEY_SCREATE

382

KEY_SCROLL_LOCK

57359

KEY_SDC

383

KEY_SDL

384

KEY_SDOWN

336

‘\x1b[1;2B’

KEY_SELECT

385

KEY_SEND

386

KEY_SEOL

387

KEY_SEXIT

388

KEY_SFIND

389

KEY_SHELP

390

KEY_SHOME

391

KEY_SIC

392

KEY_SLEFT

393

‘\x1b[1;2D’

KEY_SMESSAGE

394

KEY_SMOVE

395

KEY_SNEXT

396

KEY_SOPTIONS

397

KEY_SPREVIOUS

398

KEY_SPRINT

399

KEY_SREDO

400

KEY_SREPLACE

401

KEY_SRESET

344

KEY_SRIGHT

402

‘\x1b[1;2C’

KEY_SRSUME

403

KEY_SSAVE

404

KEY_SSUSPEND

405

KEY_STAB

340

KEY_SUNDO

406

KEY_SUP

337

‘\x1b[1;2A’

KEY_SUSPEND

407

KEY_TAB

512

‘\t’

KEY_UNDO

408

KEY_UP

259

‘\x1b[A’, ‘\x1b[OA’

KEY_UP_LEFT

348

KEY_UP_RIGHT

349

However, these keys do not represent the full range of keys that can be detected with their modifiers, such as KEY_CTRL_LEFT is not matched by any Keycode constant, but rather a combination of existing KEY_LEFT with the CTRL modifier.

For Legacy API of classic curses applications, code may be be compared with attributes of Terminal, which are duplicated from those found in curses(3), or those constants in curses beginning with phrase KEY_. These have numeric values that can be used for all basic application keys.

Async Input

The async_inkey() method is an asyncio-compatible version of inkey(). It yields control to the event loop while waiting for input, making it suitable for use with async/await.

import asyncio
from blessed import Terminal

async def main():
    term = Terminal()
    with term.cbreak():
        key = await term.async_inkey(timeout=5.0)
        if key:
            print(f"You pressed: {key!r}")
        else:
            print("Timed out")

asyncio.run(main())

The method accepts the same timeout and esc_delay parameters as inkey(). It must be called within a cbreak() or raw() context.

For a complete example using async_inkey with the Line Editor, see Line Editor.