Skip to main content

embedder_traits/
input_events.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::sync::atomic::{AtomicUsize, Ordering};
6
7use bitflags::bitflags;
8use keyboard_types::{Code, CompositionEvent, Key, KeyState, Location, Modifiers};
9use malloc_size_of_derive::MallocSizeOf;
10use serde::{Deserialize, Serialize};
11
12use crate::WebViewPoint;
13
14/// An opaque id for an [`InputEvent`].
15#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
16pub struct InputEventId(usize);
17
18static INPUT_EVENT_ID: AtomicUsize = AtomicUsize::new(0);
19
20impl InputEventId {
21    fn new() -> Self {
22        Self(INPUT_EVENT_ID.fetch_add(1, Ordering::Relaxed))
23    }
24}
25
26bitflags! {
27    /// Flags representing the state of an [`InputEvent`] after Servo has handled it.
28    #[derive(Clone, Copy, Default, Deserialize, PartialEq, Serialize)]
29    pub struct InputEventResult: u8 {
30        /// Whether or not this input event's default behavior was prevented via script.
31        const DefaultPrevented = 1 << 0;
32        /// Whether or not the WebView handled this event. Some events have default handlers in
33        /// Servo, such as keyboard events that insert characters in `<input>` areas. When these
34        /// handlers are triggered, this flag is included. This can be used to prevent triggering
35        /// behavior (such as keybindings) when the WebView has already consumed the event for its
36        /// own purpose.
37        const Consumed = 1 << 1;
38        /// Whether or not the input event failed to dispatch. This can happen when an event
39        /// is sent while Servo is shutting down or when it is in an intermediate state.
40        /// Typically these events should be considered to be consumed.
41        const DispatchFailed = 1 << 2;
42    }
43}
44
45#[derive(Deserialize, Serialize)]
46pub struct InputEventOutcome {
47    pub id: InputEventId,
48    pub result: InputEventResult,
49}
50
51/// An input event that is sent from the embedder to Servo.
52#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
53pub enum InputEvent {
54    EditingAction(ClipboardAction),
55    #[cfg(feature = "gamepad")]
56    Gamepad(GamepadEvent),
57    Ime(ImeEvent),
58    Keyboard(KeyboardEvent),
59    MouseButton(MouseButtonEvent),
60    MouseLeftViewport(MouseLeftViewportEvent),
61    MouseMove(MouseMoveEvent),
62    Touch(TouchEvent),
63    Wheel(WheelEvent),
64}
65
66#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
67pub struct InputEventAndId {
68    pub event: InputEvent,
69    pub id: InputEventId,
70}
71
72impl From<InputEvent> for InputEventAndId {
73    fn from(event: InputEvent) -> Self {
74        Self {
75            event,
76            id: InputEventId::new(),
77        }
78    }
79}
80
81/// A direction for an [`EditingAction`].
82#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
83pub enum EditingDirection {
84    Forward,
85    Backward,
86}
87
88/// Describes a unit of movement for an [`EditingAction`].
89#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
90pub enum EditingMotion {
91    Character,
92    Grapheme,
93    Word,
94    Line,
95    LineStartOrEnd,
96    Page,
97    DocumentStartOrEnd,
98}
99
100/// Whether the selection should follow cursor motion when doing an editing action.
101#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
102pub enum ModifySelection {
103    Yes,
104    No,
105}
106
107/// Which type of clipboard operation should be performed for an [`EditingAction::Clipboard`].
108#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
109pub enum ClipboardAction {
110    Copy,
111    Cut,
112    Paste,
113}
114
115/// An action to perform in an [`EditingContext`].
116///
117/// This is public because it is used in external unit tests.
118#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
119pub enum EditingAction {
120    Backspace(EditingMotion),
121    Clipboard(ClipboardAction),
122    Delete,
123    EndComposition(String),
124    InsertCompositionText(String),
125    InsertNewline,
126    InsertParagraph,
127    InsertText(String),
128    MoveCursor(EditingDirection, EditingMotion, ModifySelection),
129    SelectAll,
130    StartComposition,
131}
132
133impl InputEvent {
134    pub fn point(&self) -> Option<WebViewPoint> {
135        match self {
136            InputEvent::EditingAction(..) => None,
137            #[cfg(feature = "gamepad")]
138            InputEvent::Gamepad(..) => None,
139            InputEvent::Ime(..) => None,
140            InputEvent::Keyboard(..) => None,
141            InputEvent::MouseButton(event) => Some(event.point),
142            InputEvent::MouseMove(event) => Some(event.point),
143            InputEvent::MouseLeftViewport(_) => None,
144            InputEvent::Touch(event) => Some(event.point),
145            InputEvent::Wheel(event) => Some(event.point),
146        }
147    }
148}
149
150#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
151pub struct KeyboardEvent {
152    pub event: ::keyboard_types::KeyboardEvent,
153}
154
155impl KeyboardEvent {
156    pub fn new(keyboard_event: ::keyboard_types::KeyboardEvent) -> Self {
157        Self {
158            event: keyboard_event,
159        }
160    }
161
162    pub fn new_without_event(
163        state: KeyState,
164        key: Key,
165        code: Code,
166        location: Location,
167        modifiers: Modifiers,
168        repeat: bool,
169        is_composing: bool,
170    ) -> Self {
171        Self::new(::keyboard_types::KeyboardEvent {
172            state,
173            key,
174            code,
175            location,
176            modifiers,
177            repeat,
178            is_composing,
179        })
180    }
181
182    pub fn from_state_and_key(state: KeyState, key: Key) -> Self {
183        Self::new(::keyboard_types::KeyboardEvent {
184            state,
185            key,
186            ..::keyboard_types::KeyboardEvent::default()
187        })
188    }
189}
190
191#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)]
192pub struct MouseButtonEvent {
193    pub action: MouseButtonAction,
194    pub button: MouseButton,
195    pub point: WebViewPoint,
196    #[doc(hidden)]
197    // An internal flag marking a compatibility mouse event synthesized for a
198    // touch/pen tap. Such events must not generate pointer events.
199    pub is_compatibility_event_for_touch: bool,
200}
201
202impl MouseButtonEvent {
203    pub fn new(action: MouseButtonAction, button: MouseButton, point: WebViewPoint) -> Self {
204        Self {
205            action,
206            button,
207            point,
208            is_compatibility_event_for_touch: false,
209        }
210    }
211
212    #[doc(hidden)]
213    pub fn new_compatibility_for_touch(
214        action: MouseButtonAction,
215        button: MouseButton,
216        point: WebViewPoint,
217    ) -> Self {
218        Self {
219            action,
220            button,
221            point,
222            is_compatibility_event_for_touch: true,
223        }
224    }
225}
226
227/// The types of mouse buttons.
228///
229/// <https://w3c.github.io/pointerevents/#the-button-property>
230#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
231pub enum MouseButton {
232    #[doc(hidden)]
233    None,
234    Primary,
235    Auxiliary,
236    Secondary,
237    Back,
238    Forward,
239    Other(u16),
240}
241
242impl<T: Into<i128>> From<T> for MouseButton {
243    fn from(value: T) -> Self {
244        let value = value.into();
245        match value {
246            -1 => MouseButton::None,
247            0 => MouseButton::Primary,
248            1 => MouseButton::Auxiliary,
249            2 => MouseButton::Secondary,
250            3 => MouseButton::Back,
251            4 => MouseButton::Forward,
252            _ => MouseButton::Other(value as u16),
253        }
254    }
255}
256
257impl From<MouseButton> for i16 {
258    fn from(value: MouseButton) -> Self {
259        match value {
260            MouseButton::None => -1,
261            MouseButton::Primary => 0,
262            MouseButton::Auxiliary => 1,
263            MouseButton::Secondary => 2,
264            MouseButton::Back => 3,
265            MouseButton::Forward => 4,
266            MouseButton::Other(value) => value as i16,
267        }
268    }
269}
270
271/// The types of mouse events.
272#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
273pub enum MouseButtonAction {
274    /// Mouse button down.
275    Down,
276    /// Mouse button up.
277    Up,
278}
279
280#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)]
281pub struct MouseMoveEvent {
282    pub point: WebViewPoint,
283    #[doc(hidden)]
284    // An internal flag used to avoid refreshing the cursor in response to move
285    // events for touch devices since they are simulated in Servo using mouse events.
286    pub is_compatibility_event_for_touch: bool,
287}
288
289impl MouseMoveEvent {
290    pub fn new(point: WebViewPoint) -> Self {
291        Self {
292            point,
293            is_compatibility_event_for_touch: false,
294        }
295    }
296
297    #[doc(hidden)]
298    pub fn new_compatibility_for_touch(point: WebViewPoint) -> Self {
299        Self {
300            point,
301            is_compatibility_event_for_touch: true,
302        }
303    }
304}
305
306#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
307pub struct MouseLeftViewportEvent {
308    pub focus_moving_to_another_iframe: bool,
309}
310
311/// The type of input represented by a multi-touch event.
312#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)]
313pub enum TouchEventType {
314    /// A new touch point came in contact with the screen.
315    Down,
316    /// An existing touch point changed location.
317    Move,
318    /// A touch point was removed from the screen.
319    Up,
320    /// The system stopped tracking a touch point.
321    Cancel,
322}
323
324/// An opaque identifier for a touch point.
325///
326/// <http://w3c.github.io/touch-events/#widl-Touch-identifier>
327#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
328pub struct TouchId(pub i32);
329
330/// Distinguishes the kind of physical input that produced a [`TouchEvent`].
331/// Servo routes both pen and finger-touch input through the touch event path,
332/// but the originating subtype determines the `pointerType` reported to script.
333#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
334pub enum TouchPointerType {
335    Pen,
336    Touch,
337}
338
339#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)]
340pub struct TouchEvent {
341    pub event_type: TouchEventType,
342    pub touch_id: TouchId,
343    pub point: WebViewPoint,
344    pub pointer_type: TouchPointerType,
345    /// cancelable default value is true, once the first move has been processed by script disable it.
346    cancelable: bool,
347    /// Whether this `touchend` should generate the compatibility mouse events.
348    pub can_synthesize_mouse_events: bool,
349}
350
351impl TouchEvent {
352    pub fn new(
353        event_type: TouchEventType,
354        touch_id: TouchId,
355        point: WebViewPoint,
356        pointer_type: TouchPointerType,
357    ) -> Self {
358        TouchEvent {
359            event_type,
360            touch_id,
361            point,
362            pointer_type,
363            cancelable: true,
364            can_synthesize_mouse_events: false,
365        }
366    }
367
368    #[doc(hidden)]
369    pub fn disable_cancelable(&mut self) {
370        self.cancelable = false;
371    }
372
373    #[doc(hidden)]
374    pub fn is_cancelable(&self) -> bool {
375        self.cancelable
376    }
377}
378
379/// Unit of a [`WheelDelta`].
380#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
381pub enum WheelMode {
382    /// Delta values are specified in pixels.
383    DeltaPixel = 0x00,
384    /// Delta values are specified in lines.
385    DeltaLine = 0x01,
386    /// Delta values are specified in pages.
387    DeltaPage = 0x02,
388}
389
390/// The wheel event deltas for every direction.
391#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
392pub struct WheelDelta {
393    /// Delta in the left/right direction. A positive value means that the view scrolls left,
394    /// revealing more content to the left of the current viewport.
395    pub x: f64,
396    /// Delta in the up/down direction. A positive value means that the view scrolls up, revealing
397    /// more content above the current viewport.
398    pub y: f64,
399    /// Delta in the direction going into/out of the screen
400    pub z: f64,
401    /// Mode to measure the floats in
402    pub mode: WheelMode,
403}
404
405#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)]
406pub struct WheelEvent {
407    pub delta: WheelDelta,
408    pub point: WebViewPoint,
409}
410
411impl WheelEvent {
412    pub fn new(delta: WheelDelta, point: WebViewPoint) -> Self {
413        WheelEvent { delta, point }
414    }
415}
416
417/// The types of an input method event.
418#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
419pub enum ImeEvent {
420    Composition(CompositionEvent),
421    Dismissed,
422}
423
424#[cfg(feature = "gamepad")]
425#[derive(
426    Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize,
427)]
428/// Index of gamepad in list of system's connected gamepads.
429pub struct GamepadIndex(pub usize);
430
431#[cfg(feature = "gamepad")]
432#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
433/// The minimum and maximum values that can be reported for axis or button input from this gamepad.
434pub struct GamepadInputBounds {
435    /// Minimum and maximum axis values.
436    pub axis_bounds: (f64, f64),
437    /// Minimum and maximum button values.
438    pub button_bounds: (f64, f64),
439}
440
441#[cfg(feature = "gamepad")]
442#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
443/// The haptic effects supported by this gamepad.
444pub struct GamepadSupportedHapticEffects {
445    /// Whether gamepad has support for dual rumble effects.
446    pub supports_dual_rumble: bool,
447    /// Whether gamepad has support for trigger rumble effects.
448    pub supports_trigger_rumble: bool,
449}
450
451#[cfg(feature = "gamepad")]
452#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
453/// The types of Gamepad event.
454pub enum GamepadEvent {
455    /// A new gamepad has been connected.
456    ///
457    /// <https://www.w3.org/TR/gamepad/#event-gamepadconnected>
458    Connected(
459        GamepadIndex,
460        String,
461        GamepadInputBounds,
462        GamepadSupportedHapticEffects,
463    ),
464    /// An existing gamepad has been disconnected.
465    ///
466    /// <https://www.w3.org/TR/gamepad/#event-gamepaddisconnected>
467    Disconnected(GamepadIndex),
468    /// An existing gamepad has been updated.
469    ///
470    /// <https://www.w3.org/TR/gamepad/#receiving-inputs>
471    Updated(GamepadIndex, GamepadUpdateType),
472}
473
474#[cfg(feature = "gamepad")]
475#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
476/// The type of Gamepad input being updated.
477pub enum GamepadUpdateType {
478    /// Axis index and input value.
479    ///
480    /// <https://www.w3.org/TR/gamepad/#dfn-represents-a-standard-gamepad-axis>
481    Axis(usize, f64),
482    /// Button index and input value.
483    ///
484    /// <https://www.w3.org/TR/gamepad/#dfn-represents-a-standard-gamepad-button>
485    Button(usize, f64),
486}