stdweb/webapi/events/
keyboard.rs

1use webcore::value::Reference;
2use webcore::try_from::TryInto;
3use webapi::event::{IEvent, Event};
4
5// Used by KeyboardEvent and MouseEvent to get the state of a modifier key.
6pub(crate) fn get_event_modifier_state< T: IEvent >( event: &T, key: ModifierKey ) -> bool {
7    js!(
8        return @{event.as_ref()}.getModifierState( @{
9            match key {
10                ModifierKey::Alt => "Alt",
11                ModifierKey::AltGr => "AltGraph",
12                ModifierKey::CapsLock => "CapsLock",
13                ModifierKey::Ctrl => "Control",
14                ModifierKey::Function => "Fn",
15                ModifierKey::FunctionLock => "FnLock",
16                ModifierKey::Hyper => "Hyper",
17                ModifierKey::Meta => "Meta",
18                ModifierKey::NumLock => "NumLock",
19                ModifierKey::OS => "OS",
20                ModifierKey::ScrollLock => "ScrollLock",
21                ModifierKey::Shift => "Shift",
22                ModifierKey::Super => "Super",
23                ModifierKey::Symbol => "Symbol",
24                ModifierKey::SymbolLock => "SymbolLock",
25            }
26        } );
27    ).try_into().unwrap()
28}
29
30/// `IKeyboardEvent` objects describe a user interaction with the
31/// keyboard. Each event describes a key; the event type identifies
32/// what kind of activity was performed.
33///
34/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent)
35// https://w3c.github.io/uievents/#keyboardevent
36pub trait IKeyboardEvent: IEvent {
37    /// Indicates whether the Alt key was down when this event was fired.
38    ///
39    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/altKey)
40    // https://w3c.github.io/uievents/#ref-for-dom-keyboardevent-altkey-3
41    #[inline]
42    fn alt_key( &self ) -> bool {
43        js!(
44            return @{self.as_ref()}.altKey;
45        ).try_into().unwrap()
46    }
47
48    /// Returns a code value that indicates the physical key pressed on the keyboard.
49    ///
50    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code)
51    // https://w3c.github.io/uievents/#ref-for-dom-keyboardevent-code-3
52    #[inline]
53    fn code( &self ) -> String {
54        js!(
55            return @{self.as_ref()}.code;
56        ).try_into().unwrap()
57    }
58
59    /// Returns whether the Ctrl key was down when this event was fired.
60    ///
61    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/ctrlKey)
62    // https://w3c.github.io/uievents/#ref-for-dom-keyboardevent-ctrlkey-3
63    #[inline]
64    fn ctrl_key( &self ) -> bool {
65        js!(
66            return @{self.as_ref()}.ctrlKey;
67        ).try_into().unwrap()
68    }
69
70
71    /// Returns whether a modifier key was down when this event was fired.
72    ///
73    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/getModifierState)
74    // https://w3c.github.io/uievents/#ref-for-dom-keyboardevent-getmodifierstate-19
75    #[inline]
76    fn get_modifier_state( &self, key: ModifierKey ) -> bool {
77        get_event_modifier_state( self, key )
78    }
79
80    /// Returns whether this event was fired during composition.
81    ///
82    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/isComposing)
83    // https://w3c.github.io/uievents/#ref-for-dom-keyboardevent-iscomposing-1
84    #[inline]
85    fn is_composing( &self ) -> bool {
86        js!(
87            return @{self.as_ref()}.isComposing;
88        ).try_into().unwrap()
89    }
90
91    /// Returns the location of the key on the keyboard.
92    ///
93    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/location)
94    // https://w3c.github.io/uievents/#ref-for-dom-keyboardevent-location-1
95    fn location( &self ) -> KeyboardLocation {
96        match js!(
97            return @{self.as_ref()}.location;
98        ).try_into().unwrap() {
99            0 => KeyboardLocation::Standard,
100            1 => KeyboardLocation::Left,
101            2 => KeyboardLocation::Right,
102            3 => KeyboardLocation::Numpad,
103            4 => KeyboardLocation::Mobile,
104            5 => KeyboardLocation::Joystick,
105            _ => unreachable!("Unexpected KeyboardEvent.location value"),
106        }
107    }
108
109    /// Returns the value of a key or keys pressed by the user.
110    ///
111    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key)
112    // https://w3c.github.io/uievents/#ref-for-dom-keyboardevent-key-4
113    #[inline]
114    fn key( &self ) -> String {
115        js!(
116            return @{self.as_ref()}.key;
117        ).into_string().unwrap()
118    }
119
120    /// Indicates whether the Meta key was down when this event was fired.
121    ///
122    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/metaKey)
123    // https://w3c.github.io/uievents/#ref-for-dom-keyboardevent-metakey-3
124    #[inline]
125    fn meta_key( &self ) -> bool {
126        js!(
127            return @{self.as_ref()}.metaKey;
128        ).try_into().unwrap()
129    }
130
131    /// Indicates whether the key is held down such that it is repeating.
132    ///
133    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat)
134    // https://w3c.github.io/uievents/#ref-for-dom-keyboardevent-repeat-1
135    #[inline]
136    fn repeat( &self ) -> bool {
137        js!(
138            return @{self.as_ref()}.repeat;
139        ).try_into().unwrap()
140    }
141
142    /// Indicates whether the Shift key was down when this event was fired.
143    ///
144    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/shiftKey)
145    // https://w3c.github.io/uievents/#ref-for-dom-keyboardevent-shiftkey-3
146    #[inline]
147    fn shift_key( &self ) -> bool {
148        js!(
149            return @{self.as_ref()}.shiftKey;
150        ).try_into().unwrap()
151    }
152}
153
154/// A modifier key on the keyboard.
155#[allow(missing_docs)]
156#[derive(Clone, Copy, Debug, Eq, PartialEq)]
157pub enum ModifierKey {
158    Alt,
159    AltGr,
160    CapsLock,
161    Ctrl,
162    Function,
163    FunctionLock,
164    Hyper,
165    Meta,
166    NumLock,
167    OS,
168    ScrollLock,
169    Shift,
170    Super,
171    Symbol,
172    SymbolLock,
173}
174
175/// The location on the keyboard of a key.
176#[derive(Clone, Copy, Debug, Eq, PartialEq)]
177pub enum KeyboardLocation {
178    /// The key has only one version, or the location can't be distinguished.
179    Standard,
180    /// The left-hand version of a key.
181    Left,
182    /// The right-hand version of a key.
183    Right,
184    /// The key was on a numeric pad.
185    Numpad,
186    /// The key was on a mobile device.
187    Mobile,
188    /// The key was on a joystick.
189    Joystick,
190}
191
192/// A reference to a JavaScript object which implements the [IKeyboardEvent](trait.IKeyboardEvent.html)
193/// interface.
194///
195/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent)
196// https://w3c.github.io/uievents/#keyboardevent
197#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
198#[reference(instance_of = "KeyboardEvent")]
199#[reference(subclass_of(Event))]
200pub struct KeyboardEvent( Reference );
201
202impl IEvent for KeyboardEvent {}
203impl IKeyboardEvent for KeyboardEvent {}
204
205/// The `KeyPressEvent` is fired when a key is pressed down. It's only
206/// fired for keys which produce a character value.
207///
208/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/Events/keypress)
209// https://w3c.github.io/uievents/#keypress
210#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
211#[reference(instance_of = "KeyboardEvent")]
212#[reference(event = "keypress")]
213#[reference(subclass_of(Event, KeyboardEvent))]
214pub struct KeyPressEvent( Reference );
215
216impl IEvent for KeyPressEvent {}
217impl IKeyboardEvent for KeyPressEvent {}
218
219/// The `KeyDownEvent` is fired when a key is pressed down.
220/// Unlike the `KeyPressEvent` event it's also fired for keys which
221/// do not produce a character value.
222///
223/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/Events/keydown)
224// https://w3c.github.io/uievents/#event-type-keydown
225#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
226#[reference(instance_of = "KeyboardEvent")]
227#[reference(event = "keydown")]
228#[reference(subclass_of(Event, KeyboardEvent))]
229pub struct KeyDownEvent( Reference );
230
231impl IEvent for KeyDownEvent {}
232impl IKeyboardEvent for KeyDownEvent {}
233
234/// The `KeyUpEvent` is fired when a key is released.
235///
236/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/Events/keyup)
237// https://w3c.github.io/uievents/#event-type-keyup
238#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
239#[reference(instance_of = "KeyboardEvent")]
240#[reference(event = "keyup")]
241#[reference(subclass_of(Event, KeyboardEvent))]
242pub struct KeyUpEvent( Reference );
243
244impl IEvent for KeyUpEvent {}
245impl IKeyboardEvent for KeyUpEvent {}
246
247#[cfg(all(test, feature = "web_test"))]
248mod tests {
249    use super::*;
250    use webapi::event::ConcreteEvent;
251
252    #[test]
253    fn test_keyboard_event() {
254        let event: KeyboardEvent = js!(
255            return new KeyboardEvent(
256                @{KeyPressEvent::EVENT_TYPE},
257                {
258                    key: "A",
259                    code: "KeyA",
260                    location: 0,
261                    ctrlKey: true,
262                    shiftKey: false,
263                    altKey: true,
264                    metaKey: false,
265                    repeat: true,
266                    isComposing: false
267                }
268            );
269        ).try_into().unwrap();
270        assert!( event.alt_key() );
271        assert_eq!( event.code(), "KeyA" );
272        assert!( event.ctrl_key() );
273        assert!( event.get_modifier_state( ModifierKey::Alt ) );
274        assert!( event.get_modifier_state( ModifierKey::Ctrl ) );
275        assert!( !event.get_modifier_state( ModifierKey::Shift ) );
276        assert!( !event.is_composing() );
277        assert_eq!( event.location(), KeyboardLocation::Standard );
278        assert_eq!( event.key(), "A" );
279        assert!( !event.meta_key() );
280        assert!( event.repeat() );
281        assert!( !event.shift_key() );
282    }
283
284    #[test]
285    fn test_keypress_event() {
286        let event: KeyPressEvent = js!(
287            return new KeyboardEvent( @{KeyPressEvent::EVENT_TYPE} );
288        ).try_into().unwrap();
289        assert_eq!( event.event_type(), KeyPressEvent::EVENT_TYPE );
290    }
291
292    #[test]
293    fn test_keydown_event_is_only_constructible_from_a_keydown_event() {
294        let event: Option< KeyDownEvent > = js!(
295            return new KeyboardEvent( "keydown" );
296        ).try_into().ok();
297        assert!( event.is_some() );
298
299        let event: Option< KeyDownEvent > = js!(
300            return new KeyboardEvent( "keyup" );
301        ).try_into().ok();
302        assert!( event.is_none() );
303    }
304}