1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! Input events, decoupled from crossterm.
//!
//! Components handle `tuika` events, not raw crossterm events, so the widget
//! layer stays testable without a terminal. The host ([`super::host`])
//! translates crossterm into these. This mirrors Codex's event-stream input
//! model: a small, explicit event enum flowing to focused components.
/// A translated input event.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Event {
/// A key press.
Key(Key),
/// A mouse action.
Mouse(Mouse),
/// Bracketed-paste payload.
Paste(String),
/// Terminal resized to the given cell dimensions.
Resize {
/// New width in cells.
width: u16,
/// New height in cells.
height: u16,
},
}
/// A key press with its modifier state.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Key {
/// The key that was pressed.
pub code: KeyCode,
/// Ctrl held during the press.
pub ctrl: bool,
/// Alt held during the press.
pub alt: bool,
/// Shift held during the press.
pub shift: bool,
}
impl Key {
/// A key with the given code and no modifiers held.
pub fn new(code: KeyCode) -> Self {
Self {
code,
ctrl: false,
alt: false,
shift: false,
}
}
/// True when neither Ctrl nor Alt is held (Shift is ignored, as it is
/// already folded into the character for text input).
pub fn plain(&self) -> bool {
!self.ctrl && !self.alt
}
}
/// A physical/logical key, independent of modifier state.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum KeyCode {
/// A printable character.
Char(char),
/// Enter/Return.
Enter,
/// Escape.
Esc,
/// Backspace (delete before cursor).
Backspace,
/// Delete (delete under/after cursor).
Delete,
/// Tab.
Tab,
/// Back-tab (Shift-Tab).
BackTab,
/// Up arrow.
Up,
/// Down arrow.
Down,
/// Left arrow.
Left,
/// Right arrow.
Right,
/// Home.
Home,
/// End.
End,
/// Page Up.
PageUp,
/// Page Down.
PageDown,
}
/// A mouse event at a terminal cell, with modifier state.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Mouse {
/// What the pointer did (button press/release/drag, move, or scroll).
pub kind: MouseKind,
/// Cell column (0-based, terminal coordinates).
pub column: u16,
/// Cell row (0-based, terminal coordinates).
pub row: u16,
/// Shift held during the event.
pub shift: bool,
/// Ctrl held during the event.
pub ctrl: bool,
/// Alt held during the event.
pub alt: bool,
}
impl Mouse {
/// A bare event at `(column, row)` with the given kind and no modifiers —
/// convenience for tests and synthetic events.
pub fn at(kind: MouseKind, column: u16, row: u16) -> Self {
Self {
kind,
column,
row,
shift: false,
ctrl: false,
alt: false,
}
}
/// True when no modifier keys are held. Terminals also use Shift-drag to
/// bypass application mouse capture for native selection, so a host that
/// implements its own selection should generally act only on `plain()`
/// left-drags and leave Shift-drags to the terminal.
pub fn plain(&self) -> bool {
!self.shift && !self.ctrl && !self.alt
}
}
/// Which mouse button an event refers to.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MouseButton {
/// Left (primary) button.
Left,
/// Right (secondary) button.
Right,
/// Middle button.
Middle,
}
/// The kind of mouse interaction an event represents.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MouseKind {
/// Button pressed.
Down(MouseButton),
/// Button released.
Up(MouseButton),
/// Pointer moved with a button held (a drag of that button).
Drag(MouseButton),
/// Pointer moved with no button held.
Moved,
/// Wheel scrolled up.
ScrollUp,
/// Wheel scrolled down.
ScrollDown,
/// Wheel scrolled left.
ScrollLeft,
/// Wheel scrolled right.
ScrollRight,
}
/// Whether a component consumed an event or let it bubble.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EventFlow {
/// The event was handled; stop propagating.
Consumed,
/// The event was not handled; keep bubbling.
Ignored,
}
impl EventFlow {
/// True for [`EventFlow::Consumed`].
pub fn consumed(self) -> bool {
matches!(self, EventFlow::Consumed)
}
}