smudge_core/input.rs
1//! The platform-independent input events an application receives.
2//!
3//! [`App::handle_event`](crate::app::App::handle_event) takes these events
4//! between frames. The windowing layer translates the events of the operating
5//! system into them, and tests inject them directly, so widget and application
6//! code never sees a windowing library. Positions are logical pixels, with the
7//! origin at the top left of the window.
8
9use crate::geometry::Point;
10
11/// One input event, translated from the windowing system or injected by a
12/// test.
13#[derive(Clone, Debug, PartialEq)]
14pub enum InputEvent {
15 /// The pointer moved to a new position in logical pixels.
16 PointerMoved {
17 /// The position of the pointer in logical pixels.
18 position: Point,
19 },
20 /// The pointer left the window.
21 PointerLeft,
22 /// A pointer button was pressed.
23 PointerDown {
24 /// The position of the pointer in logical pixels.
25 position: Point,
26 /// The button that was pressed.
27 button: PointerButton,
28 },
29 /// A pointer button was released.
30 PointerUp {
31 /// The position of the pointer in logical pixels.
32 position: Point,
33 /// The button that was released.
34 button: PointerButton,
35 },
36 /// The mouse wheel or touchpad scrolled.
37 ///
38 /// The delta is in logical pixels, positive for scrolling right and down.
39 Wheel {
40 /// How far the content scrolls, in logical pixels.
41 delta: Point,
42 },
43 /// A keyboard key was pressed or released.
44 Key(KeyEvent),
45 /// The input method changed its composing text.
46 ///
47 /// `cursor` is the byte range of the cursor or selection inside `text`,
48 /// or `None` when no cursor is shown.
49 ImePreedit {
50 /// The composing text.
51 text: String,
52 /// The byte range of the cursor inside the composing text.
53 cursor: Option<(usize, usize)>,
54 },
55 /// The input method committed text, which the editor inserts.
56 ImeCommit {
57 /// The committed text.
58 text: String,
59 },
60 /// The window gained or lost the input focus of the operating system.
61 WindowFocus(
62 /// Whether the window is focused.
63 bool,
64 ),
65 /// The keyboard modifiers changed.
66 ///
67 /// Some platforms report a change only after the key event that caused
68 /// it, so the modifiers a key event carries can lag behind. This event
69 /// keeps the current state for whatever reads it next, such as a click.
70 ModifiersChanged(
71 /// The modifiers held now.
72 Modifiers,
73 ),
74}
75
76/// One of the pointer buttons an event can refer to.
77#[derive(Copy, Clone, Debug, PartialEq, Eq)]
78pub enum PointerButton {
79 /// The main button, the left button on a right-handed mouse.
80 Primary,
81 /// The context menu button, the right button on a right-handed mouse.
82 Secondary,
83 /// The middle button.
84 Middle,
85}
86
87/// A keyboard key that was pressed or released.
88#[derive(Clone, Debug, PartialEq, Eq)]
89pub struct KeyEvent {
90 /// Which key the event refers to.
91 pub key: Key,
92 /// Whether the key is being pressed, as opposed to released.
93 pub pressed: bool,
94 /// Whether this event repeats a key the user holds down.
95 pub repeat: bool,
96 /// The keyboard modifiers held when the event happened.
97 pub modifiers: Modifiers,
98 /// The text the keypress produces, when it produces any.
99 pub text: Option<String>,
100}
101
102/// A key on the keyboard, by meaning rather than by position.
103///
104/// A printable key arrives as [`Key::Character`]. Everything the platform
105/// reports that has no variant here arrives as [`Key::Other`].
106#[derive(Clone, Debug, PartialEq, Eq)]
107pub enum Key {
108 /// A character key, already affected by the keyboard layout, such as `a`
109 /// or `?`.
110 Character(String),
111 /// The Enter or Return key.
112 Enter,
113 /// The Tab key.
114 Tab,
115 /// The Escape key.
116 Escape,
117 /// The Backspace key.
118 Backspace,
119 /// The Delete key.
120 Delete,
121 /// The left arrow key.
122 ArrowLeft,
123 /// The right arrow key.
124 ArrowRight,
125 /// The up arrow key.
126 ArrowUp,
127 /// The down arrow key.
128 ArrowDown,
129 /// The Home key.
130 Home,
131 /// The End key.
132 End,
133 /// The Page Up key.
134 PageUp,
135 /// The Page Down key.
136 PageDown,
137 /// The space bar.
138 Space,
139 /// A key with no variant of its own.
140 Other,
141}
142
143/// Whether a key event was taken by a handler.
144///
145/// A key handler returns this to decide whether the event keeps bubbling to
146/// the ancestors of the node it reached.
147#[derive(Copy, Clone, Debug, PartialEq, Eq)]
148pub enum Handled {
149 /// A handler acted on the event, so it stops bubbling.
150 Yes,
151 /// The handler ignored the event, so it bubbles to the parent.
152 No,
153}
154
155/// The keyboard modifiers held during an input event.
156#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
157pub struct Modifiers {
158 /// Whether Shift is held.
159 pub shift: bool,
160 /// Whether Control is held.
161 pub control: bool,
162 /// Whether Alt is held.
163 pub alt: bool,
164 /// Whether the Meta key is held, the Command key on macOS and the Super
165 /// key elsewhere.
166 pub meta: bool,
167}
168
169impl Modifiers {
170 /// Returns whether the platform's command modifier is held.
171 ///
172 /// This is `meta` on macOS and `control` everywhere else, so a shortcut
173 /// reads the same on every platform.
174 ///
175 /// # Examples
176 ///
177 /// ```
178 /// use smudge_core::input::Modifiers;
179 ///
180 /// let modifiers = Modifiers {
181 /// control: true,
182 /// ..Modifiers::default()
183 /// };
184 /// #[cfg(not(target_os = "macos"))]
185 /// assert!(modifiers.command());
186 /// ```
187 pub fn command(&self) -> bool {
188 #[cfg(target_os = "macos")]
189 {
190 self.meta
191 }
192 #[cfg(not(target_os = "macos"))]
193 {
194 self.control
195 }
196 }
197}
198
199#[cfg(test)]
200#[path = "input_tests.rs"]
201mod tests;