Skip to content

register event handler

NSPC911 edited this page Jun 15, 2026 · 5 revisions

register_event_handler

This lets you register custom events that run when specific patterns are detected in the raw stdin data.

registering the event handler

from textual_drivers import DrivenApp

class MyApp(DrivenApp):
    def on_mount(self) -> None:
        self._driver.register_event_handler(
            pattern,               # see pattern types below
            event_constructor,     # you can pass in the direct type itself
            priority=              # whether to prevent Textual's parser from handling this further
        )

Pattern types

Pattern Match behaviour
str Glob matched against each ESC-tokenised chunk via fnmatch.fnmatch
BoundedPattern(start, end) Finds all non-overlapping substrings in the raw data that begin with start and end with end
re.Pattern Finds all matches of pattern.finditer(data) in the raw data

Glob example

Detect the terminal's response to a Primary Device Attributes query (\x1b[c), which arrives as \x1b[?<params>c:

from textual.app import ComposeResult
from textual.message import Message
from textual.widgets import Label
from textual_drivers import DrivenApp

class DeviceAttributesReceived(Message):
    def __init__(self, data: str) -> None:
        super().__init__()
        self.data = data

class MyApp(DrivenApp):
    def compose(self) -> ComposeResult:
        yield Label("Waiting for terminal response…")

    def on_mount(self) -> None:
        self.app._driver.register_event_handler("\x1b[?*c", DeviceAttributesReceived)
        self.app._driver.write("\x1b[c")
        self.app._driver.flush()

    def on_device_attributes_received(self, event: DeviceAttributesReceived) -> None:
        self.query_one(Label).update(f"Terminal identified: {event.data!r}")

BoundedPattern example

Detect the terminal's response to a Primary Device Attributes query, by matching the fixed start and end sentinels:

from textual_drivers import BoundedPattern

driver.register_event_handler(
    BoundedPattern(start="\x1b[?1;2", end="c"),
    DeviceAttributesReceived,
    priority=True,
)

BoundedPattern helps if you have sequences that have a fixed start and end content, and do not care about the middle.

re.Pattern example

Detect the terminal's response to a Primary Device Attributes query with a regex that captures the parameters:

import re

driver.register_event_handler(
    re.compile(r"\x1b\[\?([0-9;]+)c"),
    CursorPositionMsg,
    priority=True,
)

Callable fallback

The event_constructor can also be a plain callable that receives the matched string and returns anything:

def _debug(data: str) -> None:
    print(f"raw: {data!r}", flush=True)

driver.register_event_handler(BoundedPattern(start="\x1b]72;", end=_ST), _debug)

If a Event is returned from the function/method, it is posted to the app as usual.

raw_data_signal

driver.raw_data_signal is a Signal[str] that fires once for every raw stdin read chunk, before any pattern matching or filtering. It is the lowest-level observation point available — the string is exactly what came off the file descriptor, decoded from UTF-8 but otherwise unprocessed.

Subscribe in on_mount using Textual's signal API:

def on_mount(self) -> None:
    self.app._driver.raw_data_signal.subscribe(self, self._on_raw_stdin)

def _on_raw_stdin(self, data: str) -> None:
    self.query_one("#log", Log).write_line(f"raw: {data!r}")

Clone this wiki locally