Skip to main content

standard_plugin/
input.rs

1//! Keys, pastes and the pointer, as typed values. The WIT names keys by
2//! string and buttons by number (`wit/plugin.wit`, `event-types`); a
3//! plugin matches on these enums instead.
4
5use alloc::string::{String, ToString};
6
7/// Modifier keys held during a key or pointer event.
8#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
9pub struct Modifiers(pub u32);
10
11impl Modifiers {
12    pub const NONE: Self = Self(0);
13    pub const SHIFT: Self = Self(1);
14    pub const CTRL: Self = Self(2);
15    /// Alt, or Option on a Mac.
16    pub const ALT: Self = Self(4);
17    /// Super: Command on a Mac.
18    pub const SUPER: Self = Self(8);
19
20    pub const fn contains(self, other: Self) -> bool {
21        self.0 & other.0 == other.0 && other.0 != 0
22    }
23
24    pub const fn shift(self) -> bool {
25        self.contains(Self::SHIFT)
26    }
27
28    pub const fn ctrl(self) -> bool {
29        self.contains(Self::CTRL)
30    }
31
32    pub const fn alt(self) -> bool {
33        self.contains(Self::ALT)
34    }
35
36    pub const fn super_key(self) -> bool {
37        self.contains(Self::SUPER)
38    }
39
40    pub const fn is_empty(self) -> bool {
41        self.0 == 0
42    }
43}
44
45impl core::ops::BitOr for Modifiers {
46    type Output = Self;
47
48    fn bitor(self, other: Self) -> Self {
49        Self(self.0 | other.0)
50    }
51}
52
53/// Which key. A character key is the character it types; the named keys
54/// are the WIT's vocabulary. Escape never arrives: it closes the surface.
55#[derive(Clone, Debug, PartialEq, Eq, Hash)]
56pub enum KeyCode {
57    /// `a`, `A`, `1`, `?`, `é`: what the key typed, shift applied.
58    Char(char),
59    Enter,
60    Tab,
61    /// Shift+Tab, as terminals report it.
62    BackTab,
63    Backspace,
64    Delete,
65    Insert,
66    Space,
67    Left,
68    Right,
69    Up,
70    Down,
71    Home,
72    End,
73    PageUp,
74    PageDown,
75    /// `F(1)` to `F(12)`.
76    F(u8),
77    /// A name a newer viewer sends.
78    Other(String),
79}
80
81impl KeyCode {
82    /// Reads the WIT's `key.code`.
83    pub fn parse(code: &str) -> Self {
84        let mut chars = code.chars();
85        if let (Some(character), None) = (chars.next(), chars.next()) {
86            return Self::Char(character);
87        }
88        match code {
89            "enter" => Self::Enter,
90            "tab" => Self::Tab,
91            "backtab" => Self::BackTab,
92            "backspace" => Self::Backspace,
93            "delete" => Self::Delete,
94            "insert" => Self::Insert,
95            "space" => Self::Space,
96            "left" => Self::Left,
97            "right" => Self::Right,
98            "up" => Self::Up,
99            "down" => Self::Down,
100            "home" => Self::Home,
101            "end" => Self::End,
102            "pageup" => Self::PageUp,
103            "pagedown" => Self::PageDown,
104            other => match other.strip_prefix('f').and_then(|n| n.parse::<u8>().ok()) {
105                Some(n @ 1..=12) => Self::F(n),
106                _ => Self::Other(other.to_string()),
107            },
108        }
109    }
110
111    /// The WIT's name for this key.
112    pub fn name(&self) -> String {
113        match self {
114            Self::Char(character) => character.to_string(),
115            Self::Enter => "enter".into(),
116            Self::Tab => "tab".into(),
117            Self::BackTab => "backtab".into(),
118            Self::Backspace => "backspace".into(),
119            Self::Delete => "delete".into(),
120            Self::Insert => "insert".into(),
121            Self::Space => "space".into(),
122            Self::Left => "left".into(),
123            Self::Right => "right".into(),
124            Self::Up => "up".into(),
125            Self::Down => "down".into(),
126            Self::Home => "home".into(),
127            Self::End => "end".into(),
128            Self::PageUp => "pageup".into(),
129            Self::PageDown => "pagedown".into(),
130            Self::F(n) => alloc::format!("f{n}"),
131            Self::Other(name) => name.clone(),
132        }
133    }
134}
135
136#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
137pub enum KeyPhase {
138    #[default]
139    Press,
140    Repeat,
141    /// Only where the viewer's terminal reports releases.
142    Release,
143}
144
145/// A key on the surface with input focus.
146#[derive(Clone, Debug, PartialEq, Eq)]
147pub struct Key {
148    pub surface: String,
149    pub code: KeyCode,
150    /// The text the key types, when it types text.
151    pub text: Option<String>,
152    pub modifiers: Modifiers,
153    pub phase: KeyPhase,
154}
155
156impl Key {
157    /// A press of `code` with no modifiers (for tests).
158    pub fn press(surface: &str, code: KeyCode) -> Self {
159        let text = match &code {
160            KeyCode::Char(character) => Some(character.to_string()),
161            KeyCode::Space => Some(" ".into()),
162            _ => None,
163        };
164        Self {
165            surface: surface.into(),
166            code,
167            text,
168            modifiers: Modifiers::NONE,
169            phase: KeyPhase::Press,
170        }
171    }
172}
173
174#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
175pub enum PointerKind {
176    Down,
177    Up,
178    /// Motion with no button held.
179    Move,
180    /// Motion with a button held.
181    Drag,
182    /// One wheel step; the button says which way.
183    Wheel,
184    /// The pointer moved onto the surface, before its first `Move`: start
185    /// a hover.
186    Enter,
187    /// The pointer left the surface (or the surface was hidden under it):
188    /// end a hover. The position is the last one on the surface.
189    Leave,
190}
191
192#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
193pub enum Button {
194    None,
195    Left,
196    Middle,
197    Right,
198    WheelUp,
199    WheelDown,
200    WheelLeft,
201    WheelRight,
202    /// A number a newer viewer sends.
203    Other(u8),
204}
205
206impl Button {
207    pub fn from_wire(button: u8) -> Self {
208        match button {
209            0 => Self::None,
210            1 => Self::Left,
211            2 => Self::Middle,
212            3 => Self::Right,
213            4 => Self::WheelUp,
214            5 => Self::WheelDown,
215            6 => Self::WheelLeft,
216            7 => Self::WheelRight,
217            other => Self::Other(other),
218        }
219    }
220
221    pub fn wire(self) -> u8 {
222        match self {
223            Self::None => 0,
224            Self::Left => 1,
225            Self::Middle => 2,
226            Self::Right => 3,
227            Self::WheelUp => 4,
228            Self::WheelDown => 5,
229            Self::WheelLeft => 6,
230            Self::WheelRight => 7,
231            Self::Other(other) => other,
232        }
233    }
234}
235
236/// The pointer over one of the plugin's surfaces.
237#[derive(Clone, Debug, PartialEq, Eq)]
238pub struct Pointer {
239    pub surface: String,
240    /// The position in the surface's units: cells, or surface pixels.
241    pub x: u32,
242    pub y: u32,
243    /// The cell under the pointer.
244    pub col: u32,
245    pub row: u32,
246    pub button: Button,
247    pub kind: PointerKind,
248    pub modifiers: Modifiers,
249}