brick-2.9: A declarative terminal user interface library

Safe Haskell | None
Language | Haskell2010

Brick.Keybindings.KeyDispatcher

Contents

- Key dispatching
- Building handlers
- Handlers and triggers
- Misc

Description

This is the entry point into the keybinding infrastructure in this library. Note that usage of this API is not required to create working Brick applications; this API is provided for applications that need to support custom keybindings that are less tightly coupled to application behavior.

The workflow for this API is as follows:

- Create a data type `k` with a constructor for each abstract application event that you want to trigger with an input key.
- To each event `k`, assign a unique user-readable name (such as a name you could imagine using in a configuration file to refer to the event) and a list of default key bindings.
- Use the resulting data to create a `KeyConfig` with `newKeyConfig`. If desired, provide custom keybindings to `newKeyConfig` from within the program or load them from an INI file with routines like `keybindingsFromFile`.
- Optionally check for configuration-wide keybinding collisions with `keyEventMappings`.
- Implement application event handlers that will be run in response to either specific hard-coded keys or events `k`, both in some monad `m` of your choosing, using constructors `onKey` and `onEvent`.
- Use the created `KeyConfig` and handlers to create a `KeyDispatcher` with `keyDispatcher`, dealing with collisions if they arise.
- As user input events arrive, dispatch them to the appropriate handler in the dispatcher using `handleKey`.

Synopsis

- data KeyDispatcher k (m :: Type -> Type)
- keyDispatcher :: forall k (m :: Type -> Type). Ord k => KeyConfig k -> [KeyEventHandler k m] -> Either [(Binding, [KeyHandler k m])] (KeyDispatcher k m)
- handleKey :: Monad m => KeyDispatcher k m -> Key -> [Modifier] -> m Bool
- onEvent :: k -> Text -> m () -> KeyEventHandler k m
- onKey :: ToBinding a => a -> Text -> m () -> KeyEventHandler k m
- data Handler (m :: Type -> Type) = Handler {
  - handlerDescription :: Text
  - handlerAction :: m ()
  }
- data KeyHandler k (m :: Type -> Type) = KeyHandler {
  - khHandler :: KeyEventHandler k m
  - khBinding :: Binding
  }
- data KeyEventHandler k (m :: Type -> Type) = KeyEventHandler {
  - kehHandler :: Handler m
  - kehEventTrigger :: EventTrigger k
  }
- data EventTrigger k
  - = ByKey Binding
  - | ByEvent k
- keyDispatcherToList :: forall k (m :: Type -> Type). KeyDispatcher k m -> [(Binding, KeyHandler k m)]
- lookupVtyEvent :: forall k (m :: Type -> Type). Key -> [Modifier] -> KeyDispatcher k m -> Maybe (KeyHandler k m)

# Key dispatching

data KeyDispatcher k (m :: Type -> Type) Source #

A dispatcher keys that map to abstract events `k` and whose handlers run in the monad `m`.

keyDispatcher :: forall k (m :: Type -> Type). Ord k => KeyConfig k -> [KeyEventHandler k m] -> Either [(Binding, [KeyHandler k m])] (KeyDispatcher k m) Source #

Build a `KeyDispatcher` to dispatch keys to handle events of type `k` using actions in a Monad `m`. If any collisions are detected, this fails with `Left` and returns the list of colliding event handlers for each overloaded binding. (Each returned `KeyHandler` contains the original `KeyEventHandler` that was used to build it so those can be inspected to understand which handlers are mapped to the same key, either via an abstract key event using `onEvent` or via a statically configured key using `onKey`.)

This works by taking a list of abstract `KeyEventHandler`s and building a `KeyDispatcher` of event handlers based on specific Vty keys using the provided `KeyConfig` to map between abstract key events of type `k` and Vty keys. Event handlers triggered by an event `k` are set up to be triggered by either the customized bindings for `k` in the `KeyConfig`, no bindings at all if the `KeyConfig` has marked `k` as `Unbound`, or the default bindings for `k` otherwise.

Once you have a `KeyDispatcher`, you can dispatch an input key event to it and invoke the corresponding handler (if any) with `handleKey`.

handleKey Source #

Arguments

:: Monad m |
=> KeyDispatcher k m | The dispatcher to use.
-> Key | The key to handle.
-> [Modifier] | The modifiers for the key, if any.
-> m Bool |

