Mouse Support

Mouse interaction is enabled by default. When app.run() starts, wijjit.terminal.input.InputHandler switches the terminal into raw mode and activates mouse tracking sequences. From there, wijjit.core.mouse_router.MouseEventRouter decides where each event goes.

Event pipeline

  1. Terminal – prompt-toolkit emits wijjit.terminal.mouse.MouseEvent objects containing x, y, button, type (a wijjit.terminal.mouse.MouseEventType: PRESS, RELEASE, DRAG, MOVE, SCROLL, CLICK, DOUBLE_CLICK), modifier flags (shift/alt/ctrl), and click_count.

  2. MouseEventRouter – checks overlays first, then performs hit testing against the base layout to find the element occupying (x, y).

  3. HoverManager – updates hover state when the pointer moves across elements; hover changes mark the UI as dirty so highlights/tooltips refresh.

  4. Element handlers – if the target element implements handle_mouse it receives the event. Otherwise built-in logic handles clicks for common widgets (buttons, list items, frames).

Supported gestures

  • Clicks – left, right, and middle buttons. Single clicks arrive as MouseEventType.CLICK. Right-click opens context menus if defined.

  • Double clicks – delivered as a distinct MouseEventType.DOUBLE_CLICK event (with event.click_count == 2). Great for list selection shortcuts.

  • Scroll – wheel events map to MouseEventType.SCROLL; the direction is carried by event.button (MouseButton.SCROLL_UP or MouseButton.SCROLL_DOWN). There is no scroll-amount field - each wheel notch is one event. Wijjit scrolls frames/log views automatically.

  • Drag – elements can listen for PRESS/DRAG/RELEASE sequences to implement sliders or lasso selection.

Writing mouse-aware elements

Implement async def handle_mouse(self, event: MouseEvent) -> bool on your element (the base method is a coroutine, so override it as async). Return True if you consumed the event. Inspect event.type (a wijjit.terminal.mouse.MouseEventType) to branch, and use event.button for the scroll direction. Example:

from wijjit.terminal.mouse import MouseEventType, MouseButton

async def handle_mouse(self, event):
    if event.type == MouseEventType.CLICK and self.bounds.contains(event.x, event.y):
        self.toggle()
        return True
    if event.type == MouseEventType.SCROLL:
        if event.button == MouseButton.SCROLL_UP:
            self.scroll_manager.scroll(-1)
        else:
            self.scroll_manager.scroll(1)
        return True
    return False

The MouseEvent dataclass exposes type, button, x, y, the shift / alt / ctrl modifier flags, and click_count.

Hover effects & tooltips

HoverManager tracks which element the pointer is over and exposes hooks to elements via element.hovered. Built-in widgets change styling automatically; custom elements can react during render_to:

if self.hovered:
    style = style.with_background("yellow")

To show a tooltip, call app.show_tooltip(element, x, y) with a small element (typically a Frame with content) positioned near the cursor; it opens on the LayerType.TOOLTIP overlay without trapping focus. Dismiss it with app.close_overlay(overlay) using the Overlay returned by show_tooltip.

Platform notes

  • Mouse tracking requires a terminal that supports SGR mouse sequences (most modern emulators). In tmux or screen, ensure mouse mode is enabled (set -g mouse on).

  • Windows Terminal and modern PowerShell consoles fully support mouse events; the legacy cmd.exe does not.

  • If you notice missing events, verify your SSH client forwards mouse sequences (Enable “Application mouse mode”).

Debugging

  • To see what events arrive, add a logger.debug call inside a custom handle_mouse implementation and inspect the event’s x, y, button, and type.

  • To confirm which element sits under a given point, drive the app with the headless harness (wijjit.testing.WijjitHarness) and click(x, y) there, then assert on what changed - the harness routes clicks through the same hit testing as a real terminal.

  • For hover-related performance issues, limit expensive work in render_to when self.hovered toggles.

Remember that keyboard accessibility should remain intact even when mouse interactions are rich. Pair mouse handlers with equivalent key handlers to keep your TUI inclusive.