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, 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, 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, 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, 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    InsertNewline,
124    InsertParagraph,
125    InsertText(String),
126    MoveCursor(EditingDirection, EditingMotion, ModifySelection),
127    SelectAll,
128}
129
130impl InputEvent {
131    pub fn point(&self) -> Option<WebViewPoint> {
132        match self {
133            InputEvent::EditingAction(..) => None,
134            #[cfg(feature = "gamepad")]
135            InputEvent::Gamepad(..) => None,
136            InputEvent::Ime(..) => None,
137            InputEvent::Keyboard(..) => None,
138            InputEvent::MouseButton(event) => Some(event.point),
139            InputEvent::MouseMove(event) => Some(event.point),
140            InputEvent::MouseLeftViewport(_) => None,
141            InputEvent::Touch(event) => Some(event.point),
142            InputEvent::Wheel(event) => Some(event.point),
143        }
144    }
145}
146
147#[derive(Clone, Debug, Default, Deserialize, Serialize)]
148pub struct KeyboardEvent {
149    pub event: ::keyboard_types::KeyboardEvent,
150}
151
152impl KeyboardEvent {
153    pub fn new(keyboard_event: ::keyboard_types::KeyboardEvent) -> Self {
154        Self {
155            event: keyboard_event,
156        }
157    }
158
159    pub fn new_without_event(
160        state: KeyState,
161        key: Key,
162        code: Code,
163        location: Location,
164        modifiers: Modifiers,
165        repeat: bool,
166        is_composing: bool,
167    ) -> Self {
168        Self::new(::keyboard_types::KeyboardEvent {
169            state,
170            key,
171            code,
172            location,
173            modifiers,
174            repeat,
175            is_composing,
176        })
177    }
178
179    pub fn from_state_and_key(state: KeyState, key: Key) -> Self {
180        Self::new(::keyboard_types::KeyboardEvent {
181            state,
182            key,
183            ..::keyboard_types::KeyboardEvent::default()
184        })
185    }
186}
187
188#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
189pub struct MouseButtonEvent {
190    pub action: MouseButtonAction,
191    pub button: MouseButton,
192    pub point: WebViewPoint,
193}
194
195impl MouseButtonEvent {
196    pub fn new(action: MouseButtonAction, button: MouseButton, point: WebViewPoint) -> Self {
197        Self {
198            action,
199            button,
200            point,
201        }
202    }
203}
204
205/// The types of mouse buttons.
206///
207/// <https://w3c.github.io/pointerevents/#the-button-property>
208#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
209pub enum MouseButton {
210    #[doc(hidden)]
211    None,
212    Primary,
213    Auxiliary,
214    Secondary,
215    Back,
216    Forward,
217    Other(u16),
218}
219
220impl<T: Into<i128>> From<T> for MouseButton {
221    fn from(value: T) -> Self {
222        let value = value.into();
223        match value {
224            -1 => MouseButton::None,
225            0 => MouseButton::Primary,
226            1 => MouseButton::Auxiliary,
227            2 => MouseButton::Secondary,
228            3 => MouseButton::Back,
229            4 => MouseButton::Forward,
230            _ => MouseButton::Other(value as u16),
231        }
232    }
233}
234
235impl From<MouseButton> for i16 {
236    fn from(value: MouseButton) -> Self {
237        match value {
238            MouseButton::None => -1,
239            MouseButton::Primary => 0,
240            MouseButton::Auxiliary => 1,
241            MouseButton::Secondary => 2,
242            MouseButton::Back => 3,
243            MouseButton::Forward => 4,
244            MouseButton::Other(value) => value as i16,
245        }
246    }
247}
248
249/// The types of mouse events.
250#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
251pub enum MouseButtonAction {
252    /// Mouse button down.
253    Down,
254    /// Mouse button up.
255    Up,
256}
257
258#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
259pub struct MouseMoveEvent {
260    pub point: WebViewPoint,
261    #[doc(hidden)]
262    // An internal flag used to avoid refreshing the cursor in response to move
263    // events for touch devices since they are simulated in Servo using mouse events.
264    pub is_compatibility_event_for_touch: bool,
265}
266
267impl MouseMoveEvent {
268    pub fn new(point: WebViewPoint) -> Self {
269        Self {
270            point,
271            is_compatibility_event_for_touch: false,
272        }
273    }
274
275    #[doc(hidden)]
276    pub fn new_compatibility_for_touch(point: WebViewPoint) -> Self {
277        Self {
278            point,
279            is_compatibility_event_for_touch: true,
280        }
281    }
282}
283
284#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)]
285pub struct MouseLeftViewportEvent {
286    pub focus_moving_to_another_iframe: bool,
287}
288
289/// The type of input represented by a multi-touch event.
290#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
291pub enum TouchEventType {
292    /// A new touch point came in contact with the screen.
293    Down,
294    /// An existing touch point changed location.
295    Move,
296    /// A touch point was removed from the screen.
297    Up,
298    /// The system stopped tracking a touch point.
299    Cancel,
300}
301
302/// An opaque identifier for a touch point.
303///
304/// <http://w3c.github.io/touch-events/#widl-Touch-identifier>
305#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
306pub struct TouchId(pub i32);
307
308/// Distinguishes the kind of physical input that produced a [`TouchEvent`].
309/// Servo routes both pen and finger-touch input through the touch event path,
310/// but the originating subtype determines the `pointerType` reported to script.
311#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
312pub enum TouchPointerType {
313    Pen,
314    Touch,
315}
316
317#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
318pub struct TouchEvent {
319    pub event_type: TouchEventType,
320    pub touch_id: TouchId,
321    pub point: WebViewPoint,
322    pub pointer_type: TouchPointerType,
323    /// cancelable default value is true, once the first move has been processed by script disable it.
324    cancelable: bool,
325}
326
327impl TouchEvent {
328    pub fn new(
329        event_type: TouchEventType,
330        touch_id: TouchId,
331        point: WebViewPoint,
332        pointer_type: TouchPointerType,
333    ) -> Self {
334        TouchEvent {
335            event_type,
336            touch_id,
337            point,
338            pointer_type,
339            cancelable: true,
340        }
341    }
342
343    #[doc(hidden)]
344    pub fn disable_cancelable(&mut self) {
345        self.cancelable = false;
346    }
347
348    #[doc(hidden)]
349    pub fn is_cancelable(&self) -> bool {
350        self.cancelable
351    }
352}
353
354/// Unit of a [`WheelDelta`].
355#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
356pub enum WheelMode {
357    /// Delta values are specified in pixels.
358    DeltaPixel = 0x00,
359    /// Delta values are specified in lines.
360    DeltaLine = 0x01,
361    /// Delta values are specified in pages.
362    DeltaPage = 0x02,
363}
364
365/// The wheel event deltas for every direction.
366#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
367pub struct WheelDelta {
368    /// Delta in the left/right direction. A positive value means that the view scrolls left,
369    /// revealing more content to the left of the current viewport.
370    pub x: f64,
371    /// Delta in the up/down direction. A positive value means that the view scrolls up, revealing
372    /// more content above the current viewport.
373    pub y: f64,
374    /// Delta in the direction going into/out of the screen
375    pub z: f64,
376    /// Mode to measure the floats in
377    pub mode: WheelMode,
378}
379
380#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
381pub struct WheelEvent {
382    pub delta: WheelDelta,
383    pub point: WebViewPoint,
384}
385
386impl WheelEvent {
387    pub fn new(delta: WheelDelta, point: WebViewPoint) -> Self {
388        WheelEvent { delta, point }
389    }
390}
391
392/// The types of an input method event.
393#[derive(Clone, Debug, Deserialize, Serialize)]
394pub enum ImeEvent {
395    Composition(CompositionEvent),
396    Dismissed,
397}
398
399#[cfg(feature = "gamepad")]
400#[derive(
401    Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize,
402)]
403/// Index of gamepad in list of system's connected gamepads.
404pub struct GamepadIndex(pub usize);
405
406#[cfg(feature = "gamepad")]
407#[derive(Clone, Debug, Deserialize, Serialize)]
408/// The minimum and maximum values that can be reported for axis or button input from this gamepad.
409pub struct GamepadInputBounds {
410    /// Minimum and maximum axis values.
411    pub axis_bounds: (f64, f64),
412    /// Minimum and maximum button values.
413    pub button_bounds: (f64, f64),
414}
415
416#[cfg(feature = "gamepad")]
417#[derive(Clone, Debug, Deserialize, Serialize)]
418/// The haptic effects supported by this gamepad.
419pub struct GamepadSupportedHapticEffects {
420    /// Whether gamepad has support for dual rumble effects.
421    pub supports_dual_rumble: bool,
422    /// Whether gamepad has support for trigger rumble effects.
423    pub supports_trigger_rumble: bool,
424}
425
426#[cfg(feature = "gamepad")]
427#[derive(Clone, Debug, Deserialize, Serialize)]
428/// The types of Gamepad event.
429pub enum GamepadEvent {
430    /// A new gamepad has been connected.
431    ///
432    /// <https://www.w3.org/TR/gamepad/#event-gamepadconnected>
433    Connected(
434        GamepadIndex,
435        String,
436        GamepadInputBounds,
437        GamepadSupportedHapticEffects,
438    ),
439    /// An existing gamepad has been disconnected.
440    ///
441    /// <https://www.w3.org/TR/gamepad/#event-gamepaddisconnected>
442    Disconnected(GamepadIndex),
443    /// An existing gamepad has been updated.
444    ///
445    /// <https://www.w3.org/TR/gamepad/#receiving-inputs>
446    Updated(GamepadIndex, GamepadUpdateType),
447}
448
449#[cfg(feature = "gamepad")]
450#[derive(Clone, Debug, Deserialize, Serialize)]
451/// The type of Gamepad input being updated.
452pub enum GamepadUpdateType {
453    /// Axis index and input value.
454    ///
455    /// <https://www.w3.org/TR/gamepad/#dfn-represents-a-standard-gamepad-axis>
456    Axis(usize, f64),
457    /// Button index and input value.
458    ///
459    /// <https://www.w3.org/TR/gamepad/#dfn-represents-a-standard-gamepad-button>
460    Button(usize, f64),
461}