Behaviour for key input handlers in the focus stack.
Each handler module decides whether to consume a key press or pass it
through to the next handler in the stack. Handlers self-gate: they
return {:passthrough, state} when their feature is inactive (e.g.,
the picker handler passes through when no picker is open).
State contract
Input handlers receive a handler_state() which is currently
MingaEditor.State.t(). This type alias is the narrowing point: as the
shell independence refactor progresses, it will be replaced by a
focused contract struct containing only what handlers need (workspace,
capabilities, layout, shell_state). Handlers should avoid accessing
fields outside these four to prepare for that narrowing.
Implementing a handler
defmodule MyHandler do
@behaviour MingaEditor.Input.Handler
@impl true
def handle_key(state, _codepoint, _modifiers) do
if my_feature_active?(state) do
{:handled, do_something(state)}
else
{:passthrough, state}
end
end
end
Summary
Types
@type handler_state() :: MingaEditor.State.t()
The state type passed to input handlers.
Currently MingaEditor.State.t(). This alias is the single point to narrow
when the input contract is fully decoupled from MingaEditor.State. Handlers
should access only: workspace, capabilities, layout, shell_state.
@type result() :: {:handled, handler_state()} | {:passthrough, handler_state()}
Result of handling a key press.
Callbacks
@callback handle_key( handler_state(), codepoint :: non_neg_integer(), modifiers :: non_neg_integer() ) :: result()
Processes a key press event.
Returns {:handled, state} if this handler consumed the key, or
{:passthrough, state} if the key should be forwarded to the next
handler in the stack. The handler may modify state even when passing
through (e.g., clearing a transient flag).
@callback handle_mouse( handler_state(), row :: integer(), col :: integer(), button :: atom(), modifiers :: non_neg_integer(), event_type :: atom(), click_count :: pos_integer() ) :: result()
Processes a mouse event.
Returns {:handled, state} if this handler consumed the mouse event,
or {:passthrough, state} to forward it to the next handler.
The default implementation passes through all mouse events. Override this callback to intercept mouse events for your UI region.