yew_stdweb/services/
keyboard.rs1use crate::callback::Callback;
4use cfg_if::cfg_if;
5use cfg_match::cfg_match;
6use std::fmt;
7cfg_if! {
8 if #[cfg(feature = "std_web")] {
9 use stdweb::web::event::{ConcreteEvent, KeyDownEvent, KeyPressEvent, KeyUpEvent};
10 use stdweb::web::{EventListenerHandle, IEventTarget};
11 } else if #[cfg(feature = "web_sys")] {
12 use gloo::events::{EventListener, EventListenerOptions};
13 use wasm_bindgen::JsCast;
14 use web_sys::{Event, EventTarget, KeyboardEvent};
15 }
16}
17
18#[derive(Debug)]
28pub struct KeyboardService {}
29
30#[must_use = "the listener is only active until the handle is dropped"]
34pub struct KeyListenerHandle(
35 #[cfg(feature = "std_web")] Option<EventListenerHandle>,
36 #[cfg(feature = "web_sys")] EventListener,
37);
38
39impl fmt::Debug for KeyListenerHandle {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 f.write_str("KeyListenerHandle")
42 }
43}
44
45impl KeyboardService {
46 pub fn register_key_press<
55 #[cfg(feature = "std_web")] T: IEventTarget,
56 #[cfg(feature = "web_sys")] T: AsRef<EventTarget>,
57 >(
58 element: &T,
59 #[cfg(feature = "std_web")] callback: Callback<KeyPressEvent>,
60 #[cfg(feature = "web_sys")] callback: Callback<KeyboardEvent>,
61 ) -> KeyListenerHandle {
62 cfg_match! {
63 feature = "std_web" => register_key_impl(element, callback),
64 feature = "web_sys" => register_key_impl(element, callback, "keypress"),
65 }
66 }
67
68 pub fn register_key_down<
78 #[cfg(feature = "std_web")] T: IEventTarget,
79 #[cfg(feature = "web_sys")] T: AsRef<EventTarget>,
80 >(
81 element: &T,
82 #[cfg(feature = "std_web")] callback: Callback<KeyDownEvent>,
83 #[cfg(feature = "web_sys")] callback: Callback<KeyboardEvent>,
84 ) -> KeyListenerHandle {
85 cfg_match! {
86 feature = "std_web" => register_key_impl(element, callback),
87 feature = "web_sys" => register_key_impl(element, callback, "keydown"),
88 }
89 }
90
91 pub fn register_key_up<
101 #[cfg(feature = "std_web")] T: IEventTarget,
102 #[cfg(feature = "web_sys")] T: AsRef<EventTarget>,
103 >(
104 element: &T,
105 #[cfg(feature = "std_web")] callback: Callback<KeyUpEvent>,
106 #[cfg(feature = "web_sys")] callback: Callback<KeyboardEvent>,
107 ) -> KeyListenerHandle {
108 cfg_match! {
109 feature = "std_web" => register_key_impl(element, callback),
110 feature = "web_sys" => register_key_impl(element, callback, "keyup"),
111 }
112 }
113}
114
115#[cfg(feature = "std_web")]
116fn register_key_impl<T: IEventTarget, E: 'static + ConcreteEvent>(
117 element: &T,
118 callback: Callback<E>,
119) -> KeyListenerHandle {
120 let handle = element.add_event_listener(move |event: E| {
121 callback.emit(event);
122 });
123 cfg_match! {
124 feature = "std_web" => KeyListenerHandle(Some(handle)),
125 feature = "web_sys" => KeyListenerHandle(handle),
126 }
127}
128
129#[cfg(feature = "web_sys")]
130fn register_key_impl<T: AsRef<EventTarget>>(
131 element: &T,
132 callback: Callback<KeyboardEvent>,
133 event: &'static str,
134) -> KeyListenerHandle {
135 let listener = move |event: &Event| {
136 let event = event
137 .dyn_ref::<KeyboardEvent>()
138 .expect("wrong event type")
139 .clone();
140 callback.emit(event);
141 };
142 let options = EventListenerOptions::enable_prevent_default();
143 KeyListenerHandle(EventListener::new_with_options(
144 element.as_ref(),
145 event,
146 options,
147 listener,
148 ))
149}
150
151#[cfg(feature = "std_web")]
152impl Drop for KeyListenerHandle {
153 fn drop(&mut self) {
154 if let Some(handle) = self.0.take() {
155 handle.remove()
156 } else {
157 panic!("Tried to drop KeyListenerHandle twice")
158 }
159 }
160}