mail client (IMAP/SMTP)
git clone https://git.lucas.co/cce-mail.git
src/wpe/input.rs (5.3K)
1 //! Translating cce-ui input into `WPEEvent`s.
2 //!
3 //! Unlike the Servo backend — where `main.rs` carried `dom_key`/`dom_button`
4 //! helpers and the host took engine types — the mapping lives *here* and
5 //! [`super::WebKitHost`] takes cce-ui's own `MouseButton` / `KeyEvent`. That
6 //! keeps engine vocabulary out of the chrome, so switching backends deletes
7 //! those helpers from `main.rs` rather than rewriting them.
8 //!
9 //! **Keyboard is the fiddly part.** `wpe_event_keyboard_new` wants an X11
10 //! *keysym* (`keyval`), not a character. Latin-1 codepoints are their own
11 //! keysym; anything above maps to `codepoint + 0x0100_0000`; named keys have
12 //! fixed `XK_*` values. Getting this wrong is silent — the page just receives
13 //! nothing useful.
14
15 use cce_ui::widget::{ElementState, Key, KeyEvent, MouseButton, NamedKey};
16
17 use super::ffi::*;
18
19 /// X11 keysyms for the named keys cce-ui reports (`/usr/include/X11/keysymdef.h`).
20 mod keysym {
21 pub const BACKSPACE: u32 = 0xff08;
22 pub const TAB: u32 = 0xff09;
23 pub const RETURN: u32 = 0xff0d;
24 pub const ESCAPE: u32 = 0xff1b;
25 pub const SPACE: u32 = 0x0020;
26 pub const HOME: u32 = 0xff50;
27 pub const LEFT: u32 = 0xff51;
28 pub const UP: u32 = 0xff52;
29 pub const RIGHT: u32 = 0xff53;
30 pub const DOWN: u32 = 0xff54;
31 pub const PAGE_UP: u32 = 0xff55;
32 pub const PAGE_DOWN: u32 = 0xff56;
33 pub const END: u32 = 0xff57;
34 pub const DELETE: u32 = 0xffff;
35 pub const F1: u32 = 0xffbe;
36 pub const F2: u32 = 0xffbf;
37 pub const F3: u32 = 0xffc0;
38 pub const F4: u32 = 0xffc1;
39 pub const F5: u32 = 0xffc2;
40 pub const F6: u32 = 0xffc3;
41 pub const F7: u32 = 0xffc4;
42 pub const F8: u32 = 0xffc5;
43 pub const F9: u32 = 0xffc6;
44 pub const F10: u32 = 0xffc7;
45 pub const F11: u32 = 0xffc8;
46 pub const F12: u32 = 0xffc9;
47 pub const SHIFT_L: u32 = 0xffe1;
48 pub const CONTROL_L: u32 = 0xffe3;
49 pub const ALT_L: u32 = 0xffe9;
50 pub const SUPER_L: u32 = 0xffeb;
51 }
52
53 /// A Unicode scalar as an X11 keysym: Latin-1 is identity, the rest is the
54 /// codepoint in the 0x01000000 plane.
55 fn unicode_keysym(c: char) -> u32 {
56 match c as u32 {
57 cp @ 0x20..=0xff => cp,
58 cp => cp + 0x0100_0000,
59 }
60 }
61
62 /// cce-ui key -> X11 keysym. `None` for keys with no sensible mapping.
63 pub(super) fn keyval(key: &Key) -> Option<u32> {
64 Some(match key {
65 Key::Character(s) => unicode_keysym(s.chars().next()?),
66 Key::Named(n) => match n {
67 NamedKey::Backspace => keysym::BACKSPACE,
68 NamedKey::Tab => keysym::TAB,
69 NamedKey::Enter => keysym::RETURN,
70 NamedKey::Escape => keysym::ESCAPE,
71 NamedKey::Space => keysym::SPACE,
72 NamedKey::ArrowDown => keysym::DOWN,
73 NamedKey::ArrowLeft => keysym::LEFT,
74 NamedKey::ArrowRight => keysym::RIGHT,
75 NamedKey::ArrowUp => keysym::UP,
76 NamedKey::End => keysym::END,
77 NamedKey::Home => keysym::HOME,
78 NamedKey::PageDown => keysym::PAGE_DOWN,
79 NamedKey::PageUp => keysym::PAGE_UP,
80 NamedKey::Delete => keysym::DELETE,
81 NamedKey::Control => keysym::CONTROL_L,
82 NamedKey::Shift => keysym::SHIFT_L,
83 NamedKey::Alt => keysym::ALT_L,
84 NamedKey::Super => keysym::SUPER_L,
85 NamedKey::F1 => keysym::F1,
86 NamedKey::F2 => keysym::F2,
87 NamedKey::F3 => keysym::F3,
88 NamedKey::F4 => keysym::F4,
89 NamedKey::F5 => keysym::F5,
90 NamedKey::F6 => keysym::F6,
91 NamedKey::F7 => keysym::F7,
92 NamedKey::F8 => keysym::F8,
93 NamedKey::F9 => keysym::F9,
94 NamedKey::F10 => keysym::F10,
95 NamedKey::F11 => keysym::F11,
96 NamedKey::F12 => keysym::F12,
97 },
98 })
99 }
100
101 /// X11 button numbering, which is what WPE expects.
102 pub(super) fn button_number(b: MouseButton) -> Option<u32> {
103 Some(match b {
104 MouseButton::Left => 1,
105 MouseButton::Middle => 2,
106 MouseButton::Right => 3,
107 // Back/Forward are chrome navigation in `main.rs`, deliberately not
108 // forwarded to the page.
109 _ => return None,
110 })
111 }
112
113 /// An X11 button number's held-button bit, the form a pointer event's
114 /// modifiers carry it in (`WPE_MODIFIER_POINTER_BUTTON1` is button 1, and the
115 /// five are consecutive).
116 pub(super) fn button_modifier(n: u32) -> WPEModifiers::Type {
117 match n {
118 1..=5 => WPEModifiers::WPE_MODIFIER_POINTER_BUTTON1 << (n - 1),
119 _ => 0,
120 }
121 }
122
123 pub(super) fn modifiers(ctrl: bool, shift: bool, alt: bool) -> WPEModifiers::Type {
124 let mut m: WPEModifiers::Type = 0;
125 if ctrl {
126 m |= WPEModifiers::WPE_MODIFIER_KEYBOARD_CONTROL;
127 }
128 if shift {
129 m |= WPEModifiers::WPE_MODIFIER_KEYBOARD_SHIFT;
130 }
131 if alt {
132 m |= WPEModifiers::WPE_MODIFIER_KEYBOARD_ALT;
133 }
134 m
135 }
136
137 pub(super) fn is_pressed(e: &KeyEvent) -> bool {
138 e.state == ElementState::Pressed
139 }
140
141 /// WPE stamps events with a millisecond clock. It only has to be monotonic
142 /// and consistent — `wpe_view_compute_press_count` uses it for double-click
143 /// detection, so a frozen value would turn every click into a triple-click.
144 pub(super) fn now_ms() -> u32 {
145 use std::time::{SystemTime, UNIX_EPOCH};
146 SystemTime::now()
147 .duration_since(UNIX_EPOCH)
148 .map(|d| d.as_millis() as u32)
149 .unwrap_or(0)
150 }