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```