Handle a keyboard event by looking it up in the `KeyDispatcher` and invoking the matching binding's handler if one is found. Return `True` if the a matching handler was found and run; return `False` if no matching binding was found.

# Building handlers

onEvent Source #

Arguments

:: k | The key event whose bindings should trigger this handler.
-> Text | The description of the handler.
-> m () | The handler to invoke.
-> KeyEventHandler k m |

Specify a handler for the specified key event.

onKey Source #

Arguments

:: ToBinding a |
=> a | The binding that should trigger this handler.
-> Text | The description of the handler.
-> m () | The handler to invoke.
-> KeyEventHandler k m |

Specify a handler for the specified key.

# Handlers and triggers

data Handler (m :: Type -> Type) Source #

A `Handler` represents a handler implementation to be invoked in response to some event that runs in the monad `m`.

In general, you should never need to make one of these manually. Instead, use `onEvent` and `onKey`. This type's internals are exposed for easy inspection, not construction.

Constructors

Handler |

Fields

- handlerDescription :: Text

  The description of this handler's behavior.

- handlerAction :: m ()

  The action to take when this handler is invoked.

data KeyHandler k (m :: Type -> Type) Source #

A handler for a specific key.

In general, you should never need to create one of these manually. The internals are exposed to make inspection easy.

Constructors

KeyHandler |

Fields

- khHandler :: KeyEventHandler k m

  The handler to invoke. Note that this maintains the original abstract key event handler; this allows us to obtain the original `EventTrigger` for the `KeyEventHandler` upon which this `KeyHandler` is built. This can be important for keybinding consistency checks or collision checks as well as help text generation.

- khBinding :: Binding

  The specific key binding that should trigger this handler.

data KeyEventHandler k (m :: Type -> Type) Source #

A handler for an abstract key event.

In general, you should never need to create these manually. Instead, use `onEvent` and `onKey`. The internals of this type are exposed to allow inspection of handler data for e.g. custom help generation.

Constructors

KeyEventHandler |

Fields

- kehHandler :: Handler m

  The handler to invoke.

- kehEventTrigger :: EventTrigger k

  The trigger for the handler.

data EventTrigger k Source #

A trigger for an event handler.

Constructors

ByKey Binding | The key event is always triggered by a specific key.
ByEvent k | The trigger is an abstract key event.

#### Instances

Instances details

Show k => Show (EventTrigger k) Source # |
Instance details Defined in Brick.Keybindings.KeyDispatcher Methods showsPrec :: Int -> EventTrigger k -> ShowS Source # show :: EventTrigger k -> String Source # showList :: [EventTrigger k] -> ShowS Source #
Eq k => Eq (EventTrigger k) Source # |
Instance details Defined in Brick.Keybindings.KeyDispatcher Methods (==) :: EventTrigger k -> EventTrigger k -> Bool Source # (/=) :: EventTrigger k -> EventTrigger k -> Bool Source #
Ord k => Ord (EventTrigger k) Source # |

Instance details

Defined in Brick.Keybindings.KeyDispatcher

Methods

compare :: EventTrigger k -> EventTrigger k -> Ordering Source #

(<) :: EventTrigger k -> EventTrigger k -> Bool Source #

(<=) :: EventTrigger k -> EventTrigger k -> Bool Source #

(>) :: EventTrigger k -> EventTrigger k -> Bool Source #

(>=) :: EventTrigger k -> EventTrigger k -> Bool Source #

max :: EventTrigger k -> EventTrigger k -> EventTrigger k Source #

min :: EventTrigger k -> EventTrigger k -> EventTrigger k Source #

# Misc

keyDispatcherToList :: forall k (m :: Type -> Type). KeyDispatcher k m -> [(Binding, KeyHandler k m)] Source #

Convert a key dispatcher to a list of pairs of bindings and their handlers.

lookupVtyEvent :: forall k (m :: Type -> Type). Key -> [Modifier] -> KeyDispatcher k m -> Maybe (KeyHandler k m) Source #

Find the key handler that matches a Vty key event, if any. Modifier order is unimportant since the lookup for a matching binding ignores modifier order.

This works by looking up an event handler whose binding is the specified key and modifiers based on the `KeyConfig` that was used to build the `KeyDispatcher`.

Ordinarily you will not need to use this function; use `handleKey` instead. This is provided for more direct access to the `KeyDispatcher` internals.