1use terminput::{
2 Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers, MediaKeyCode,
3 ModifierDirection, ModifierKeyCode, MouseButton, MouseEvent, MouseEventKind, ScrollDirection,
4 UnsupportedEvent,
5};
6use web_sys::wasm_bindgen::JsValue;
7#[cfg(feature = "web_sys_0_3")]
8use web_sys_0_3 as web_sys;
9
10pub fn to_terminput_mouse(
12 mouse_event: web_sys::MouseEvent,
13) -> Result<MouseEvent, UnsupportedEvent> {
14 let event_kind = mouse_event.type_();
15 let mouse_button = to_terminput_mouse_button(mouse_event.button());
16 Ok(MouseEvent {
17 kind: to_terminput_mouse_kind(event_kind.as_str(), mouse_button)?,
18 modifiers: to_terminput_mouse_modifiers(&mouse_event),
19 column: mouse_event.client_x() as u16,
20 row: mouse_event.client_y() as u16,
21 })
22}
23
24pub fn to_terminput_mouse_drag(drag_event: web_sys::DragEvent) -> MouseEvent {
29 let mouse_button = to_terminput_mouse_button(drag_event.button());
30
31 MouseEvent {
32 kind: MouseEventKind::Drag(mouse_button),
33 modifiers: to_terminput_drag_modifiers(&drag_event),
34 column: drag_event.client_x() as u16,
35 row: drag_event.client_y() as u16,
36 }
37}
38
39pub fn to_terminput_mouse_scroll(event: web_sys::WheelEvent) -> MouseEvent {
41 let direction = to_terminput_scroll_direction(&event);
42 MouseEvent {
43 kind: MouseEventKind::Scroll(direction),
44 modifiers: KeyModifiers::empty(),
45 column: event.client_x() as u16,
46 row: event.client_y() as u16,
47 }
48}
49
50pub fn to_terminput_key(key_event: web_sys::KeyboardEvent) -> Result<KeyEvent, UnsupportedEvent> {
53 Ok(KeyEvent {
54 code: to_terminput_key_code(
55 &key_event.key(),
56 to_terminput_modifier_direction(key_event.location()),
57 )?,
58 modifiers: to_terminput_key_modifiers(&key_event),
59 state: key_state_to_terminput(&key_event),
60 kind: to_terminput_key_kind(&key_event),
61 })
62}
63
64pub fn to_terminput_paste(
67 clipboard_event: web_sys::ClipboardEvent,
68) -> Result<Event, UnsupportedEvent> {
69 if let Some(data) = clipboard_event.clipboard_data() {
70 let content = data
71 .get_data("text")
72 .map_err(|e| map_js_error("failed to read clipboard data: ", e))?;
73 Ok(Event::Paste(content))
74 } else {
75 Err(UnsupportedEvent("no clipboard data available".to_string()))
76 }
77}
78
79pub fn to_terminput_resize(window: &web_sys::Window) -> Result<Event, UnsupportedEvent> {
81 let height = window
82 .inner_height()
83 .map_err(|e| map_js_error("failed to read height: ", e))?;
84 let width = window
85 .inner_width()
86 .map_err(|e| map_js_error("failed to read width: ", e))?;
87 let height = height.as_f64().unwrap_or_default();
88 let width = width.as_f64().unwrap_or_default();
89 Ok(Event::Resize {
90 rows: height as u32,
91 cols: width as u32,
92 })
93}
94
95fn map_js_error(message: &str, error: JsValue) -> UnsupportedEvent {
96 UnsupportedEvent(message.to_string() + &error.as_string().unwrap_or_default())
97}
98
99fn to_terminput_scroll_direction(event: &web_sys::WheelEvent) -> ScrollDirection {
100 if event.delta_x() > 0.0 {
101 ScrollDirection::Right
102 } else if event.delta_x() < 0.0 {
103 ScrollDirection::Left
104 } else if event.delta_y() > 0.0 {
105 ScrollDirection::Down
106 } else {
107 ScrollDirection::Up
108 }
109}
110
111fn to_terminput_mouse_kind(
112 event_kind: &str,
113 mouse_button: MouseButton,
114) -> Result<MouseEventKind, UnsupportedEvent> {
115 Ok(match event_kind {
116 "mousemove" => MouseEventKind::Moved,
117 "mousedown" => MouseEventKind::Down(mouse_button),
118 "mouseup" => MouseEventKind::Up(mouse_button),
119 kind => return Err(UnsupportedEvent(kind.to_string())),
120 })
121}
122
123fn to_terminput_mouse_button(button: i16) -> MouseButton {
124 match button {
125 0 => MouseButton::Left,
126 1 => MouseButton::Middle,
127 2 => MouseButton::Right,
128 _ => MouseButton::Unknown,
129 }
130}
131
132fn to_terminput_mouse_modifiers(event: &web_sys::MouseEvent) -> KeyModifiers {
133 let mut modifiers = KeyModifiers::empty();
134 if event.ctrl_key() {
135 modifiers |= KeyModifiers::CTRL;
136 }
137 if event.shift_key() {
138 modifiers |= KeyModifiers::SHIFT;
139 }
140 if event.alt_key() {
141 modifiers |= KeyModifiers::ALT;
142 }
143 if event.meta_key() {
144 modifiers |= KeyModifiers::META;
145 }
146
147 modifiers
148}
149
150fn to_terminput_drag_modifiers(event: &web_sys::DragEvent) -> KeyModifiers {
151 let mut modifiers = KeyModifiers::empty();
152 if event.ctrl_key() {
153 modifiers |= KeyModifiers::CTRL;
154 }
155 if event.shift_key() {
156 modifiers |= KeyModifiers::SHIFT;
157 }
158 if event.alt_key() {
159 modifiers |= KeyModifiers::ALT;
160 }
161 if event.meta_key() {
162 modifiers |= KeyModifiers::META;
163 }
164
165 modifiers
166}
167
168fn to_terminput_key_kind(key_event: &web_sys::KeyboardEvent) -> KeyEventKind {
169 if key_event.repeat() {
170 KeyEventKind::Repeat
171 } else if key_event.type_() == "keyup" {
172 KeyEventKind::Release
173 } else {
174 KeyEventKind::Press
175 }
176}
177
178fn to_terminput_key_modifiers(event: &web_sys::KeyboardEvent) -> KeyModifiers {
179 let mut modifiers = KeyModifiers::empty();
180 if event.ctrl_key() {
181 modifiers |= KeyModifiers::CTRL;
182 }
183 if event.shift_key() {
184 modifiers |= KeyModifiers::SHIFT;
185 }
186 if event.alt_key() {
187 modifiers |= KeyModifiers::ALT;
188 }
189 if event.meta_key() {
190 modifiers |= KeyModifiers::META;
191 }
192
193 modifiers
194}
195
196fn to_terminput_modifier_direction(location: u32) -> ModifierDirection {
197 match location {
198 1 => ModifierDirection::Left,
199 2 => ModifierDirection::Right,
200 _ => ModifierDirection::Unknown,
201 }
202}
203
204fn key_state_to_terminput(event: &web_sys::KeyboardEvent) -> KeyEventState {
205 let mut state = KeyEventState::empty();
206 if event.location() == 3 {
207 state |= KeyEventState::KEYPAD;
208 }
209
210 if event.get_modifier_state("CapsLock") {
211 state |= KeyEventState::CAPS_LOCK;
212 }
213 if event.get_modifier_state("NumLock") {
214 state |= KeyEventState::NUM_LOCK;
215 }
216
217 state
218}
219
220fn to_terminput_key_code(
221 key: &str,
222 direction: ModifierDirection,
223) -> Result<KeyCode, UnsupportedEvent> {
224 let key = key.to_ascii_lowercase();
225 if key.len() == 1 {
226 let key_char = key.chars().next().expect("length checked");
227 if key_char.is_alphanumeric() {
228 return Ok(KeyCode::Char(key_char));
229 }
230 }
231 Ok(match key.as_str() {
232 "f1" => KeyCode::F(1),
233 "f2" => KeyCode::F(2),
234 "f3" => KeyCode::F(3),
235 "f4" => KeyCode::F(4),
236 "f5" => KeyCode::F(5),
237 "f6" => KeyCode::F(6),
238 "f7" => KeyCode::F(7),
239 "f8" => KeyCode::F(8),
240 "f9" => KeyCode::F(9),
241 "f10" => KeyCode::F(10),
242 "f11" => KeyCode::F(11),
243 "f12" => KeyCode::F(12),
244 "backspace" => KeyCode::Backspace,
245 "enter" => KeyCode::Enter,
246 "arrowleft" => KeyCode::Left,
247 "arrowright" => KeyCode::Right,
248 "arrowup" => KeyCode::Up,
249 "arrowdown" => KeyCode::Down,
250 "tab" => KeyCode::Tab,
251 "delete" => KeyCode::Delete,
252 "home" => KeyCode::Home,
253 "end" => KeyCode::End,
254 "pageup" => KeyCode::PageUp,
255 "pagedown" => KeyCode::PageDown,
256 "capslock" => KeyCode::CapsLock,
257 "scrolllock" => KeyCode::ScrollLock,
258 "numlock" => KeyCode::NumLock,
259 "printscreen" => KeyCode::PrintScreen,
260 "alt" => KeyCode::Modifier(ModifierKeyCode::Alt, direction),
261 "control" => KeyCode::Modifier(ModifierKeyCode::Control, direction),
262 "hyper" => KeyCode::Modifier(ModifierKeyCode::Hyper, direction),
263 "meta" => KeyCode::Modifier(ModifierKeyCode::Meta, direction),
264 "super" => KeyCode::Modifier(ModifierKeyCode::Super, direction),
265 "shift" => KeyCode::Modifier(ModifierKeyCode::Shift, direction),
266 "mediaplay" => KeyCode::Media(MediaKeyCode::Play),
267 "mediapause" => KeyCode::Media(MediaKeyCode::Pause),
268 "mediaplaypause" => KeyCode::Media(MediaKeyCode::PlayPause),
269 "mediastop" => KeyCode::Media(MediaKeyCode::Stop),
270 "mediatracknext" => KeyCode::Media(MediaKeyCode::TrackNext),
271 "mediatrackprevious" => KeyCode::Media(MediaKeyCode::TrackPrevious),
272 "mediafastforward" => KeyCode::Media(MediaKeyCode::FastForward),
273 "mediarewind" => KeyCode::Media(MediaKeyCode::Rewind),
274 "mediarecord" => KeyCode::Media(MediaKeyCode::Record),
275 key => return Err(UnsupportedEvent(key.to_string())),
276 })
277}