ul_next/
event.rs

1//! Events that can be fired in [`View`](crate::view::View)s.
2
3use std::sync::Arc;
4
5use crate::{error::CreationError, key_code::VirtualKeyCode, string::UlString, Library};
6
7#[derive(Clone, Copy)]
8/// The type of the [`KeyEvent`].
9pub enum KeyEventType {
10    /// Raw Key-Down type. Use this when a physical key is pressed.
11    ///
12    /// You should use `RawKeyDown` for physical key presses since it allows the renderer to
13    /// handle accelerator command translation.
14    RawKeyDown = ul_sys::ULKeyEventType_kKeyEventType_RawKeyDown as isize,
15
16    /// Key-Down event type. (Does not trigger accelerator commands in WebCore)
17    /// (eg, Ctrl+C for copy is an accelerator command).
18    ///
19    /// You should probably use `RawKeyDown` instead when a physical key is pressed.
20    /// This type is only here for historic compatibility with WebCore's key event types.
21    KeyDown = ul_sys::ULKeyEventType_kKeyEventType_KeyDown as isize,
22
23    /// Key-Up event type. Use this when a physical key is released.
24    KeyUp = ul_sys::ULKeyEventType_kKeyEventType_KeyUp as isize,
25
26    /// Character input event type. Use this when the OS generates text from a physical key being
27    /// pressed (for example, this maps to `WM_CHAR` on Windows).
28    Char = ul_sys::ULKeyEventType_kKeyEventType_Char as isize,
29}
30
31/// Modifiers that can be pressed with a key.
32pub struct KeyEventModifiers {
33    /// Whether or not an ALT key is down
34    pub alt: bool,
35    /// Whether or not a Control key is down
36    pub ctrl: bool,
37    /// Whether or not a meta key (Command-key on Mac, Windows-key on Win) is down
38    pub meta: bool,
39    /// Whether or not a Shift key is down
40    pub shift: bool,
41}
42
43impl KeyEventModifiers {
44    fn to_u32(&self) -> u32 {
45        let mut n = 0;
46
47        if self.alt {
48            n |= 1 << 0;
49        }
50        if self.ctrl {
51            n |= 1 << 1;
52        }
53        if self.meta {
54            n |= 1 << 2;
55        }
56        if self.shift {
57            n |= 1 << 3;
58        }
59
60        n
61    }
62}
63
64/// Wrapper around all arguments needed to create a [`KeyEvent`].
65pub struct KeyEventCreationInfo<'a, 'b> {
66    /// The type of the event.
67    pub ty: KeyEventType,
68
69    /// The modifiers that were pressed with the key.
70    pub modifiers: KeyEventModifiers,
71
72    /// The virtual key-code associated with this keyboard event.
73    /// This is either directly from the event (ie, WPARAM on Windows) or via a
74    /// mapping function.
75    pub virtual_key_code: VirtualKeyCode,
76
77    /// The actual key-code generated by the platform.
78    /// The DOM spec primarily uses Windows-equivalent codes
79    /// (hence `virtual_key_code` above) but it helps to also specify the
80    /// platform-specific key-code as well.
81    pub native_key_code: i32,
82
83    /// The actual text generated by this keyboard event.
84    /// This is usually only a single character.
85    pub text: &'a str,
86
87    /// The text generated by this keyboard event before
88    /// all modifiers except shift are applied. This is used internally for
89    /// working out shortcut keys. This is usually only a single character.
90    pub unmodified_text: &'b str,
91    /// Whether or not this is a keypad event.
92    pub is_keypad: bool,
93    /// Whether or not this was generated as the result
94    /// of an auto-repeat (eg, holding down a key)
95    pub is_auto_repeat: bool,
96    /// Whether or not the pressed key is a "system key".
97    /// This is a Windows-only concept and should be "false" for all
98    /// non-Windows platforms. For more information, see the following link:
99    ///   <http://msdn.microsoft.com/en-us/library/ms646286(VS.85).aspx>
100    pub is_system_key: bool,
101}
102
103/// A generic keyboard event, that can be used to fire a key event in a
104/// `view` by [`View::fire_key_event`](crate::view::View::fire_key_event).
105pub struct KeyEvent {
106    lib: Arc<Library>,
107    internal: ul_sys::ULKeyEvent,
108}
109
110impl KeyEvent {
111    /// Create a new `KeyEvent`.
112    ///
113    /// # Arguments
114    /// * `lib` - The ultralight library.
115    /// * `creation_info` - The information needed to create the key event.
116    pub fn new(
117        lib: Arc<Library>,
118        creation_info: KeyEventCreationInfo,
119    ) -> Result<KeyEvent, CreationError> {
120        let ul_string_text = unsafe { UlString::from_str(lib.clone(), creation_info.text) }?;
121        let ul_string_unmodified_text =
122            unsafe { UlString::from_str(lib.clone(), creation_info.unmodified_text) }?;
123
124        let internal = unsafe {
125            lib.ultralight().ulCreateKeyEvent(
126                creation_info.ty as u32,
127                creation_info.modifiers.to_u32(),
128                creation_info.virtual_key_code.into(),
129                creation_info.native_key_code,
130                ul_string_text.to_ul(),
131                ul_string_unmodified_text.to_ul(),
132                creation_info.is_keypad,
133                creation_info.is_auto_repeat,
134                creation_info.is_system_key,
135            )
136        };
137
138        if internal.is_null() {
139            Err(CreationError::NullReference)
140        } else {
141            Ok(Self { lib, internal })
142        }
143    }
144
145    /// Returns the underlying [`ul_sys::ULKeyEvent`] struct, to be used locally for
146    /// calling the underlying C API.
147    pub(crate) unsafe fn to_ul(&self) -> ul_sys::ULKeyEvent {
148        self.internal
149    }
150}
151
152impl Drop for KeyEvent {
153    fn drop(&mut self) {
154        unsafe {
155            self.lib.ultralight().ulDestroyKeyEvent(self.internal);
156        }
157    }
158}
159
160#[derive(Clone, Copy)]
161/// The type of the [`MouseEvent`].
162pub enum MouseEventType {
163    /// Mouse moved event type
164    MouseMoved = ul_sys::ULMouseEventType_kMouseEventType_MouseMoved as isize,
165    /// Mouse button pressed event type
166    MouseDown = ul_sys::ULMouseEventType_kMouseEventType_MouseDown as isize,
167    /// Mouse button released event type
168    MouseUp = ul_sys::ULMouseEventType_kMouseEventType_MouseUp as isize,
169}
170
171#[derive(Clone, Copy)]
172/// The type of button that was pressed or released.
173pub enum MouseButton {
174    None = ul_sys::ULMouseButton_kMouseButton_None as isize,
175    Left = ul_sys::ULMouseButton_kMouseButton_Left as isize,
176    Middle = ul_sys::ULMouseButton_kMouseButton_Middle as isize,
177    Right = ul_sys::ULMouseButton_kMouseButton_Right as isize,
178}
179
180/// A generic mouse event, that can be used to fire a key event in a
181/// `view` by [`View::fire_mouse_event`](crate::view::View::fire_mouse_event).
182pub struct MouseEvent {
183    lib: Arc<Library>,
184    internal: ul_sys::ULMouseEvent,
185}
186
187impl MouseEvent {
188    /// Create a new `MouseEvent`.
189    ///
190    /// # Arguments
191    /// * `lib` - The ultralight library.
192    /// * `ty` - The type of the event.
193    /// * `x` - The x-position of the mouse. relative to the view.
194    /// * `y` - The y-position of the mouse. relative to the view.
195    /// * `button` - The button that was pressed or released if any.
196    pub fn new(
197        lib: Arc<Library>,
198        ty: MouseEventType,
199        x: i32,
200        y: i32,
201        button: MouseButton,
202    ) -> Result<MouseEvent, CreationError> {
203        let internal = unsafe {
204            lib.ultralight()
205                .ulCreateMouseEvent(ty as u32, x, y, button as u32)
206        };
207
208        if internal.is_null() {
209            Err(CreationError::NullReference)
210        } else {
211            Ok(Self { lib, internal })
212        }
213    }
214
215    /// Returns the underlying [`ul_sys::ULMouseEvent`] struct, to be used locally for
216    /// calling the underlying C API.
217    pub(crate) unsafe fn to_ul(&self) -> ul_sys::ULMouseEvent {
218        self.internal
219    }
220}
221
222impl Drop for MouseEvent {
223    fn drop(&mut self) {
224        unsafe {
225            self.lib.ultralight().ulDestroyMouseEvent(self.internal);
226        }
227    }
228}
229
230#[derive(Clone, Copy)]
231/// The type of the [`ScrollEvent`].
232pub enum ScrollEventType {
233    /// The delta value is interpreted as number of pixels
234    ScrollByPixel = ul_sys::ULScrollEventType_kScrollEventType_ScrollByPixel as isize,
235    /// The delta value is interpreted as number of pages
236    ScrollByPage = ul_sys::ULScrollEventType_kScrollEventType_ScrollByPage as isize,
237}
238
239/// A generic scroll event, that can be used to fire a key event in a
240/// `view` by [`View::fire_scroll_event`](crate::view::View::fire_scroll_event).
241pub struct ScrollEvent {
242    lib: Arc<Library>,
243    internal: ul_sys::ULScrollEvent,
244}
245
246impl ScrollEvent {
247    /// Create a new `ScrollEvent`.
248    ///
249    /// # Arguments
250    /// * `lib` - The ultralight library.
251    /// * `ty` - The type of the event.
252    /// * `delta_x` - The horizontal scroll amount.
253    /// * `delta_y` - The vertical scroll amount.
254    pub fn new(
255        lib: Arc<Library>,
256        ty: ScrollEventType,
257        delta_x: i32,
258        delta_y: i32,
259    ) -> Result<ScrollEvent, CreationError> {
260        let internal = unsafe {
261            lib.ultralight()
262                .ulCreateScrollEvent(ty as u32, delta_x, delta_y)
263        };
264
265        if internal.is_null() {
266            Err(CreationError::NullReference)
267        } else {
268            Ok(Self { lib, internal })
269        }
270    }
271
272    /// Returns the underlying [`ul_sys::ULScrollEvent`] struct, to be used locally for
273    /// calling the underlying C API.
274    pub(crate) unsafe fn to_ul(&self) -> ul_sys::ULScrollEvent {
275        self.internal
276    }
277}
278
279impl Drop for ScrollEvent {
280    fn drop(&mut self) {
281        unsafe {
282            self.lib.ultralight().ulDestroyScrollEvent(self.internal);
283        }
284    }
285}
286
287#[derive(Clone, Copy)]
288/// The type of the [`GamepadEvent`].
289pub enum GamepadEventType {
290    /// This event type should be fired when a gamepad is connected
291    ///
292    /// Note: You will need to previously declare the gamepad, its index, and details about
293    ///  its axis and button layout via [`Renderer::set_gamepad_details`][crate::renderer::Renderer::set_gamepad_details]
294    ///  prior to calling [`Renderer::fire_gamepad_event`][crate::renderer::Renderer::fire_gamepad_event].
295    Connected = ul_sys::ULGamepadEventType_kGamepadEventType_Connected as isize,
296    /// This event type should be fired when a gamepad is disconnected.
297    Disconnected = ul_sys::ULGamepadEventType_kGamepadEventType_Disconnected as isize,
298}
299
300/// Event representing a change in gamepad connection state
301///
302/// See [`Renderer::fire_gamepad_event`][crate::renderer::Renderer::fire_gamepad_event].
303pub struct GamepadEvent {
304    lib: Arc<Library>,
305    internal: ul_sys::ULGamepadEvent,
306}
307
308impl GamepadEvent {
309    /// Create a new `GamepadEvent`.
310    ///
311    /// # Arguments
312    /// * `lib` - The ultralight library.
313    /// * `index` - The index of the gamepad, this should match the value previously set in
314    ///   [`Renderer::set_gamepad_details`][crate::renderer::Renderer::set_gamepad_details].
315    /// * `ty` - The type of this GamepadEvent.
316    pub fn new(
317        lib: Arc<Library>,
318        index: u32,
319        ty: GamepadEventType,
320    ) -> Result<GamepadEvent, CreationError> {
321        let internal = unsafe { lib.ultralight().ulCreateGamepadEvent(index, ty as u32) };
322
323        if internal.is_null() {
324            Err(CreationError::NullReference)
325        } else {
326            Ok(Self { lib, internal })
327        }
328    }
329
330    /// Returns the underlying [`ul_sys::ULGamepadEvent`] struct, to be used locally for
331    /// calling the underlying C API.
332    pub(crate) unsafe fn to_ul(&self) -> ul_sys::ULGamepadEvent {
333        self.internal
334    }
335}
336
337impl Drop for GamepadEvent {
338    fn drop(&mut self) {
339        unsafe {
340            self.lib.ultralight().ulDestroyGamepadEvent(self.internal);
341        }
342    }
343}
344
345/// Event representing a change in gamepad axis state (eg, pressing a stick in a certain direction).
346///
347/// See [`Renderer::fire_gamepad_axis_event`][crate::renderer::Renderer::fire_gamepad_axis_event].
348pub struct GamepadAxisEvent {
349    lib: Arc<Library>,
350    internal: ul_sys::ULGamepadAxisEvent,
351}
352
353impl GamepadAxisEvent {
354    /// Create a new `GamepadAxisEvent`.
355    ///
356    /// # Arguments
357    /// * `lib` - The ultralight library.
358    /// * `index` - The index of the gamepad, this should match the value previously set in
359    ///   [`Renderer::set_gamepad_details`][crate::renderer::Renderer::set_gamepad_details].
360    /// * `axis_index` - The index of the axis whose value has changed.
361    ///   This value should be in the range previously set in [`Renderer::set_gamepad_details`][crate::renderer::Renderer::set_gamepad_details].
362    /// * `value` - The new value of the axis. This value should be normalized to the range [-1.0, 1.0].
363    pub fn new(
364        lib: Arc<Library>,
365        index: u32,
366        axis_index: u32,
367        value: f64,
368    ) -> Result<GamepadAxisEvent, CreationError> {
369        let internal = unsafe {
370            lib.ultralight()
371                .ulCreateGamepadAxisEvent(index, axis_index, value)
372        };
373
374        if internal.is_null() {
375            Err(CreationError::NullReference)
376        } else {
377            Ok(Self { lib, internal })
378        }
379    }
380
381    /// Returns the underlying [`ul_sys::ULGamepadAxisEvent`] struct, to be used locally for
382    /// calling the underlying C API.
383    pub(crate) unsafe fn to_ul(&self) -> ul_sys::ULGamepadAxisEvent {
384        self.internal
385    }
386}
387
388impl Drop for GamepadAxisEvent {
389    fn drop(&mut self) {
390        unsafe {
391            self.lib
392                .ultralight()
393                .ulDestroyGamepadAxisEvent(self.internal);
394        }
395    }
396}
397
398/// Event representing a change in gamepad button state (eg, pressing a button on a gamepad).
399///
400/// See [`Renderer::fire_gamepad_button_event`][crate::renderer::Renderer::fire_gamepad_button_event].
401pub struct GamepadButtonEvent {
402    lib: Arc<Library>,
403    internal: ul_sys::ULGamepadButtonEvent,
404}
405
406impl GamepadButtonEvent {
407    /// Create a new `GamepadButtonEvent`.
408    ///
409    /// # Arguments
410    /// * `lib` - The ultralight library.
411    /// * `index` - The index of the gamepad, this should match the value previously set in
412    ///   [`Renderer::set_gamepad_details`][crate::renderer::Renderer::set_gamepad_details].
413    /// * `button_index` - The index of the button whose value has changed.
414    ///   This value should be in the range previously set in [`Renderer::set_gamepad_details`][crate::renderer::Renderer::set_gamepad_details].
415    /// * `value` - The new value of the axis. This value should be normalized to the range [-1.0, 1.0].
416    ///   with any value greater than 0.0 to be considered "pressed".
417    pub fn new(
418        lib: Arc<Library>,
419        index: u32,
420        button_index: u32,
421        value: f64,
422    ) -> Result<GamepadButtonEvent, CreationError> {
423        let internal = unsafe {
424            lib.ultralight()
425                .ulCreateGamepadButtonEvent(index, button_index, value)
426        };
427
428        if internal.is_null() {
429            Err(CreationError::NullReference)
430        } else {
431            Ok(Self { lib, internal })
432        }
433    }
434
435    /// Returns the underlying [`ul_sys::ULGamepadButtonEvent`] struct, to be used locally for
436    /// calling the underlying C API.
437    pub(crate) unsafe fn to_ul(&self) -> ul_sys::ULGamepadButtonEvent {
438        self.internal
439    }
440}
441
442impl Drop for GamepadButtonEvent {
443    fn drop(&mut self) {
444        unsafe {
445            self.lib
446                .ultralight()
447                .ulDestroyGamepadButtonEvent(self.internal);
448        }
449    }
450}