fune/servo/components/script/dom/keyboardevent.rs
Josh Matthews 57518b13d8 servo: Merge #11950 - Support non-QWERTY keyboards (from jdm:keylayout2); r=emilio
Using the ReceivedCharacter event from glutin, we can obtain the actual key characters that the user is pressing and releasing. This gets passed to the script thread along with the physical key data, since KeyboardEvent needs both pieces of information, where they get merged into a single logical key that gets processed by clients like TextInput without any special changes.

Tested by switching my macbook keyboard to dvorak and looking at the output of keypress/keyup/keydown event listeners, as well as playing with tests/html/textarea.html. Non-content keybindings like reload work as expected, too - the remapped keybinding triggers the reload action.

---
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #4144
- [X] These changes do not require tests because I can't think of a way to test remapped keyboard input

Fixes  #11991.

Source-Repo: https://github.com/servo/servo
Source-Revision: 68fb9ebc413f9cfc1ad4ca578d904c164836db74
2016-07-06 02:51:50 -07:00

859 lines
29 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::KeyboardEventBinding;
use dom::bindings::codegen::Bindings::KeyboardEventBinding::{KeyboardEventConstants, KeyboardEventMethods};
use dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{Root, RootedReference};
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::event::Event;
use dom::uievent::UIEvent;
use dom::window::Window;
use msg::constellation_msg;
use msg::constellation_msg::{Key, KeyModifiers};
use std::borrow::Cow;
use std::cell::Cell;
no_jsmanaged_fields!(Key);
#[dom_struct]
pub struct KeyboardEvent {
uievent: UIEvent,
key: Cell<Option<Key>>,
key_string: DOMRefCell<DOMString>,
code: DOMRefCell<DOMString>,
location: Cell<u32>,
ctrl: Cell<bool>,
alt: Cell<bool>,
shift: Cell<bool>,
meta: Cell<bool>,
repeat: Cell<bool>,
is_composing: Cell<bool>,
char_code: Cell<Option<u32>>,
key_code: Cell<u32>,
printable: Cell<Option<char>>,
}
impl KeyboardEvent {
fn new_inherited() -> KeyboardEvent {
KeyboardEvent {
uievent: UIEvent::new_inherited(),
key: Cell::new(None),
key_string: DOMRefCell::new(DOMString::new()),
code: DOMRefCell::new(DOMString::new()),
location: Cell::new(0),
ctrl: Cell::new(false),
alt: Cell::new(false),
shift: Cell::new(false),
meta: Cell::new(false),
repeat: Cell::new(false),
is_composing: Cell::new(false),
char_code: Cell::new(None),
key_code: Cell::new(0),
printable: Cell::new(None),
}
}
pub fn new_uninitialized(window: &Window) -> Root<KeyboardEvent> {
reflect_dom_object(box KeyboardEvent::new_inherited(),
GlobalRef::Window(window),
KeyboardEventBinding::Wrap)
}
pub fn new(window: &Window,
type_: DOMString,
canBubble: bool,
cancelable: bool,
view: Option<&Window>,
_detail: i32,
ch: Option<char>,
key: Option<Key>,
key_string: DOMString,
code: DOMString,
location: u32,
repeat: bool,
isComposing: bool,
ctrlKey: bool,
altKey: bool,
shiftKey: bool,
metaKey: bool,
char_code: Option<u32>,
key_code: u32) -> Root<KeyboardEvent> {
let ev = KeyboardEvent::new_uninitialized(window);
ev.InitKeyboardEvent(type_, canBubble, cancelable, view, key_string, location,
DOMString::new(), repeat, DOMString::new());
ev.key.set(key);
*ev.code.borrow_mut() = code;
ev.ctrl.set(ctrlKey);
ev.alt.set(altKey);
ev.shift.set(shiftKey);
ev.meta.set(metaKey);
ev.char_code.set(char_code);
ev.printable.set(ch);
ev.key_code.set(key_code);
ev.is_composing.set(isComposing);
ev
}
pub fn Constructor(global: GlobalRef,
type_: DOMString,
init: &KeyboardEventBinding::KeyboardEventInit) -> Fallible<Root<KeyboardEvent>> {
let event = KeyboardEvent::new(global.as_window(), type_,
init.parent.parent.parent.bubbles,
init.parent.parent.parent.cancelable,
init.parent.parent.view.r(),
init.parent.parent.detail,
None,
key_from_string(&init.key, init.location),
init.key.clone(), init.code.clone(), init.location,
init.repeat, init.isComposing, init.parent.ctrlKey,
init.parent.altKey, init.parent.shiftKey, init.parent.metaKey,
None, 0);
Ok(event)
}
pub fn key_properties(ch: Option<char>, key: Key, mods: KeyModifiers)
-> KeyEventProperties {
KeyEventProperties {
key_string: key_value(ch, key, mods),
code: code_value(key),
location: key_location(key),
char_code: ch.map(|ch| ch as u32),
key_code: key_keycode(key),
}
}
}
impl KeyboardEvent {
pub fn printable(&self) -> Option<char> {
self.printable.get()
}
pub fn get_key(&self) -> Option<Key> {
self.key.get().clone()
}
pub fn get_key_modifiers(&self) -> KeyModifiers {
let mut result = KeyModifiers::empty();
if self.shift.get() {
result = result | constellation_msg::SHIFT;
}
if self.ctrl.get() {
result = result | constellation_msg::CONTROL;
}
if self.alt.get() {
result = result | constellation_msg::ALT;
}
if self.meta.get() {
result = result | constellation_msg::SUPER;
}
result
}
}
// https://w3c.github.io/uievents-key/#key-value-tables
pub fn key_value(ch: Option<char>, key: Key, mods: KeyModifiers) -> Cow<'static, str> {
if let Some(ch) = ch {
return Cow::from(format!("{}", ch));
}
let shift = mods.contains(constellation_msg::SHIFT);
Cow::from(match key {
Key::Space => " ",
Key::Apostrophe if shift => "\"",
Key::Apostrophe => "'",
Key::Comma if shift => "<",
Key::Comma => ",",
Key::Minus if shift => "_",
Key::Minus => "-",
Key::Period if shift => ">",
Key::Period => ".",
Key::Slash if shift => "?",
Key::Slash => "/",
Key::GraveAccent if shift => "~",
Key::GraveAccent => "`",
Key::Num0 if shift => ")",
Key::Num0 => "0",
Key::Num1 if shift => "!",
Key::Num1 => "1",
Key::Num2 if shift => "@",
Key::Num2 => "2",
Key::Num3 if shift => "#",
Key::Num3 => "3",
Key::Num4 if shift => "$",
Key::Num4 => "4",
Key::Num5 if shift => "%",
Key::Num5 => "5",
Key::Num6 if shift => "^",
Key::Num6 => "6",
Key::Num7 if shift => "&",
Key::Num7 => "7",
Key::Num8 if shift => "*",
Key::Num8 => "8",
Key::Num9 if shift => "(",
Key::Num9 => "9",
Key::Semicolon if shift => ":",
Key::Semicolon => ";",
Key::Equal if shift => "+",
Key::Equal => "=",
Key::A if shift => "A",
Key::A => "a",
Key::B if shift => "B",
Key::B => "b",
Key::C if shift => "C",
Key::C => "c",
Key::D if shift => "D",
Key::D => "d",
Key::E if shift => "E",
Key::E => "e",
Key::F if shift => "F",
Key::F => "f",
Key::G if shift => "G",
Key::G => "g",
Key::H if shift => "H",
Key::H => "h",
Key::I if shift => "I",
Key::I => "i",
Key::J if shift => "J",
Key::J => "j",
Key::K if shift => "K",
Key::K => "k",
Key::L if shift => "L",
Key::L => "l",
Key::M if shift => "M",
Key::M => "m",
Key::N if shift => "N",
Key::N => "n",
Key::O if shift => "O",
Key::O => "o",
Key::P if shift => "P",
Key::P => "p",
Key::Q if shift => "Q",
Key::Q => "q",
Key::R if shift => "R",
Key::R => "r",
Key::S if shift => "S",
Key::S => "s",
Key::T if shift => "T",
Key::T => "t",
Key::U if shift => "U",
Key::U => "u",
Key::V if shift => "V",
Key::V => "v",
Key::W if shift => "W",
Key::W => "w",
Key::X if shift => "X",
Key::X => "x",
Key::Y if shift => "Y",
Key::Y => "y",
Key::Z if shift => "Z",
Key::Z => "z",
Key::LeftBracket if shift => "{",
Key::LeftBracket => "[",
Key::Backslash if shift => "|",
Key::Backslash => "\\",
Key::RightBracket if shift => "}",
Key::RightBracket => "]",
Key::World1 => "Unidentified",
Key::World2 => "Unidentified",
Key::Escape => "Escape",
Key::Enter => "Enter",
Key::Tab => "Tab",
Key::Backspace => "Backspace",
Key::Insert => "Insert",
Key::Delete => "Delete",
Key::Right => "ArrowRight",
Key::Left => "ArrowLeft",
Key::Down => "ArrowDown",
Key::Up => "ArrowUp",
Key::PageUp => "PageUp",
Key::PageDown => "PageDown",
Key::Home => "Home",
Key::End => "End",
Key::CapsLock => "CapsLock",
Key::ScrollLock => "ScrollLock",
Key::NumLock => "NumLock",
Key::PrintScreen => "PrintScreen",
Key::Pause => "Pause",
Key::F1 => "F1",
Key::F2 => "F2",
Key::F3 => "F3",
Key::F4 => "F4",
Key::F5 => "F5",
Key::F6 => "F6",
Key::F7 => "F7",
Key::F8 => "F8",
Key::F9 => "F9",
Key::F10 => "F10",
Key::F11 => "F11",
Key::F12 => "F12",
Key::F13 => "F13",
Key::F14 => "F14",
Key::F15 => "F15",
Key::F16 => "F16",
Key::F17 => "F17",
Key::F18 => "F18",
Key::F19 => "F19",
Key::F20 => "F20",
Key::F21 => "F21",
Key::F22 => "F22",
Key::F23 => "F23",
Key::F24 => "F24",
Key::F25 => "F25",
Key::Kp0 => "0",
Key::Kp1 => "1",
Key::Kp2 => "2",
Key::Kp3 => "3",
Key::Kp4 => "4",
Key::Kp5 => "5",
Key::Kp6 => "6",
Key::Kp7 => "7",
Key::Kp8 => "8",
Key::Kp9 => "9",
Key::KpDecimal => ".",
Key::KpDivide => "/",
Key::KpMultiply => "*",
Key::KpSubtract => "-",
Key::KpAdd => "+",
Key::KpEnter => "Enter",
Key::KpEqual => "=",
Key::LeftShift => "Shift",
Key::LeftControl => "Control",
Key::LeftAlt => "Alt",
Key::LeftSuper => "Super",
Key::RightShift => "Shift",
Key::RightControl => "Control",
Key::RightAlt => "Alt",
Key::RightSuper => "Super",
Key::Menu => "ContextMenu",
Key::NavigateForward => "BrowserForward",
Key::NavigateBackward => "BrowserBack",
})
}
fn key_from_string(key_string: &str, location: u32) -> Option<Key> {
match key_string {
" " => Some(Key::Space),
"\"" => Some(Key::Apostrophe),
"'" => Some(Key::Apostrophe),
"<" => Some(Key::Comma),
"," => Some(Key::Comma),
"_" => Some(Key::Minus),
"-" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Minus),
">" => Some(Key::Period),
"." if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Period),
"?" => Some(Key::Slash),
"/" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Slash),
"~" => Some(Key::GraveAccent),
"`" => Some(Key::GraveAccent),
")" => Some(Key::Num0),
"0" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num0),
"!" => Some(Key::Num1),
"1" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num1),
"@" => Some(Key::Num2),
"2" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num2),
"#" => Some(Key::Num3),
"3" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num3),
"$" => Some(Key::Num4),
"4" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num4),
"%" => Some(Key::Num5),
"5" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num5),
"^" => Some(Key::Num6),
"6" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num6),
"&" => Some(Key::Num7),
"7" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num7),
"*" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num8),
"8" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num8),
"(" => Some(Key::Num9),
"9" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num9),
":" => Some(Key::Semicolon),
";" => Some(Key::Semicolon),
"+" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Equal),
"=" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Equal),
"A" => Some(Key::A),
"a" => Some(Key::A),
"B" => Some(Key::B),
"b" => Some(Key::B),
"C" => Some(Key::C),
"c" => Some(Key::C),
"D" => Some(Key::D),
"d" => Some(Key::D),
"E" => Some(Key::E),
"e" => Some(Key::E),
"F" => Some(Key::F),
"f" => Some(Key::F),
"G" => Some(Key::G),
"g" => Some(Key::G),
"H" => Some(Key::H),
"h" => Some(Key::H),
"I" => Some(Key::I),
"i" => Some(Key::I),
"J" => Some(Key::J),
"j" => Some(Key::J),
"K" => Some(Key::K),
"k" => Some(Key::K),
"L" => Some(Key::L),
"l" => Some(Key::L),
"M" => Some(Key::M),
"m" => Some(Key::M),
"N" => Some(Key::N),
"n" => Some(Key::N),
"O" => Some(Key::O),
"o" => Some(Key::O),
"P" => Some(Key::P),
"p" => Some(Key::P),
"Q" => Some(Key::Q),
"q" => Some(Key::Q),
"R" => Some(Key::R),
"r" => Some(Key::R),
"S" => Some(Key::S),
"s" => Some(Key::S),
"T" => Some(Key::T),
"t" => Some(Key::T),
"U" => Some(Key::U),
"u" => Some(Key::U),
"V" => Some(Key::V),
"v" => Some(Key::V),
"W" => Some(Key::W),
"w" => Some(Key::W),
"X" => Some(Key::X),
"x" => Some(Key::X),
"Y" => Some(Key::Y),
"y" => Some(Key::Y),
"Z" => Some(Key::Z),
"z" => Some(Key::Z),
"{" => Some(Key::LeftBracket),
"[" => Some(Key::LeftBracket),
"|" => Some(Key::Backslash),
"\\" => Some(Key::Backslash),
"}" => Some(Key::RightBracket),
"]" => Some(Key::RightBracket),
"Escape" => Some(Key::Escape),
"Enter" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Enter),
"Tab" => Some(Key::Tab),
"Backspace" => Some(Key::Backspace),
"Insert" => Some(Key::Insert),
"Delete" => Some(Key::Delete),
"ArrowRight" => Some(Key::Right),
"ArrowLeft" => Some(Key::Left),
"ArrowDown" => Some(Key::Down),
"ArrowUp" => Some(Key::Up),
"PageUp" => Some(Key::PageUp),
"PageDown" => Some(Key::PageDown),
"Home" => Some(Key::Home),
"End" => Some(Key::End),
"CapsLock" => Some(Key::CapsLock),
"ScrollLock" => Some(Key::ScrollLock),
"NumLock" => Some(Key::NumLock),
"PrintScreen" => Some(Key::PrintScreen),
"Pause" => Some(Key::Pause),
"F1" => Some(Key::F1),
"F2" => Some(Key::F2),
"F3" => Some(Key::F3),
"F4" => Some(Key::F4),
"F5" => Some(Key::F5),
"F6" => Some(Key::F6),
"F7" => Some(Key::F7),
"F8" => Some(Key::F8),
"F9" => Some(Key::F9),
"F10" => Some(Key::F10),
"F11" => Some(Key::F11),
"F12" => Some(Key::F12),
"F13" => Some(Key::F13),
"F14" => Some(Key::F14),
"F15" => Some(Key::F15),
"F16" => Some(Key::F16),
"F17" => Some(Key::F17),
"F18" => Some(Key::F18),
"F19" => Some(Key::F19),
"F20" => Some(Key::F20),
"F21" => Some(Key::F21),
"F22" => Some(Key::F22),
"F23" => Some(Key::F23),
"F24" => Some(Key::F24),
"F25" => Some(Key::F25),
"0" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp0),
"1" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp1),
"2" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp2),
"3" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp3),
"4" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp4),
"5" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp5),
"6" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp6),
"7" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp7),
"8" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp8),
"9" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp9),
"." if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpDecimal),
"/" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpDivide),
"*" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpMultiply),
"-" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpSubtract),
"+" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpAdd),
"Enter" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpEnter),
"=" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpEqual),
"Shift" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT => Some(Key::LeftShift),
"Control" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT => Some(Key::LeftControl),
"Alt" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT => Some(Key::LeftAlt),
"Super" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT => Some(Key::LeftSuper),
"Shift" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT => Some(Key::RightShift),
"Control" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT => Some(Key::RightControl),
"Alt" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT => Some(Key::RightAlt),
"Super" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT => Some(Key::RightSuper),
"ContextMenu" => Some(Key::Menu),
"BrowserForward" => Some(Key::NavigateForward),
"BrowserBack" => Some(Key::NavigateBackward),
_ => None
}
}
// https://w3c.github.io/uievents-code/#code-value-tables
fn code_value(key: Key) -> &'static str {
match key {
Key::Space => "Space",
Key::Apostrophe => "Quote",
Key::Comma => "Comma",
Key::Minus => "Minus",
Key::Period => "Period",
Key::Slash => "Slash",
Key::GraveAccent => "Backquote",
Key::Num0 => "Digit0",
Key::Num1 => "Digit1",
Key::Num2 => "Digit2",
Key::Num3 => "Digit3",
Key::Num4 => "Digit4",
Key::Num5 => "Digit5",
Key::Num6 => "Digit6",
Key::Num7 => "Digit7",
Key::Num8 => "Digit8",
Key::Num9 => "Digit9",
Key::Semicolon => "Semicolon",
Key::Equal => "Equal",
Key::A => "KeyA",
Key::B => "KeyB",
Key::C => "KeyC",
Key::D => "KeyD",
Key::E => "KeyE",
Key::F => "KeyF",
Key::G => "KeyG",
Key::H => "KeyH",
Key::I => "KeyI",
Key::J => "KeyJ",
Key::K => "KeyK",
Key::L => "KeyL",
Key::M => "KeyM",
Key::N => "KeyN",
Key::O => "KeyO",
Key::P => "KeyP",
Key::Q => "KeyQ",
Key::R => "KeyR",
Key::S => "KeyS",
Key::T => "KeyT",
Key::U => "KeyU",
Key::V => "KeyV",
Key::W => "KeyW",
Key::X => "KeyX",
Key::Y => "KeyY",
Key::Z => "KeyZ",
Key::LeftBracket => "BracketLeft",
Key::Backslash => "Backslash",
Key::RightBracket => "BracketRight",
Key::World1 |
Key::World2 => panic!("unknown char code for {:?}", key),
Key::Escape => "Escape",
Key::Enter => "Enter",
Key::Tab => "Tab",
Key::Backspace => "Backspace",
Key::Insert => "Insert",
Key::Delete => "Delete",
Key::Right => "ArrowRight",
Key::Left => "ArrowLeft",
Key::Down => "ArrowDown",
Key::Up => "ArrowUp",
Key::PageUp => "PageUp",
Key::PageDown => "PageDown",
Key::Home => "Home",
Key::End => "End",
Key::CapsLock => "CapsLock",
Key::ScrollLock => "ScrollLock",
Key::NumLock => "NumLock",
Key::PrintScreen => "PrintScreen",
Key::Pause => "Pause",
Key::F1 => "F1",
Key::F2 => "F2",
Key::F3 => "F3",
Key::F4 => "F4",
Key::F5 => "F5",
Key::F6 => "F6",
Key::F7 => "F7",
Key::F8 => "F8",
Key::F9 => "F9",
Key::F10 => "F10",
Key::F11 => "F11",
Key::F12 => "F12",
Key::F13 => "F13",
Key::F14 => "F14",
Key::F15 => "F15",
Key::F16 => "F16",
Key::F17 => "F17",
Key::F18 => "F18",
Key::F19 => "F19",
Key::F20 => "F20",
Key::F21 => "F21",
Key::F22 => "F22",
Key::F23 => "F23",
Key::F24 => "F24",
Key::F25 => "F25",
Key::Kp0 => "Numpad0",
Key::Kp1 => "Numpad1",
Key::Kp2 => "Numpad2",
Key::Kp3 => "Numpad3",
Key::Kp4 => "Numpad4",
Key::Kp5 => "Numpad5",
Key::Kp6 => "Numpad6",
Key::Kp7 => "Numpad7",
Key::Kp8 => "Numpad8",
Key::Kp9 => "Numpad9",
Key::KpDecimal => "NumpadDecimal",
Key::KpDivide => "NumpadDivide",
Key::KpMultiply => "NumpadMultiply",
Key::KpSubtract => "NumpadSubtract",
Key::KpAdd => "NumpadAdd",
Key::KpEnter => "NumpadEnter",
Key::KpEqual => "NumpadEqual",
Key::LeftShift | Key::RightShift => "Shift",
Key::LeftControl | Key::RightControl => "Control",
Key::LeftAlt | Key::RightAlt => "Alt",
Key::LeftSuper | Key::RightSuper => "Super",
Key::Menu => "ContextMenu",
Key::NavigateForward => "BrowserForward",
Key::NavigateBackward => "BrowserBackward",
}
}
fn key_location(key: Key) -> u32 {
match key {
Key::Kp0 | Key::Kp1 | Key::Kp2 |
Key::Kp3 | Key::Kp4 | Key::Kp5 |
Key::Kp6 | Key::Kp7 | Key::Kp8 |
Key::Kp9 | Key::KpDecimal |
Key::KpDivide | Key::KpMultiply |
Key::KpSubtract | Key::KpAdd |
Key::KpEnter | Key::KpEqual =>
KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD,
Key::LeftShift | Key::LeftAlt |
Key::LeftControl | Key::LeftSuper =>
KeyboardEventConstants::DOM_KEY_LOCATION_LEFT,
Key::RightShift | Key::RightAlt |
Key::RightControl | Key::RightSuper =>
KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT,
_ => KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD,
}
}
// https://w3c.github.io/uievents/#legacy-key-models
fn key_keycode(key: Key) -> u32 {
match key {
// https://w3c.github.io/uievents/#legacy-key-models
Key::Backspace => 8,
Key::Tab => 9,
Key::Enter => 13,
Key::LeftShift | Key::RightShift => 16,
Key::LeftControl | Key::RightControl => 17,
Key::LeftAlt | Key::RightAlt => 18,
Key::CapsLock => 20,
Key::Escape => 27,
Key::Space => 32,
Key::PageUp => 33,
Key::PageDown => 34,
Key::End => 35,
Key::Home => 36,
Key::Left => 37,
Key::Up => 38,
Key::Right => 39,
Key::Down => 40,
Key::Delete => 46,
// https://w3c.github.io/uievents/#optionally-fixed-virtual-key-codes
Key::Semicolon => 186,
Key::Equal => 187,
Key::Comma => 188,
Key::Minus => 189,
Key::Period => 190,
Key::Slash => 191,
Key::LeftBracket => 219,
Key::Backslash => 220,
Key::RightBracket => 221,
Key::Apostrophe => 222,
//§ B.2.1.3
Key::Num0 |
Key::Num1 |
Key::Num2 |
Key::Num3 |
Key::Num4 |
Key::Num5 |
Key::Num6 |
Key::Num7 |
Key::Num8 |
Key::Num9 => key as u32 - Key::Num0 as u32 + '0' as u32,
//§ B.2.1.4
Key::A |
Key::B |
Key::C |
Key::D |
Key::E |
Key::F |
Key::G |
Key::H |
Key::I |
Key::J |
Key::K |
Key::L |
Key::M |
Key::N |
Key::O |
Key::P |
Key::Q |
Key::R |
Key::S |
Key::T |
Key::U |
Key::V |
Key::W |
Key::X |
Key::Y |
Key::Z => key as u32 - Key::A as u32 + 'A' as u32,
//§ B.2.1.8
_ => 0
}
}
#[derive(HeapSizeOf)]
pub struct KeyEventProperties {
pub key_string: Cow<'static, str>,
pub code: &'static str,
pub location: u32,
pub char_code: Option<u32>,
pub key_code: u32,
}
impl KeyEventProperties {
pub fn is_printable(&self) -> bool {
self.char_code.is_some()
}
}
impl KeyboardEventMethods for KeyboardEvent {
// https://w3c.github.io/uievents/#widl-KeyboardEvent-initKeyboardEvent
fn InitKeyboardEvent(&self,
typeArg: DOMString,
canBubbleArg: bool,
cancelableArg: bool,
viewArg: Option<&Window>,
keyArg: DOMString,
locationArg: u32,
_modifiersListArg: DOMString,
repeat: bool,
_locale: DOMString) {
if self.upcast::<Event>().dispatching() {
return;
}
self.upcast::<UIEvent>()
.InitUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, 0);
*self.key_string.borrow_mut() = keyArg;
self.location.set(locationArg);
self.repeat.set(repeat);
}
// https://w3c.github.io/uievents/#widl-KeyboardEvent-key
fn Key(&self) -> DOMString {
self.key_string.borrow().clone()
}
// https://w3c.github.io/uievents/#widl-KeyboardEvent-code
fn Code(&self) -> DOMString {
self.code.borrow().clone()
}
// https://w3c.github.io/uievents/#widl-KeyboardEvent-location
fn Location(&self) -> u32 {
self.location.get()
}
// https://w3c.github.io/uievents/#widl-KeyboardEvent-ctrlKey
fn CtrlKey(&self) -> bool {
self.ctrl.get()
}
// https://w3c.github.io/uievents/#widl-KeyboardEvent-shiftKey
fn ShiftKey(&self) -> bool {
self.shift.get()
}
// https://w3c.github.io/uievents/#widl-KeyboardEvent-altKey
fn AltKey(&self) -> bool {
self.alt.get()
}
// https://w3c.github.io/uievents/#widl-KeyboardEvent-metaKey
fn MetaKey(&self) -> bool {
self.meta.get()
}
// https://w3c.github.io/uievents/#widl-KeyboardEvent-repeat
fn Repeat(&self) -> bool {
self.repeat.get()
}
// https://w3c.github.io/uievents/#widl-KeyboardEvent-isComposing
fn IsComposing(&self) -> bool {
self.is_composing.get()
}
// https://w3c.github.io/uievents/#dom-keyboardevent-getmodifierstate
fn GetModifierState(&self, keyArg: DOMString) -> bool {
match &*keyArg {
"Ctrl" => self.CtrlKey(),
"Alt" => self.AltKey(),
"Shift" => self.ShiftKey(),
"Meta" => self.MetaKey(),
"AltGraph" | "CapsLock" | "NumLock" | "ScrollLock" | "Accel" |
"Fn" | "FnLock" | "Hyper" | "OS" | "Symbol" | "SymbolLock" => false, //FIXME
_ => false,
}
}
// https://w3c.github.io/uievents/#widl-KeyboardEvent-charCode
fn CharCode(&self) -> u32 {
self.char_code.get().unwrap_or(0)
}
// https://w3c.github.io/uievents/#widl-KeyboardEvent-keyCode
fn KeyCode(&self) -> u32 {
self.key_code.get()
}
// https://w3c.github.io/uievents/#widl-KeyboardEvent-which
fn Which(&self) -> u32 {
self.char_code.get().unwrap_or(self.KeyCode())
}
// https://dom.spec.whatwg.org/#dom-event-istrusted
fn IsTrusted(&self) -> bool {
self.uievent.IsTrusted()
}
}