Input: keys, mouse & actions
lib/input/tui_input.sh - key/mouse binding tables, dispatch, defaults, pass-through, and the built-in actions bindable from tui.bind, <bind action="…">, <button action="…"> or tui.cmd.add. Guide: ../guide/input-bindings.md. ← API index for the full module list and a task-oriented tour with examples.
Every key and mouse event is decoded into a name (ctrl+s, pgdn, wheel:up, mouse:right, paste) and looked up in three tables: user bindings (--user, saved per app), code bindings (your app and markup), and the defaults from share/defaults/keybinds.xml, grouped so whole groups can be switched off. Handlers read the event from the TUI_EVENT_* variables (Core). Functions return 0 unless their entry says otherwise.
Input and bindings
| Function | Summary |
|---|---|
tui.bind |
Binds a key or mouse event to a command. |
tui.unbind |
Removes a code binding, or with --user a user binding. The default for KEY applies again. |
tui.bind.reset |
Removes every code binding, or with --user every user binding. Defaults are not affected. |
tui.bind.list |
Prints every binding: user, then code, then defaults. |
tui.bind.table |
Builds the same rows as tui.bind.list as an aligned, framed text table in the variable _TBL. |
tui.bind.defaults |
Reloads the default bindings, replacing the current defaults. |
tui.defaults.off |
Switches groups of default bindings off. |
tui.defaults.on |
Switches default groups back on, both the app-wide and the page-only setting. |
tui.defaults.list |
Prints each default group, sorted, as GROUP<TAB>on\|off<TAB>KEYS. |
tui.bind
tui.bind KEY COMMAND [--pane ID] [--pass] [--always] [--page] [--user] [--desc TEXT]
Binds a key or mouse event to a command.
Parameters
KEY: a key name such asa,Q,ctrl+s,alt+enter,shift+tab,f5,pgdn, or a mouse name such asmouse:right,wheel:down,drag:left. Names are case-insensitive except single letters (Qisshift+q).COMMAND: a function name with optional arguments, e.g."tui.action.scroll down 10". Several commands can be chained with;.
Options
--pane ID: only whenIDis the event’s pane: the focused widget’s pane for keys, the pane under the pointer for mouse events.--pass: after this command, keep going down the lookup order, so the default still runs too.--always: also fire while a text widget has focus and would otherwise take the key.--page: removed on the next page change.<bind>in markup uses this.--user: a binding made by the person using the app. It beats code bindings and is saved withtui.bind.save.--desc TEXT: description shown in binding lists and the Keybinds page.
Returns: 1 when KEY or COMMAND is missing.
Notes
- Lookup order per event: pane-scoped user, pane-scoped code, global user, global code, then the built-in default. The first match stops the search unless it was bound with
--pass. COMMANDis split on;and spaces, not evaluated: arguments can’t contain spaces or quotes. Wrap anything more complex in a function.- A command that is not defined when the key is pressed is skipped; the reason is left in
TUI_LAST_BIND_ERROR. - Binding the same
KEY(and pane) again replaces the command and its flags. - Unknown flags are ignored.
- Bindings made while a plugin loads are removed when that plugin is disabled.
Example
tui.bind ctrl+e on_export --desc "Export"
tui.bind mouse:right on_ctx --pane output
tui.bind ctrl+s on_save --always
tui.bind q "log_quit; tui.action.quit"
See also: tui.unbind, tui.defaults.off, ../guide/input-bindings.md
tui.unbind
tui.unbind KEY [--pane ID] [--user]
Removes a code binding, or with --user a user binding. The default for KEY applies again.
Notes
--panemust match the scope the binding was made with.- Default bindings can’t be unbound one by one; switch their group off with
tui.defaults.offor bind the key to something else.
tui.bind.reset
tui.bind.reset [--user]
Removes every code binding, or with --user every user binding. Defaults are not affected.
tui.bind.list
tui.bind.list
Prints every binding: user, then code, then defaults.
Output: one line per binding, SCOPE<TAB>KEY<TAB>COMMAND<TAB>NOTE. SCOPE is global, pane:ID or default. NOTE holds the description and markers such as (yours), (unsaved), (pass), (page), (overridden), (off).
tui.bind.table
tui.bind.table
Builds the same rows as tui.bind.list as an aligned, framed text table in the variable _TBL.
Notes
- Fork-free; show it with
tui.output PANE "$_TBL".
tui.bind.defaults
tui.bind.defaults [FILE]
Reloads the default bindings, replacing the current defaults.
Parameters
FILE: default$TUI_DEFAULTS_DIR/keybinds.xml:~/.config/DABT/defaults/keybinds.xmlwhen installed, elseshare/defaults/keybinds.xml.
Returns: 1 when FILE can’t be read; the app then has no defaults.
Notes
- One
<bind key="…" action="…" group="…" [desc="…"] [always="true"]/>per line. Bindings withoutgroupgo intomisc.
tui.defaults.off
tui.defaults.off GROUP... [--page]
Switches groups of default bindings off.
Parameters
GROUP:click,focus,help,pages,palette,pane,paste,quit,scroll,wheel(seetui.defaults.list).--page: only until the page changes.<tui defaults="-quit,-scroll">does this.
Notes
- Without
--pageit lasts for the run. To persist it, set thedefaults.offconfig key.
Example
tui.defaults.off quit # this app handles q itself
tui.defaults.on
tui.defaults.on GROUP...
Switches default groups back on, both the app-wide and the page-only setting.
tui.defaults.list
tui.defaults.list
Prints each default group, sorted, as GROUP<TAB>on|off<TAB>KEYS.
Saved user bindings
| Function | Summary |
|---|---|
tui.bind.save |
Writes the user bindings (--user) to disk; they load automatically on the next start. |
tui.bind.load |
Replaces the user bindings with those in FILE (default: the saved file) and marks them saved. |
tui.bind.discard |
Drops unsaved changes to the user bindings by reloading the saved file. |
tui.bind.dirty |
Returns 0 while the user bindings differ from the saved file, else 1. |
tui.bind.saved_file |
Prints the path of the saved user bindings (TUI_USER_KEYBINDS). |
tui.bind.save
tui.bind.save [FILE]
Writes the user bindings (--user) to disk; they load automatically on the next start.
Parameters
FILE: defaulttui.bind.saved_file(~/.config/DABT/apps/<app>/keybinds.xml).
Returns: 1 and a message on stderr when the file can’t be written.
Notes
- With no user bindings the file is deleted.
- Saving to another
FILEdoes not change which file loads at start.
tui.bind.load
tui.bind.load [FILE]
Replaces the user bindings with those in FILE (default: the saved file) and marks them saved.
Notes
- Runs automatically when the library is sourced.
- Commands that are not defined yet are kept and skipped when pressed.
tui.bind.discard
tui.bind.discard
Drops unsaved changes to the user bindings by reloading the saved file.
tui.bind.dirty
tui.bind.dirty
Returns 0 while the user bindings differ from the saved file, else 1.
tui.bind.saved_file
tui.bind.saved_file
Prints the path of the saved user bindings (TUI_USER_KEYBINDS).
Kill switch, terminal mode, clipboard
| Function | Summary |
|---|---|
tui.keys.suspend |
Kill switch: turns every keyboard binding off, user and default, and shows a warning box. Default: toggle. |
tui.keys.suspend_key |
Changes the chord that toggles the keyboard kill switch. Default: ctrl+alt+k. |
tui.keys.suspended |
Returns 0 while the keyboard kill switch is on. |
tui.passthrough |
Terminal mode: hands mouse and keyboard back to the terminal so its native selection, copy, link clicking and scrolling work. Default: toggle. |
tui.passthrough.key |
Changes the chord that toggles terminal mode. Default: ctrl+alt+p. |
tui.passthrough.active |
Returns 0 while terminal mode is on. |
tui.clipboard.copy |
Copies TEXT to the system clipboard through the terminal (OSC 52). |
tui.clipboard.paste |
Prints the text of the last bracketed paste (no trailing newline). |
tui.keys.suspend
tui.keys.suspend [on|off|toggle]
Kill switch: turns every keyboard binding off, user and default, and shows a warning box. Default: toggle.
Notes
- Mouse input keeps working. A focused text input still takes typing and Enter.
- The toggle chord (
ctrl+alt+kby default) always works; change it withtui.keys.suspend_key. - Survives page changes.
tui.keys.suspend_key
tui.keys.suspend_key KEY
Changes the chord that toggles the keyboard kill switch. Default: ctrl+alt+k.
tui.keys.suspended
tui.keys.suspended
Returns 0 while the keyboard kill switch is on.
tui.passthrough
tui.passthrough [on|off|toggle]
Terminal mode: hands mouse and keyboard back to the terminal so its native selection, copy, link clicking and scrolling work. Default: toggle.
Notes
- The screen is frozen while on: no timers, repaints or resize layouts. Background jobs keep running and their output appears when you leave.
- Every key except the toggle chord (
ctrl+alt+pby default) is ignored. - Independent of the keyboard kill switch.
See also: tui.passthrough.key
tui.passthrough.key
tui.passthrough.key KEY
Changes the chord that toggles terminal mode. Default: ctrl+alt+p.
tui.passthrough.active
tui.passthrough.active
Returns 0 while terminal mode is on.
tui.clipboard.copy
tui.clipboard.copy TEXT
Copies TEXT to the system clipboard through the terminal (OSC 52).
Notes
- Works in kitty, foot, WezTerm, Alacritty, iTerm2 and tmux (with
set-clipboard on). GNOME Terminal and other VTE terminals ignore it silently. - Some terminals cap the size of an OSC 52 payload.
tui.clipboard.paste
tui.clipboard.paste
Prints the text of the last bracketed paste (no trailing newline).
Notes
- There is no way to read the system clipboard from a terminal; this is only what the user pasted into the app.
Built-in actions
Use as COMMAND in tui.bind, <bind action="…">, <button action="…"> or tui.cmd.add. All are bound by default and rebindable. More actions live with their modules: tui.action.text_keys, tui.action.update, tui.palette.open.
| Function | Summary |
|---|---|
tui.action.quit |
Quits the app. Asks for confirmation first when the confirm.quit config key is 1. |
tui.action.quit_now |
Quits the app without asking, regardless of confirm.quit. |
tui.action.focus_next |
Moves focus to the next focusable widget in creation order, wrapping around (tab). |
tui.action.focus_prev |
Moves focus to the previous focusable widget (shift+tab). |
tui.action.focus_dir |
Moves focus to the widget you would expect in that direction on screen. |
tui.action.unfocus |
Removes focus from the focused widget (esc). |
tui.action.activate |
Acts on the focused widget as Enter does: presses a button, toggles a checkbox, submits a text widget, opens a select, or runs a list/table action. |
tui.action.click |
Handles a left press or drag: jumps a scrollbar, else acts on the widget under the pointer, else removes focus. |
tui.action.scroll |
Scrolls the target pane by N lines (up/down, default 3) or columns (left/right, default 5). |
tui.action.page |
Scrolls the target pane by one screen (its height minus 3 rows). |
tui.action.scroll_top |
Scrolls the target pane to the top left. |
tui.action.scroll_bottom |
Scrolls the target pane to the end. |
tui.action.pane_next |
Moves keyboard focus to the next pane worth visiting: scrollable panes and panes with two or more widgets. |
tui.action.pane_prev |
Moves keyboard focus to the previous such pane. |
tui.action.pane_dir |
Moves keyboard focus to the nearest such pane in that direction. |
tui.action.focus_pane |
Moves keyboard focus into PANE: to the widget that last had focus there, else its first widget, else the pane itself becomes the scroll target. |
tui.action.scroll_or_pane |
Scrolls the target pane when it can scroll that way, else moves to the neighbouring pane (alt+arrows). |
tui.action.paste |
Inserts the pasted text (TUI_EVENT_PASTE) into the focused text widget, replacing the selection. |
tui.action.goto |
Opens a page, like tui.goto. Does nothing without an argument. |
tui.action.goto_default |
Opens a page shipped with DABT ($TUI_DEFAULTS_DIR/pages/NAME.xml). Also reachable from the palette. |
tui.action.back |
Returns to the previous page. Does nothing when there is no history. |
tui.action.reload_page |
Reloads the current page. Its on_visit runs again. |
tui.action.redraw |
Recomputes the layout and repaints everything, like tui.relayout. |
tui.action.quit
tui.action.quit
Quits the app. Asks for confirmation first when the confirm.quit config key is 1.
Notes
tui.action.quit_nowquits without asking.
tui.action.quit_now
tui.action.quit_now
Quits the app without asking, regardless of confirm.quit.
tui.action.focus_next
tui.action.focus_next
Moves focus to the next focusable widget in creation order, wrapping around (tab).
tui.action.focus_prev
tui.action.focus_prev
Moves focus to the previous focusable widget (shift+tab).
tui.action.focus_dir
tui.action.focus_dir up|down|left|right
Moves focus to the widget you would expect in that direction on screen.
Notes
- Left/right only consider widgets on the same screen row; up/down only widgets whose columns overlap the current one. When nothing is there, focus stays.
- With nothing focused,
down/rightfocus the first widget andup/leftthe last.
tui.action.unfocus
tui.action.unfocus
Removes focus from the focused widget (esc).
tui.action.activate
tui.action.activate
Acts on the focused widget as Enter does: presses a button, toggles a checkbox, submits a text widget, opens a select, or runs a list/table action.
tui.action.click
tui.action.click
Handles a left press or drag: jumps a scrollbar, else acts on the widget under the pointer, else removes focus.
Notes
- Clicking a scrollable pane also makes it the keyboard pane. A sticky input keeps focus.
tui.action.scroll
tui.action.scroll up|down|left|right [N]
Scrolls the target pane by N lines (up/down, default 3) or columns (left/right, default 5).
Notes
- Target: for mouse events the pane under the pointer; for keys the keyboard pane, else the pane under the pointer, else the focused widget’s pane, else the first scrollable pane.
- The wheel over a textarea, list or table scrolls that widget instead.
- Merged repeats (
TUI_EVENT_COUNT) multiply the distance.
tui.action.page
tui.action.page up|down
Scrolls the target pane by one screen (its height minus 3 rows).
tui.action.scroll_top
tui.action.scroll_top
Scrolls the target pane to the top left.
tui.action.scroll_bottom
tui.action.scroll_bottom
Scrolls the target pane to the end.
tui.action.pane_next
tui.action.pane_next
Moves keyboard focus to the next pane worth visiting: scrollable panes and panes with two or more widgets.
tui.action.pane_prev
tui.action.pane_prev
Moves keyboard focus to the previous such pane.
tui.action.pane_dir
tui.action.pane_dir up|down|left|right
Moves keyboard focus to the nearest such pane in that direction.
tui.action.focus_pane
tui.action.focus_pane PANE
Moves keyboard focus into PANE: to the widget that last had focus there, else its first widget, else the pane itself becomes the scroll target.
Returns: 1 for an unknown pane.
tui.action.scroll_or_pane
tui.action.scroll_or_pane up|down|left|right
Scrolls the target pane when it can scroll that way, else moves to the neighbouring pane (alt+arrows).
tui.action.paste
tui.action.paste
Inserts the pasted text (TUI_EVENT_PASTE) into the focused text widget, replacing the selection.
Notes
- Single-line widgets turn newlines into spaces.
tui.action.goto
tui.action.goto PAGE_FILE
Opens a page, like tui.goto. Does nothing without an argument.
tui.action.goto_default
tui.action.goto_default settings|keybinds|plugins
Opens a page shipped with DABT ($TUI_DEFAULTS_DIR/pages/NAME.xml). Also reachable from the palette.
tui.action.back
tui.action.back
Returns to the previous page. Does nothing when there is no history.
Notes
- History holds the last 30 pages; reloading the same page does not add to it.
tui.action.reload_page
tui.action.reload_page
Reloads the current page. Its on_visit runs again.
tui.action.redraw
tui.action.redraw
Recomputes the layout and repaints everything, like tui.relayout.
