terminput_termina/
mapping.rs

1#[cfg(feature = "termina_0_1")]
2use termina_0_1 as termina;
3use terminput::{
4    Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers, MediaKeyCode,
5    ModifierDirection, ModifierKeyCode, MouseButton, MouseEvent, MouseEventKind, ScrollDirection,
6    UnsupportedEvent,
7};
8
9/// Converts the termina [`Event`](termina::Event) to a terminput [`Event`].
10pub fn to_terminput(value: termina::Event) -> Result<Event, UnsupportedEvent> {
11    Ok(match value {
12        termina::Event::FocusIn => Event::FocusGained,
13        termina::Event::FocusOut => Event::FocusLost,
14        termina::Event::Key(key_event) => Event::Key(to_terminput_key(key_event)?),
15        termina::Event::Mouse(mouse_event) => Event::Mouse(to_terminput_mouse(mouse_event)),
16        termina::Event::Paste(value) => Event::Paste(value),
17        termina::Event::WindowResized(window_size) => Event::Resize {
18            cols: window_size.cols as u32,
19            rows: window_size.rows as u32,
20        },
21        event @ (termina::Event::Dcs(_) | termina::Event::Csi(_)) => {
22            Err(UnsupportedEvent(format!("{event:?}")))?
23        }
24    })
25}
26
27/// Converts the terminput [`Event`] to a termina [`Event`](termina::Event).
28pub fn to_termina(value: Event) -> Result<termina::Event, UnsupportedEvent> {
29    Ok(match value {
30        Event::FocusGained => termina::Event::FocusIn,
31        Event::FocusLost => termina::Event::FocusOut,
32        Event::Key(key_event) => termina::Event::Key(to_termina_key(key_event)),
33        Event::Mouse(mouse_event) => termina::Event::Mouse(to_termina_mouse(mouse_event)?),
34        Event::Paste(value) => termina::Event::Paste(value),
35        Event::Resize { cols, rows } => termina::Event::WindowResized(termina::WindowSize {
36            cols: cols
37                .try_into()
38                .map_err(|e| UnsupportedEvent(format!("{e:?}")))?,
39            rows: rows
40                .try_into()
41                .map_err(|e| UnsupportedEvent(format!("{e:?}")))?,
42            pixel_width: None,
43            pixel_height: None,
44        }),
45    })
46}
47
48/// Converts the termina [`MouseEvent`](termina::event::MouseEvent) to a terminput [`MouseEvent`].
49pub fn to_terminput_mouse(value: termina::event::MouseEvent) -> MouseEvent {
50    MouseEvent {
51        kind: mouse_kind_to_terminput(value.kind),
52        column: value.column,
53        row: value.row,
54        modifiers: key_modifiers_to_terminput(value.modifiers),
55    }
56}
57
58/// Converts the terminput [`MouseEvent`] to a termina [`MouseEvent`](termina::event::MouseEvent).
59pub fn to_termina_mouse(value: MouseEvent) -> Result<termina::event::MouseEvent, UnsupportedEvent> {
60    Ok(termina::event::MouseEvent {
61        kind: mouse_kind_to_termina(value.kind)?,
62        column: value.column,
63        row: value.row,
64        modifiers: key_modifiers_to_termina(value.modifiers),
65    })
66}
67
68fn mouse_kind_to_terminput(value: termina::event::MouseEventKind) -> MouseEventKind {
69    match value {
70        termina::event::MouseEventKind::Down(button) => {
71            MouseEventKind::Down(mouse_button_to_terminput(button))
72        }
73        termina::event::MouseEventKind::Up(button) => {
74            MouseEventKind::Up(mouse_button_to_terminput(button))
75        }
76        termina::event::MouseEventKind::Drag(button) => {
77            MouseEventKind::Drag(mouse_button_to_terminput(button))
78        }
79        termina::event::MouseEventKind::Moved => MouseEventKind::Moved,
80        termina::event::MouseEventKind::ScrollDown => MouseEventKind::Scroll(ScrollDirection::Down),
81        termina::event::MouseEventKind::ScrollUp => MouseEventKind::Scroll(ScrollDirection::Up),
82        termina::event::MouseEventKind::ScrollLeft => MouseEventKind::Scroll(ScrollDirection::Left),
83        termina::event::MouseEventKind::ScrollRight => {
84            MouseEventKind::Scroll(ScrollDirection::Right)
85        }
86    }
87}
88
89fn mouse_kind_to_termina(
90    value: MouseEventKind,
91) -> Result<termina::event::MouseEventKind, UnsupportedEvent> {
92    Ok(match value {
93        MouseEventKind::Down(button) => {
94            termina::event::MouseEventKind::Down(mouse_button_to_termina(button)?)
95        }
96        MouseEventKind::Up(button) => {
97            termina::event::MouseEventKind::Up(mouse_button_to_termina(button)?)
98        }
99        MouseEventKind::Drag(button) => {
100            termina::event::MouseEventKind::Drag(mouse_button_to_termina(button)?)
101        }
102        MouseEventKind::Moved => termina::event::MouseEventKind::Moved,
103        MouseEventKind::Scroll(ScrollDirection::Down) => termina::event::MouseEventKind::ScrollDown,
104        MouseEventKind::Scroll(ScrollDirection::Up) => termina::event::MouseEventKind::ScrollUp,
105        MouseEventKind::Scroll(ScrollDirection::Left) => termina::event::MouseEventKind::ScrollLeft,
106        MouseEventKind::Scroll(ScrollDirection::Right) => {
107            termina::event::MouseEventKind::ScrollRight
108        }
109    })
110}
111
112fn mouse_button_to_terminput(value: termina::event::MouseButton) -> MouseButton {
113    match value {
114        termina::event::MouseButton::Left => MouseButton::Left,
115        termina::event::MouseButton::Right => MouseButton::Right,
116        termina::event::MouseButton::Middle => MouseButton::Middle,
117    }
118}
119
120fn mouse_button_to_termina(
121    value: MouseButton,
122) -> Result<termina::event::MouseButton, UnsupportedEvent> {
123    Ok(match value {
124        MouseButton::Left => termina::event::MouseButton::Left,
125        MouseButton::Right => termina::event::MouseButton::Right,
126        MouseButton::Middle => termina::event::MouseButton::Middle,
127        val @ MouseButton::Unknown => Err(UnsupportedEvent(format!("{val:?}")))?,
128    })
129}
130
131/// Converts the termina [`KeyEvent`](termina::event::KeyEvent) to a terminput [`KeyEvent`].
132pub fn to_terminput_key(value: termina::event::KeyEvent) -> Result<KeyEvent, UnsupportedEvent> {
133    Ok(KeyEvent {
134        code: key_code_to_terminput(value.code)?,
135        modifiers: key_modifiers_to_terminput(value.modifiers),
136        kind: key_kind_to_terminput(value.kind),
137        state: key_state_to_terminput(value.state),
138    })
139}
140
141/// Converts the terminput [`KeyEvent`] to a termina [`KeyEvent`](termina::event::KeyEvent).
142pub fn to_termina_key(value: KeyEvent) -> termina::event::KeyEvent {
143    termina::event::KeyEvent {
144        code: convert_termina_key_code(value.code, value.modifiers.intersects(KeyModifiers::SHIFT)),
145        modifiers: key_modifiers_to_termina(value.modifiers),
146        kind: key_kind_to_termina(value.kind),
147        state: key_state_to_termina(value.state),
148    }
149}
150
151fn key_code_to_terminput(value: termina::event::KeyCode) -> Result<KeyCode, UnsupportedEvent> {
152    Ok(match value {
153        termina::event::KeyCode::Backspace => KeyCode::Backspace,
154        termina::event::KeyCode::Enter => KeyCode::Enter,
155        termina::event::KeyCode::Left => KeyCode::Left,
156        termina::event::KeyCode::Right => KeyCode::Right,
157        termina::event::KeyCode::Up => KeyCode::Up,
158        termina::event::KeyCode::Down => KeyCode::Down,
159        termina::event::KeyCode::Home => KeyCode::Home,
160        termina::event::KeyCode::End => KeyCode::End,
161        termina::event::KeyCode::PageUp => KeyCode::PageUp,
162        termina::event::KeyCode::PageDown => KeyCode::PageDown,
163        termina::event::KeyCode::Tab => KeyCode::Tab,
164        termina::event::KeyCode::BackTab => KeyCode::Tab,
165        termina::event::KeyCode::Delete => KeyCode::Delete,
166        termina::event::KeyCode::Insert => KeyCode::Insert,
167        termina::event::KeyCode::Function(f) => KeyCode::F(f),
168        termina::event::KeyCode::Char(c) => KeyCode::Char(c),
169        termina::event::KeyCode::Escape => KeyCode::Esc,
170        termina::event::KeyCode::CapsLock => KeyCode::CapsLock,
171        termina::event::KeyCode::ScrollLock => KeyCode::ScrollLock,
172        termina::event::KeyCode::NumLock => KeyCode::NumLock,
173        termina::event::KeyCode::PrintScreen => KeyCode::PrintScreen,
174        termina::event::KeyCode::Pause => KeyCode::Pause,
175        termina::event::KeyCode::Menu => KeyCode::Menu,
176        termina::event::KeyCode::KeypadBegin => KeyCode::KeypadBegin,
177        termina::event::KeyCode::Media(m) => KeyCode::Media(media_code_to_terminput(m)),
178        termina::event::KeyCode::Modifier(m) => {
179            let (code, direction) = convert_modifier_key_code(m);
180            KeyCode::Modifier(code, direction)
181        }
182        termina::event::KeyCode::Null => Err(UnsupportedEvent(format!("{value:?}")))?,
183    })
184}
185
186fn convert_termina_key_code(value: KeyCode, shift: bool) -> termina::event::KeyCode {
187    match value {
188        KeyCode::Backspace => termina::event::KeyCode::Backspace,
189        KeyCode::Enter => termina::event::KeyCode::Enter,
190        KeyCode::Left => termina::event::KeyCode::Left,
191        KeyCode::Right => termina::event::KeyCode::Right,
192        KeyCode::Up => termina::event::KeyCode::Up,
193        KeyCode::Down => termina::event::KeyCode::Down,
194        KeyCode::Home => termina::event::KeyCode::Home,
195        KeyCode::End => termina::event::KeyCode::End,
196        KeyCode::PageUp => termina::event::KeyCode::PageUp,
197        KeyCode::PageDown => termina::event::KeyCode::PageDown,
198        KeyCode::Tab if shift => termina::event::KeyCode::BackTab,
199        KeyCode::Tab => termina::event::KeyCode::Tab,
200        KeyCode::Delete => termina::event::KeyCode::Delete,
201        KeyCode::Insert => termina::event::KeyCode::Insert,
202        KeyCode::F(f) => termina::event::KeyCode::Function(f),
203        KeyCode::Char(c) => termina::event::KeyCode::Char(c),
204        KeyCode::Esc => termina::event::KeyCode::Escape,
205        KeyCode::CapsLock => termina::event::KeyCode::CapsLock,
206        KeyCode::ScrollLock => termina::event::KeyCode::ScrollLock,
207        KeyCode::NumLock => termina::event::KeyCode::NumLock,
208        KeyCode::PrintScreen => termina::event::KeyCode::PrintScreen,
209        KeyCode::Pause => termina::event::KeyCode::Pause,
210        KeyCode::Menu => termina::event::KeyCode::Menu,
211        KeyCode::KeypadBegin => termina::event::KeyCode::KeypadBegin,
212        KeyCode::Media(m) => termina::event::KeyCode::Media(media_code_to_termina(m)),
213        KeyCode::Modifier(code, direction) => {
214            termina::event::KeyCode::Modifier(convert_termina_modifier_key_code(code, direction))
215        }
216    }
217}
218
219fn key_modifiers_to_terminput(value: termina::event::Modifiers) -> KeyModifiers {
220    let mut res = KeyModifiers::empty();
221    if value.intersects(termina::event::Modifiers::ALT) {
222        res |= KeyModifiers::ALT;
223    }
224    if value.intersects(termina::event::Modifiers::SHIFT) {
225        res |= KeyModifiers::SHIFT;
226    }
227    if value.intersects(termina::event::Modifiers::CONTROL) {
228        res |= KeyModifiers::CTRL;
229    }
230    if value.intersects(termina::event::Modifiers::SUPER) {
231        res |= KeyModifiers::SUPER;
232    }
233
234    res
235}
236
237fn key_modifiers_to_termina(value: KeyModifiers) -> termina::event::Modifiers {
238    let mut res = termina::event::Modifiers::empty();
239    if value.intersects(KeyModifiers::ALT) {
240        res |= termina::event::Modifiers::ALT;
241    }
242    if value.intersects(KeyModifiers::SHIFT) {
243        res |= termina::event::Modifiers::SHIFT;
244    }
245    if value.intersects(KeyModifiers::CTRL) {
246        res |= termina::event::Modifiers::CONTROL;
247    }
248    if value.intersects(KeyModifiers::SUPER) {
249        res |= termina::event::Modifiers::SUPER;
250    }
251
252    res
253}
254
255fn key_kind_to_terminput(value: termina::event::KeyEventKind) -> KeyEventKind {
256    match value {
257        termina::event::KeyEventKind::Press => KeyEventKind::Press,
258        termina::event::KeyEventKind::Repeat => KeyEventKind::Repeat,
259        termina::event::KeyEventKind::Release => KeyEventKind::Release,
260    }
261}
262
263fn key_kind_to_termina(value: KeyEventKind) -> termina::event::KeyEventKind {
264    match value {
265        KeyEventKind::Press => termina::event::KeyEventKind::Press,
266        KeyEventKind::Repeat => termina::event::KeyEventKind::Repeat,
267        KeyEventKind::Release => termina::event::KeyEventKind::Release,
268    }
269}
270
271fn media_code_to_terminput(value: termina::event::MediaKeyCode) -> MediaKeyCode {
272    match value {
273        termina::event::MediaKeyCode::Play => MediaKeyCode::Play,
274        termina::event::MediaKeyCode::Pause => MediaKeyCode::Pause,
275        termina::event::MediaKeyCode::PlayPause => MediaKeyCode::PlayPause,
276        termina::event::MediaKeyCode::Reverse => MediaKeyCode::Reverse,
277        termina::event::MediaKeyCode::Stop => MediaKeyCode::Stop,
278        termina::event::MediaKeyCode::FastForward => MediaKeyCode::FastForward,
279        termina::event::MediaKeyCode::Rewind => MediaKeyCode::Rewind,
280        termina::event::MediaKeyCode::TrackNext => MediaKeyCode::TrackNext,
281        termina::event::MediaKeyCode::TrackPrevious => MediaKeyCode::TrackPrevious,
282        termina::event::MediaKeyCode::Record => MediaKeyCode::Record,
283        termina::event::MediaKeyCode::LowerVolume => MediaKeyCode::LowerVolume,
284        termina::event::MediaKeyCode::RaiseVolume => MediaKeyCode::RaiseVolume,
285        termina::event::MediaKeyCode::MuteVolume => MediaKeyCode::MuteVolume,
286    }
287}
288
289fn media_code_to_termina(value: MediaKeyCode) -> termina::event::MediaKeyCode {
290    match value {
291        MediaKeyCode::Play => termina::event::MediaKeyCode::Play,
292        MediaKeyCode::Pause => termina::event::MediaKeyCode::Pause,
293        MediaKeyCode::PlayPause => termina::event::MediaKeyCode::PlayPause,
294        MediaKeyCode::Reverse => termina::event::MediaKeyCode::Reverse,
295        MediaKeyCode::Stop => termina::event::MediaKeyCode::Stop,
296        MediaKeyCode::FastForward => termina::event::MediaKeyCode::FastForward,
297        MediaKeyCode::Rewind => termina::event::MediaKeyCode::Rewind,
298        MediaKeyCode::TrackNext => termina::event::MediaKeyCode::TrackNext,
299        MediaKeyCode::TrackPrevious => termina::event::MediaKeyCode::TrackPrevious,
300        MediaKeyCode::Record => termina::event::MediaKeyCode::Record,
301        MediaKeyCode::LowerVolume => termina::event::MediaKeyCode::LowerVolume,
302        MediaKeyCode::RaiseVolume => termina::event::MediaKeyCode::RaiseVolume,
303        MediaKeyCode::MuteVolume => termina::event::MediaKeyCode::MuteVolume,
304    }
305}
306
307fn convert_modifier_key_code(
308    value: termina::event::ModifierKeyCode,
309) -> (ModifierKeyCode, ModifierDirection) {
310    match value {
311        termina::event::ModifierKeyCode::LeftShift => {
312            (ModifierKeyCode::Shift, ModifierDirection::Left)
313        }
314        termina::event::ModifierKeyCode::LeftControl => {
315            (ModifierKeyCode::Control, ModifierDirection::Left)
316        }
317        termina::event::ModifierKeyCode::LeftAlt => (ModifierKeyCode::Alt, ModifierDirection::Left),
318        termina::event::ModifierKeyCode::LeftSuper => {
319            (ModifierKeyCode::Super, ModifierDirection::Left)
320        }
321        termina::event::ModifierKeyCode::LeftHyper => {
322            (ModifierKeyCode::Hyper, ModifierDirection::Left)
323        }
324        termina::event::ModifierKeyCode::LeftMeta => {
325            (ModifierKeyCode::Meta, ModifierDirection::Left)
326        }
327        termina::event::ModifierKeyCode::RightShift => {
328            (ModifierKeyCode::Shift, ModifierDirection::Right)
329        }
330        termina::event::ModifierKeyCode::RightControl => {
331            (ModifierKeyCode::Control, ModifierDirection::Right)
332        }
333        termina::event::ModifierKeyCode::RightAlt => {
334            (ModifierKeyCode::Alt, ModifierDirection::Right)
335        }
336        termina::event::ModifierKeyCode::RightSuper => {
337            (ModifierKeyCode::Super, ModifierDirection::Right)
338        }
339        termina::event::ModifierKeyCode::RightHyper => {
340            (ModifierKeyCode::Hyper, ModifierDirection::Right)
341        }
342        termina::event::ModifierKeyCode::RightMeta => {
343            (ModifierKeyCode::Meta, ModifierDirection::Right)
344        }
345        termina::event::ModifierKeyCode::IsoLevel3Shift => {
346            (ModifierKeyCode::IsoLevel3Shift, ModifierDirection::Unknown)
347        }
348        termina::event::ModifierKeyCode::IsoLevel5Shift => {
349            (ModifierKeyCode::IsoLevel5Shift, ModifierDirection::Unknown)
350        }
351    }
352}
353
354fn convert_termina_modifier_key_code(
355    code: ModifierKeyCode,
356    direction: ModifierDirection,
357) -> termina::event::ModifierKeyCode {
358    match (code, direction) {
359        (ModifierKeyCode::Shift, ModifierDirection::Left | ModifierDirection::Unknown) => {
360            termina::event::ModifierKeyCode::LeftShift
361        }
362        (ModifierKeyCode::Control, ModifierDirection::Left | ModifierDirection::Unknown) => {
363            termina::event::ModifierKeyCode::LeftControl
364        }
365        (ModifierKeyCode::Alt, ModifierDirection::Left | ModifierDirection::Unknown) => {
366            termina::event::ModifierKeyCode::LeftAlt
367        }
368        (ModifierKeyCode::Super, ModifierDirection::Left | ModifierDirection::Unknown) => {
369            termina::event::ModifierKeyCode::LeftSuper
370        }
371        (ModifierKeyCode::Hyper, ModifierDirection::Left | ModifierDirection::Unknown) => {
372            termina::event::ModifierKeyCode::LeftHyper
373        }
374        (ModifierKeyCode::Meta, ModifierDirection::Left | ModifierDirection::Unknown) => {
375            termina::event::ModifierKeyCode::LeftMeta
376        }
377        (ModifierKeyCode::Shift, ModifierDirection::Right) => {
378            termina::event::ModifierKeyCode::RightShift
379        }
380        (ModifierKeyCode::Control, ModifierDirection::Right) => {
381            termina::event::ModifierKeyCode::RightControl
382        }
383        (ModifierKeyCode::Alt, ModifierDirection::Right) => {
384            termina::event::ModifierKeyCode::RightAlt
385        }
386        (ModifierKeyCode::Super, ModifierDirection::Right) => {
387            termina::event::ModifierKeyCode::RightSuper
388        }
389        (ModifierKeyCode::Hyper, ModifierDirection::Right) => {
390            termina::event::ModifierKeyCode::RightHyper
391        }
392        (ModifierKeyCode::Meta, ModifierDirection::Right) => {
393            termina::event::ModifierKeyCode::RightMeta
394        }
395        (ModifierKeyCode::IsoLevel3Shift, _) => termina::event::ModifierKeyCode::IsoLevel3Shift,
396        (ModifierKeyCode::IsoLevel5Shift, _) => termina::event::ModifierKeyCode::IsoLevel5Shift,
397    }
398}
399
400fn key_state_to_terminput(value: termina::event::KeyEventState) -> KeyEventState {
401    let mut state = KeyEventState::empty();
402    if value.intersects(termina::event::KeyEventState::KEYPAD) {
403        state |= KeyEventState::KEYPAD;
404    }
405    if value.intersects(termina::event::KeyEventState::CAPS_LOCK) {
406        state |= KeyEventState::CAPS_LOCK;
407    }
408    if value.intersects(termina::event::KeyEventState::NUM_LOCK) {
409        state |= KeyEventState::NUM_LOCK;
410    }
411    state
412}
413
414fn key_state_to_termina(value: KeyEventState) -> termina::event::KeyEventState {
415    let mut state = termina::event::KeyEventState::empty();
416    if value.intersects(KeyEventState::KEYPAD) {
417        state |= termina::event::KeyEventState::KEYPAD;
418    }
419    if value.intersects(KeyEventState::CAPS_LOCK) {
420        state |= termina::event::KeyEventState::CAPS_LOCK;
421    }
422    if value.intersects(KeyEventState::NUM_LOCK) {
423        state |= termina::event::KeyEventState::NUM_LOCK;
424    }
425    state
426}