yew_stdweb/services/keyboard.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
//! Service to register key press event listeners on elements.
use crate::callback::Callback;
use cfg_if::cfg_if;
use cfg_match::cfg_match;
use std::fmt;
cfg_if! {
if #[cfg(feature = "std_web")] {
use stdweb::web::event::{ConcreteEvent, KeyDownEvent, KeyPressEvent, KeyUpEvent};
use stdweb::web::{EventListenerHandle, IEventTarget};
} else if #[cfg(feature = "web_sys")] {
use gloo::events::{EventListener, EventListenerOptions};
use wasm_bindgen::JsCast;
use web_sys::{Event, EventTarget, KeyboardEvent};
}
}
/// Service for registering callbacks on elements to get keystrokes from the user.
///
/// # Note
/// Elements which natively support keyboard input (such as `<input/>` or `<textarea/>`) can use the
/// `onkeypress` or `oninput` attributes from within the html macro. You **should use those events
/// instead** of locating the element and registering an event listener using this service.
///
/// This service is for adding key event listeners to elements which don't support these attributes,
/// (for example the `document` and `<canvas>` elements).
#[derive(Debug)]
pub struct KeyboardService {}
/// Handle for the key event listener.
///
/// When the handle goes out of scope, the listener will be removed from the element.
#[must_use = "the listener is only active until the handle is dropped"]
pub struct KeyListenerHandle(
#[cfg(feature = "std_web")] Option<EventListenerHandle>,
#[cfg(feature = "web_sys")] EventListener,
);
impl fmt::Debug for KeyListenerHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("KeyListenerHandle")
}
}
impl KeyboardService {
/// Registers a callback which listens to KeyPressEvents on a provided element.
///
/// # Documentation
/// [keypress event](https://developer.mozilla.org/en-US/docs/Web/API/Document/keypress_event)
///
/// # Warning
/// This API has been deprecated in the HTML standard and it is not recommended for use in new projects.
/// Consult the browser compatibility chart in the linked MDN documentation.
pub fn register_key_press<
#[cfg(feature = "std_web")] T: IEventTarget,
#[cfg(feature = "web_sys")] T: AsRef<EventTarget>,
>(
element: &T,
#[cfg(feature = "std_web")] callback: Callback<KeyPressEvent>,
#[cfg(feature = "web_sys")] callback: Callback<KeyboardEvent>,
) -> KeyListenerHandle {
cfg_match! {
feature = "std_web" => register_key_impl(element, callback),
feature = "web_sys" => register_key_impl(element, callback, "keypress"),
}
}
/// Registers a callback which listens to KeyDownEvents on a provided element.
///
/// # Documentation
/// [keydown event](https://developer.mozilla.org/en-US/docs/Web/API/Document/keydown_event)
///
/// # Note
/// This browser feature is relatively new and is set to replace the `keypress` event.
/// It may not be fully supported in all browsers.
/// Consult the browser compatibility chart in the linked MDN documentation.
pub fn register_key_down<
#[cfg(feature = "std_web")] T: IEventTarget,
#[cfg(feature = "web_sys")] T: AsRef<EventTarget>,
>(
element: &T,
#[cfg(feature = "std_web")] callback: Callback<KeyDownEvent>,
#[cfg(feature = "web_sys")] callback: Callback<KeyboardEvent>,
) -> KeyListenerHandle {
cfg_match! {
feature = "std_web" => register_key_impl(element, callback),
feature = "web_sys" => register_key_impl(element, callback, "keydown"),
}
}
/// Registers a callback that listens to KeyUpEvents on a provided element.
///
/// # Documentation
/// [keyup event](https://developer.mozilla.org/en-US/docs/Web/API/Document/keyup_event)
///
/// # Note
/// This browser feature is relatively new and is set to replace keypress events.
/// It may not be fully supported in all browsers.
/// Consult the browser compatibility chart in the linked MDN documentation.
pub fn register_key_up<
#[cfg(feature = "std_web")] T: IEventTarget,
#[cfg(feature = "web_sys")] T: AsRef<EventTarget>,
>(
element: &T,
#[cfg(feature = "std_web")] callback: Callback<KeyUpEvent>,
#[cfg(feature = "web_sys")] callback: Callback<KeyboardEvent>,
) -> KeyListenerHandle {
cfg_match! {
feature = "std_web" => register_key_impl(element, callback),
feature = "web_sys" => register_key_impl(element, callback, "keyup"),
}
}
}
#[cfg(feature = "std_web")]
fn register_key_impl<T: IEventTarget, E: 'static + ConcreteEvent>(
element: &T,
callback: Callback<E>,
) -> KeyListenerHandle {
let handle = element.add_event_listener(move |event: E| {
callback.emit(event);
});
cfg_match! {
feature = "std_web" => KeyListenerHandle(Some(handle)),
feature = "web_sys" => KeyListenerHandle(handle),
}
}
#[cfg(feature = "web_sys")]
fn register_key_impl<T: AsRef<EventTarget>>(
element: &T,
callback: Callback<KeyboardEvent>,
event: &'static str,
) -> KeyListenerHandle {
let listener = move |event: &Event| {
let event = event
.dyn_ref::<KeyboardEvent>()
.expect("wrong event type")
.clone();
callback.emit(event);
};
let options = EventListenerOptions::enable_prevent_default();
KeyListenerHandle(EventListener::new_with_options(
element.as_ref(),
event,
options,
listener,
))
}
#[cfg(feature = "std_web")]
impl Drop for KeyListenerHandle {
fn drop(&mut self) {
if let Some(handle) = self.0.take() {
handle.remove()
} else {
panic!("Tried to drop KeyListenerHandle twice")
}
}
}