key_dispatch.md

  1# Key Dispatch
  2
  3GPUI is designed for keyboard-first interactivity.
  4
  5To expose functionality to the mouse, you render a button with a click handler.
  6
  7To expose functionality to the keyboard, you bind an _action_ in a _key context_.
  8
  9Actions are similar to framework-level events like `MouseDown`, `KeyDown`, etc, but you can define them yourself:
 10
 11```rust
 12mod menu {
 13    #[gpui::action]
 14    struct MoveUp;
 15
 16    #[gpui::action]
 17    struct MoveDown;
 18}
 19```
 20
 21Actions are frequently unit structs, for which we have a macro. The above could also be written:
 22
 23```rust
 24mod menu {
 25    actions!(gpui, [MoveUp, MoveDown]);
 26}
 27```
 28
 29Actions can also be more complex types:
 30
 31```rust
 32mod menu {
 33    #[gpui::action]
 34    struct Move {
 35        direction: Direction,
 36        select: bool,
 37    }
 38}
 39```
 40
 41To bind actions, chain `on_action` on to your element:
 42
 43```rust
 44impl Render for Menu {
 45    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 46        div()
 47            .on_action(|this: &mut Menu, move: &MoveUp, window: &mut Window, cx: &mut Context<Menu>| {
 48                // ...
 49            })
 50            .on_action(|this, move: &MoveDown, cx| {
 51                // ...
 52            })
 53            .children(unimplemented!())
 54    }
 55}
 56```
 57
 58In order to bind keys to actions, you need to declare a _key context_ for part of the element tree by calling `key_context`.
 59
 60```rust
 61impl Render for Menu {
 62    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 63        div()
 64            .key_context("menu")
 65            .on_action(|this: &mut Menu, move: &MoveUp, window: &mut Window, cx: &mut Context<Menu>| {
 66                // ...
 67            })
 68            .on_action(|this, move: &MoveDown, cx| {
 69                // ...
 70            })
 71            .children(unimplemented!())
 72    }
 73}
 74```
 75
 76Now you can target your context in the keymap. Note how actions are identified in the keymap by their fully-qualified type name.
 77
 78```json
 79{
 80  "context": "menu",
 81  "bindings": {
 82    "up": "menu::MoveUp",
 83    "down": "menu::MoveDown"
 84  }
 85}
 86```
 87
 88If you had opted for the more complex type definition, you'd provide the serialized representation of the action alongside the name:
 89
 90```json
 91{
 92  "context": "menu",
 93  "bindings": {
 94    "up": ["menu::Move", {direction: "up", select: false}]
 95    "down": ["menu::Move", {direction: "down", select: false}]
 96    "shift-up": ["menu::Move", {direction: "up", select: true}]
 97    "shift-down": ["menu::Move", {direction: "down", select: true}]
 98  }
 99}
100```