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
Terminal – prompt-toolkit emits
wijjit.terminal.mouse.MouseEventobjects containingx,y,button,type(awijjit.terminal.mouse.MouseEventType:PRESS,RELEASE,DRAG,MOVE,SCROLL,CLICK,DOUBLE_CLICK), modifier flags (shift/alt/ctrl), andclick_count.MouseEventRouter – checks overlays first, then performs hit testing against the base layout to find the element occupying
(x, y).HoverManager – updates hover state when the pointer moves across elements; hover changes mark the UI as dirty so highlights/tooltips refresh.
Element handlers – if the target element implements
handle_mouseit 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_CLICKevent (withevent.click_count == 2). Great for list selection shortcuts.Scroll – wheel events map to
MouseEventType.SCROLL; the direction is carried byevent.button(MouseButton.SCROLL_UPorMouseButton.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/RELEASEsequences 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.exedoes 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.debugcall inside a customhandle_mouseimplementation and inspect the event’sx,y,button, andtype.To confirm which element sits under a given point, drive the app with the headless harness (
wijjit.testing.WijjitHarness) andclick(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_towhenself.hoveredtoggles.
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.