Cursor Shapes

DECSCUSR (DEC Set Cursor Style) escape sequences allow changing the cursor shape between block, underline, and bar styles, with optional blinking.

The blessed library provides:

  • A CursorShape class with constants for each style

  • A cursor_shape() context manager for temporary changes

Available Shapes

Constant

Value

Description

DEFAULT

0

Reset to terminal default

BLINKING_BLOCK

1

Blinking block cursor

STEADY_BLOCK

2

Steady (non-blinking) block

BLINKING_UNDERLINE

3

Blinking underline cursor

STEADY_UNDERLINE

4

Steady underline cursor

BLINKING_BAR

5

Blinking bar (line) cursor

STEADY_BAR

6

Steady bar (line) cursor

Usage

Use the cursor_shape() context manager to temporarily change the cursor shape. The cursor is automatically restored to the terminal default on exit:

from blessed import Terminal

term = Terminal()

with term.cursor_shape(term.CursorShape.BLINKING_BAR):
    # cursor is a blinking bar
    val = term.inkey()

String names are also accepted:

with term.cursor_shape('steady_underline'):
    val = term.inkey()

Direct Sequences

You can also use sequence() to get the raw escape string for manual use:

import sys
from blessed.cursor_shape import CursorShape

sys.stdout.write(CursorShape.sequence(CursorShape.STEADY_BAR))
sys.stdout.flush()

# ... do work ...

sys.stdout.write(CursorShape.sequence(CursorShape.DEFAULT))
sys.stdout.flush()

Example

#!/usr/bin/env python3
"""Demonstrate DECSCUSR cursor shape changes with line editor input."""
from blessed import Terminal
from blessed.line_editor import LineEditor

term = Terminal()


def readline(col, width=40):
    """Read a line of input at current position."""
    ed = LineEditor(max_width=width, limit=200)
    while True:
        result = ed.feed_key(term.inkey())
        if result.line is not None or result.eof or result.interrupt:
            return result.line or ''
        if result.changed:
            ds = ed.display
            print(term.move_x(col) + term.clear_eol + ds.text
                  + term.move_x(col + ds.cursor), end='', flush=True)


print("Cursor shape demo -- type with each shape, press Enter to continue.\n")

with term.cbreak():
    for name, value in sorted(term.CursorShape.STYLES.items()):
        if name == 'default':
            continue
        label = f"  {name}: "
        print(label, end='', flush=True)
        with term.cursor_shape(value):
            readline(col=len(label))
        print()

print("\nCursor restored to terminal default.")