use webcore::value::Reference;
use webcore::try_from::TryInto;
use webapi::event::{IEvent, Event};
pub(crate) fn get_event_modifier_state< T: IEvent >( event: &T, key: ModifierKey ) -> bool {
js!(
return @{event.as_ref()}.getModifierState( @{
match key {
ModifierKey::Alt => "Alt",
ModifierKey::AltGr => "AltGraph",
ModifierKey::CapsLock => "CapsLock",
ModifierKey::Ctrl => "Control",
ModifierKey::Function => "Fn",
ModifierKey::FunctionLock => "FnLock",
ModifierKey::Hyper => "Hyper",
ModifierKey::Meta => "Meta",
ModifierKey::NumLock => "NumLock",
ModifierKey::OS => "OS",
ModifierKey::ScrollLock => "ScrollLock",
ModifierKey::Shift => "Shift",
ModifierKey::Super => "Super",
ModifierKey::Symbol => "Symbol",
ModifierKey::SymbolLock => "SymbolLock",
}
} );
).try_into().unwrap()
}
pub trait IKeyboardEvent: IEvent {
#[inline]
fn alt_key( &self ) -> bool {
js!(
return @{self.as_ref()}.altKey;
).try_into().unwrap()
}
#[inline]
fn code( &self ) -> String {
js!(
return @{self.as_ref()}.code;
).try_into().unwrap()
}
#[inline]
fn ctrl_key( &self ) -> bool {
js!(
return @{self.as_ref()}.ctrlKey;
).try_into().unwrap()
}
#[inline]
fn get_modifier_state( &self, key: ModifierKey ) -> bool {
get_event_modifier_state( self, key )
}
#[inline]
fn is_composing( &self ) -> bool {
js!(
return @{self.as_ref()}.isComposing;
).try_into().unwrap()
}
fn location( &self ) -> KeyboardLocation {
match js!(
return @{self.as_ref()}.location;
).try_into().unwrap() {
0 => KeyboardLocation::Standard,
1 => KeyboardLocation::Left,
2 => KeyboardLocation::Right,
3 => KeyboardLocation::Numpad,
4 => KeyboardLocation::Mobile,
5 => KeyboardLocation::Joystick,
_ => unreachable!("Unexpected KeyboardEvent.location value"),
}
}
#[inline]
fn key( &self ) -> String {
js!(
return @{self.as_ref()}.key;
).into_string().unwrap()
}
#[inline]
fn meta_key( &self ) -> bool {
js!(
return @{self.as_ref()}.metaKey;
).try_into().unwrap()
}
#[inline]
fn repeat( &self ) -> bool {
js!(
return @{self.as_ref()}.repeat;
).try_into().unwrap()
}
#[inline]
fn shift_key( &self ) -> bool {
js!(
return @{self.as_ref()}.shiftKey;
).try_into().unwrap()
}
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ModifierKey {
Alt,
AltGr,
CapsLock,
Ctrl,
Function,
FunctionLock,
Hyper,
Meta,
NumLock,
OS,
ScrollLock,
Shift,
Super,
Symbol,
SymbolLock,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum KeyboardLocation {
Standard,
Left,
Right,
Numpad,
Mobile,
Joystick,
}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "KeyboardEvent")]
#[reference(subclass_of(Event))]
pub struct KeyboardEvent( Reference );
impl IEvent for KeyboardEvent {}
impl IKeyboardEvent for KeyboardEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "KeyboardEvent")]
#[reference(event = "keypress")]
#[reference(subclass_of(Event, KeyboardEvent))]
pub struct KeyPressEvent( Reference );
impl IEvent for KeyPressEvent {}
impl IKeyboardEvent for KeyPressEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "KeyboardEvent")]
#[reference(event = "keydown")]
#[reference(subclass_of(Event, KeyboardEvent))]
pub struct KeyDownEvent( Reference );
impl IEvent for KeyDownEvent {}
impl IKeyboardEvent for KeyDownEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "KeyboardEvent")]
#[reference(event = "keyup")]
#[reference(subclass_of(Event, KeyboardEvent))]
pub struct KeyUpEvent( Reference );
impl IEvent for KeyUpEvent {}
impl IKeyboardEvent for KeyUpEvent {}
#[cfg(all(test, feature = "web_test"))]
mod tests {
use super::*;
use webapi::event::ConcreteEvent;
#[test]
fn test_keyboard_event() {
let event: KeyboardEvent = js!(
return new KeyboardEvent(
@{KeyPressEvent::EVENT_TYPE},
{
key: "A",
code: "KeyA",
location: 0,
ctrlKey: true,
shiftKey: false,
altKey: true,
metaKey: false,
repeat: true,
isComposing: false
}
);
).try_into().unwrap();
assert!( event.alt_key() );
assert_eq!( event.code(), "KeyA" );
assert!( event.ctrl_key() );
assert!( event.get_modifier_state( ModifierKey::Alt ) );
assert!( event.get_modifier_state( ModifierKey::Ctrl ) );
assert!( !event.get_modifier_state( ModifierKey::Shift ) );
assert!( !event.is_composing() );
assert_eq!( event.location(), KeyboardLocation::Standard );
assert_eq!( event.key(), "A" );
assert!( !event.meta_key() );
assert!( event.repeat() );
assert!( !event.shift_key() );
}
#[test]
fn test_keypress_event() {
let event: KeyPressEvent = js!(
return new KeyboardEvent( @{KeyPressEvent::EVENT_TYPE} );
).try_into().unwrap();
assert_eq!( event.event_type(), KeyPressEvent::EVENT_TYPE );
}
#[test]
fn test_keydown_event_is_only_constructible_from_a_keydown_event() {
let event: Option< KeyDownEvent > = js!(
return new KeyboardEvent( "keydown" );
).try_into().ok();
assert!( event.is_some() );
let event: Option< KeyDownEvent > = js!(
return new KeyboardEvent( "keyup" );
).try_into().ok();
assert!( event.is_none() );
}
}