mirror of
https://github.com/servo/servo.git
synced 2025-08-02 20:20:14 +01:00
Auto merge of #21881 - pyfisch:keyboard-types, r=paulrouget
Use keyboard-types crate Have embedders send DOM keys to servo and use a strongly typed KeyboardEvent from the W3C UI Events spec. All keyboard handling now uses the new types. Introduce a ShortcutMatcher to recognize key bindings. Shortcuts are now recognized in a uniform way. Updated the winit port. Updated webdriver integration. part of #20331 What this PR does: * allow the use non-ASCII keyboards for text input * decouple keyboard event "key" from "code" (key meaning vs location) What this PR does not do: * completely improve keyboard events send from winit and webdriver * add support for CompositionEvent or IME Notes: * The winit embedder does not send keyup events for printable keys (this is a regression) * keyboard-types is on crates.io because I believe it to be useful outside of servo. If you prefer I can add a copy in this repo. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21881) <!-- Reviewable:end -->
This commit is contained in:
commit
9a0404ac5f
35 changed files with 747 additions and 1673 deletions
|
@ -58,6 +58,7 @@ image = "0.19"
|
|||
ipc-channel = "0.11"
|
||||
itertools = "0.7.6"
|
||||
jstraceable_derive = {path = "../jstraceable_derive"}
|
||||
keyboard-types = {version = "0.4.2-servo", features = ["serde"]}
|
||||
lazy_static = "1"
|
||||
libc = "0.2"
|
||||
log = "0.4"
|
||||
|
|
|
@ -100,9 +100,10 @@ use hyper_serde::Serde;
|
|||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use js::jsapi::{JSContext, JSObject, JSRuntime};
|
||||
use js::jsapi::JS_GetRuntime;
|
||||
use keyboard_types::{Key, KeyState, Modifiers};
|
||||
use metrics::{InteractiveFlag, InteractiveMetrics, InteractiveWindow, ProfilerMetadataFactory, ProgressiveWebMetric};
|
||||
use mime::{Mime, TopLevel, SubLevel};
|
||||
use msg::constellation_msg::{BrowsingContextId, Key, KeyModifiers, KeyState};
|
||||
use msg::constellation_msg::BrowsingContextId;
|
||||
use net_traits::{FetchResponseMsg, IpcSend, ReferrerPolicy};
|
||||
use net_traits::CookieSource::NonHTTP;
|
||||
use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
|
||||
|
@ -769,10 +770,12 @@ impl Document {
|
|||
// Step 1 is not handled here; the fragid is already obtained by the calling function
|
||||
// Step 2: Simply use None to indicate the top of the document.
|
||||
// Step 3 & 4
|
||||
percent_decode(fragid.as_bytes()).decode_utf8().ok()
|
||||
// Step 5
|
||||
percent_decode(fragid.as_bytes())
|
||||
.decode_utf8()
|
||||
.ok()
|
||||
// Step 5
|
||||
.and_then(|decoded_fragid| self.get_element_by_id(&Atom::from(decoded_fragid)))
|
||||
// Step 6
|
||||
// Step 6
|
||||
.or_else(|| self.get_anchor_by_name(fragid))
|
||||
// Step 7 & 8
|
||||
}
|
||||
|
@ -805,7 +808,8 @@ impl Document {
|
|||
rect.origin.x.to_nearest_px() as f32,
|
||||
rect.origin.y.to_nearest_px() as f32,
|
||||
)
|
||||
}).or_else(|| {
|
||||
})
|
||||
.or_else(|| {
|
||||
if fragment.is_empty() || fragment.eq_ignore_ascii_case("top") {
|
||||
// FIXME(stshine): this should be the origin of the stacking context space,
|
||||
// which may differ under the influence of writing mode.
|
||||
|
@ -1348,13 +1352,7 @@ impl Document {
|
|||
}
|
||||
|
||||
/// The entry point for all key processing for web content
|
||||
pub fn dispatch_key_event(
|
||||
&self,
|
||||
ch: Option<char>,
|
||||
key: Key,
|
||||
state: KeyState,
|
||||
modifiers: KeyModifiers,
|
||||
) {
|
||||
pub fn dispatch_key_event(&self, keyboard_event: ::keyboard_types::KeyboardEvent) {
|
||||
let focused = self.get_focused_element();
|
||||
let body = self.GetBody();
|
||||
|
||||
|
@ -1364,50 +1362,29 @@ impl Document {
|
|||
(&None, &None) => self.window.upcast(),
|
||||
};
|
||||
|
||||
let ctrl = modifiers.contains(KeyModifiers::CONTROL);
|
||||
let alt = modifiers.contains(KeyModifiers::ALT);
|
||||
let shift = modifiers.contains(KeyModifiers::SHIFT);
|
||||
let meta = modifiers.contains(KeyModifiers::SUPER);
|
||||
|
||||
let is_composing = false;
|
||||
let is_repeating = state == KeyState::Repeated;
|
||||
let ev_type = DOMString::from(
|
||||
match state {
|
||||
KeyState::Pressed | KeyState::Repeated => "keydown",
|
||||
KeyState::Released => "keyup",
|
||||
}.to_owned(),
|
||||
);
|
||||
|
||||
let props = KeyboardEvent::key_properties(ch, key, modifiers);
|
||||
|
||||
let keyevent = KeyboardEvent::new(
|
||||
&self.window,
|
||||
ev_type,
|
||||
DOMString::from(keyboard_event.state.to_string()),
|
||||
true,
|
||||
true,
|
||||
Some(&self.window),
|
||||
0,
|
||||
ch,
|
||||
Some(key),
|
||||
DOMString::from(props.key_string.clone()),
|
||||
DOMString::from(props.code),
|
||||
props.location,
|
||||
is_repeating,
|
||||
is_composing,
|
||||
ctrl,
|
||||
alt,
|
||||
shift,
|
||||
meta,
|
||||
None,
|
||||
props.key_code,
|
||||
keyboard_event.key.clone(),
|
||||
DOMString::from(keyboard_event.code.to_string()),
|
||||
keyboard_event.location as u32,
|
||||
keyboard_event.repeat,
|
||||
keyboard_event.is_composing,
|
||||
keyboard_event.modifiers,
|
||||
0,
|
||||
keyboard_event.key.legacy_keycode(),
|
||||
);
|
||||
let event = keyevent.upcast::<Event>();
|
||||
event.fire(target);
|
||||
let mut cancel_state = event.get_cancel_state();
|
||||
|
||||
// https://w3c.github.io/uievents/#keys-cancelable-keys
|
||||
if state != KeyState::Released &&
|
||||
props.is_printable() &&
|
||||
if keyboard_event.state == KeyState::Down &&
|
||||
keyboard_event.key.legacy_charcode() != 0 &&
|
||||
cancel_state != EventDefault::Prevented
|
||||
{
|
||||
// https://w3c.github.io/uievents/#keypress-event-order
|
||||
|
@ -1418,18 +1395,13 @@ impl Document {
|
|||
true,
|
||||
Some(&self.window),
|
||||
0,
|
||||
ch,
|
||||
Some(key),
|
||||
DOMString::from(props.key_string),
|
||||
DOMString::from(props.code),
|
||||
props.location,
|
||||
is_repeating,
|
||||
is_composing,
|
||||
ctrl,
|
||||
alt,
|
||||
shift,
|
||||
meta,
|
||||
props.char_code,
|
||||
keyboard_event.key.clone(),
|
||||
DOMString::from(keyboard_event.code.to_string()),
|
||||
keyboard_event.location as u32,
|
||||
keyboard_event.repeat,
|
||||
keyboard_event.is_composing,
|
||||
keyboard_event.modifiers,
|
||||
keyboard_event.key.legacy_charcode(),
|
||||
0,
|
||||
);
|
||||
let ev = event.upcast::<Event>();
|
||||
|
@ -1438,7 +1410,7 @@ impl Document {
|
|||
}
|
||||
|
||||
if cancel_state == EventDefault::Allowed {
|
||||
let msg = EmbedderMsg::KeyEvent(ch, key, state, modifiers);
|
||||
let msg = EmbedderMsg::Keyboard(keyboard_event.clone());
|
||||
self.send_to_embedder(msg);
|
||||
|
||||
// This behavior is unspecced
|
||||
|
@ -1446,8 +1418,10 @@ impl Document {
|
|||
// however *when* we do it is up to us.
|
||||
// Here, we're dispatching it after the key event so the script has a chance to cancel it
|
||||
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=27337
|
||||
match key {
|
||||
Key::Space if state == KeyState::Released => {
|
||||
match keyboard_event.key {
|
||||
Key::Character(ref letter)
|
||||
if letter == " " && keyboard_event.state == KeyState::Up =>
|
||||
{
|
||||
let maybe_elem = target.downcast::<Element>();
|
||||
if let Some(el) = maybe_elem {
|
||||
synthetic_click_activation(
|
||||
|
@ -1459,11 +1433,15 @@ impl Document {
|
|||
ActivationSource::NotFromClick,
|
||||
)
|
||||
}
|
||||
},
|
||||
Key::Enter if state == KeyState::Released => {
|
||||
}
|
||||
Key::Enter if keyboard_event.state == KeyState::Up => {
|
||||
let maybe_elem = target.downcast::<Element>();
|
||||
if let Some(el) = maybe_elem {
|
||||
if let Some(a) = el.as_maybe_activatable() {
|
||||
let ctrl = keyboard_event.modifiers.contains(Modifiers::CONTROL);
|
||||
let alt = keyboard_event.modifiers.contains(Modifiers::ALT);
|
||||
let shift = keyboard_event.modifiers.contains(Modifiers::SHIFT);
|
||||
let meta = keyboard_event.modifiers.contains(Modifiers::META);
|
||||
a.implicit_submission(ctrl, alt, shift, meta);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use dom::bindings::cell::DomRefCell;
|
||||
use dom::bindings::codegen::Bindings::KeyboardEventBinding;
|
||||
use dom::bindings::codegen::Bindings::KeyboardEventBinding::{KeyboardEventConstants, KeyboardEventMethods};
|
||||
use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
|
||||
use dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods;
|
||||
use dom::bindings::error::Fallible;
|
||||
use dom::bindings::inheritance::Castable;
|
||||
|
@ -15,47 +15,39 @@ use dom::event::Event;
|
|||
use dom::uievent::UIEvent;
|
||||
use dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use msg::constellation_msg::{Key, KeyModifiers};
|
||||
use std::borrow::Cow;
|
||||
use keyboard_types::{Key, Modifiers};
|
||||
use std::cell::Cell;
|
||||
|
||||
unsafe_no_jsmanaged_fields!(Key);
|
||||
unsafe_no_jsmanaged_fields!(Modifiers);
|
||||
|
||||
#[dom_struct]
|
||||
pub struct KeyboardEvent {
|
||||
uievent: UIEvent,
|
||||
key: Cell<Option<Key>>,
|
||||
key_string: DomRefCell<DOMString>,
|
||||
key: DomRefCell<DOMString>,
|
||||
typed_key: DomRefCell<Key>,
|
||||
code: DomRefCell<DOMString>,
|
||||
location: Cell<u32>,
|
||||
ctrl: Cell<bool>,
|
||||
alt: Cell<bool>,
|
||||
shift: Cell<bool>,
|
||||
meta: Cell<bool>,
|
||||
modifiers: Cell<Modifiers>,
|
||||
repeat: Cell<bool>,
|
||||
is_composing: Cell<bool>,
|
||||
char_code: Cell<Option<u32>>,
|
||||
char_code: Cell<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()),
|
||||
key: DomRefCell::new(DOMString::new()),
|
||||
typed_key: DomRefCell::new(Key::Unidentified),
|
||||
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),
|
||||
modifiers: Cell::new(Modifiers::empty()),
|
||||
repeat: Cell::new(false),
|
||||
is_composing: Cell::new(false),
|
||||
char_code: Cell::new(None),
|
||||
char_code: Cell::new(0),
|
||||
key_code: Cell::new(0),
|
||||
printable: Cell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,18 +66,13 @@ impl KeyboardEvent {
|
|||
cancelable: bool,
|
||||
view: Option<&Window>,
|
||||
_detail: i32,
|
||||
ch: Option<char>,
|
||||
key: Option<Key>,
|
||||
key_string: DOMString,
|
||||
key: Key,
|
||||
code: DOMString,
|
||||
location: u32,
|
||||
repeat: bool,
|
||||
is_composing: bool,
|
||||
ctrl_key: bool,
|
||||
alt_key: bool,
|
||||
shift_key: bool,
|
||||
meta_key: bool,
|
||||
char_code: Option<u32>,
|
||||
modifiers: Modifiers,
|
||||
char_code: u32,
|
||||
key_code: u32,
|
||||
) -> DomRoot<KeyboardEvent> {
|
||||
let ev = KeyboardEvent::new_uninitialized(window);
|
||||
|
@ -94,22 +81,18 @@ impl KeyboardEvent {
|
|||
can_bubble,
|
||||
cancelable,
|
||||
view,
|
||||
key_string,
|
||||
DOMString::from(key.to_string()),
|
||||
location,
|
||||
DOMString::new(),
|
||||
repeat,
|
||||
DOMString::new(),
|
||||
);
|
||||
ev.key.set(key);
|
||||
*ev.typed_key.borrow_mut() = key;
|
||||
*ev.code.borrow_mut() = code;
|
||||
ev.ctrl.set(ctrl_key);
|
||||
ev.alt.set(alt_key);
|
||||
ev.shift.set(shift_key);
|
||||
ev.meta.set(meta_key);
|
||||
ev.char_code.set(char_code);
|
||||
ev.printable.set(ch);
|
||||
ev.key_code.set(key_code);
|
||||
ev.modifiers.set(modifiers);
|
||||
ev.is_composing.set(is_composing);
|
||||
ev.char_code.set(char_code);
|
||||
ev.key_code.set(key_code);
|
||||
ev
|
||||
}
|
||||
|
||||
|
@ -118,6 +101,11 @@ impl KeyboardEvent {
|
|||
type_: DOMString,
|
||||
init: &KeyboardEventBinding::KeyboardEventInit,
|
||||
) -> Fallible<DomRoot<KeyboardEvent>> {
|
||||
let mut modifiers = Modifiers::empty();
|
||||
modifiers.set(Modifiers::CONTROL, init.parent.ctrlKey);
|
||||
modifiers.set(Modifiers::ALT, init.parent.altKey);
|
||||
modifiers.set(Modifiers::SHIFT, init.parent.shiftKey);
|
||||
modifiers.set(Modifiers::META, init.parent.metaKey);
|
||||
let event = KeyboardEvent::new(
|
||||
window,
|
||||
type_,
|
||||
|
@ -125,680 +113,27 @@ impl KeyboardEvent {
|
|||
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(),
|
||||
Key::Unidentified,
|
||||
init.code.clone(),
|
||||
init.location,
|
||||
init.repeat,
|
||||
init.isComposing,
|
||||
init.parent.ctrlKey,
|
||||
init.parent.altKey,
|
||||
init.parent.shiftKey,
|
||||
init.parent.metaKey,
|
||||
None,
|
||||
modifiers,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
*event.key.borrow_mut() = init.key.clone();
|
||||
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 key(&self) -> Key {
|
||||
self.typed_key.borrow().clone()
|
||||
}
|
||||
|
||||
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 | KeyModifiers::SHIFT;
|
||||
}
|
||||
if self.ctrl.get() {
|
||||
result = result | KeyModifiers::CONTROL;
|
||||
}
|
||||
if self.alt.get() {
|
||||
result = result | KeyModifiers::ALT;
|
||||
}
|
||||
if self.meta.get() {
|
||||
result = result | KeyModifiers::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(KeyModifiers::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(MallocSizeOf)]
|
||||
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()
|
||||
pub fn modifiers(&self) -> Modifiers {
|
||||
self.modifiers.get()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -822,14 +157,14 @@ impl KeyboardEventMethods for KeyboardEvent {
|
|||
|
||||
self.upcast::<UIEvent>()
|
||||
.InitUIEvent(type_arg, can_bubble_arg, cancelable_arg, view_arg, 0);
|
||||
*self.key_string.borrow_mut() = key_arg;
|
||||
*self.key.borrow_mut() = key_arg;
|
||||
self.location.set(location_arg);
|
||||
self.repeat.set(repeat);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-key
|
||||
fn Key(&self) -> DOMString {
|
||||
self.key_string.borrow().clone()
|
||||
self.key.borrow().clone()
|
||||
}
|
||||
|
||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-code
|
||||
|
@ -844,22 +179,22 @@ impl KeyboardEventMethods for KeyboardEvent {
|
|||
|
||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-ctrlKey
|
||||
fn CtrlKey(&self) -> bool {
|
||||
self.ctrl.get()
|
||||
self.modifiers.get().contains(Modifiers::CONTROL)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-shiftKey
|
||||
fn ShiftKey(&self) -> bool {
|
||||
self.shift.get()
|
||||
self.modifiers.get().contains(Modifiers::SHIFT)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-altKey
|
||||
fn AltKey(&self) -> bool {
|
||||
self.alt.get()
|
||||
self.modifiers.get().contains(Modifiers::ALT)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-metaKey
|
||||
fn MetaKey(&self) -> bool {
|
||||
self.meta.get()
|
||||
self.modifiers.get().contains(Modifiers::META)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-repeat
|
||||
|
@ -874,20 +209,26 @@ impl KeyboardEventMethods for KeyboardEvent {
|
|||
|
||||
// https://w3c.github.io/uievents/#dom-keyboardevent-getmodifierstate
|
||||
fn GetModifierState(&self, key_arg: DOMString) -> bool {
|
||||
match &*key_arg {
|
||||
"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,
|
||||
}
|
||||
self.modifiers.get().contains(match &*key_arg {
|
||||
"Alt" => Modifiers::ALT,
|
||||
"AltGraph" => Modifiers::ALT_GRAPH,
|
||||
"CapsLock" => Modifiers::CAPS_LOCK,
|
||||
"Control" => Modifiers::CONTROL,
|
||||
"Fn" => Modifiers::FN,
|
||||
"FnLock" => Modifiers::FN_LOCK,
|
||||
"Meta" => Modifiers::META,
|
||||
"NumLock" => Modifiers::NUM_LOCK,
|
||||
"ScrollLock" => Modifiers::SCROLL_LOCK,
|
||||
"Shift" => Modifiers::SHIFT,
|
||||
"Symbol" => Modifiers::SYMBOL,
|
||||
"SymbolLock" => Modifiers::SYMBOL_LOCK,
|
||||
_ => return false,
|
||||
})
|
||||
}
|
||||
|
||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-charCode
|
||||
fn CharCode(&self) -> u32 {
|
||||
self.char_code.get().unwrap_or(0)
|
||||
self.char_code.get()
|
||||
}
|
||||
|
||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-keyCode
|
||||
|
@ -897,7 +238,11 @@ impl KeyboardEventMethods for KeyboardEvent {
|
|||
|
||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-which
|
||||
fn Which(&self) -> u32 {
|
||||
self.char_code.get().unwrap_or(self.KeyCode())
|
||||
if self.char_code.get() != 0 {
|
||||
self.char_code.get()
|
||||
} else {
|
||||
self.key_code.get()
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-istrusted
|
||||
|
|
|
@ -54,6 +54,7 @@ extern crate image;
|
|||
extern crate ipc_channel;
|
||||
#[macro_use]
|
||||
extern crate jstraceable_derive;
|
||||
extern crate keyboard_types;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate libc;
|
||||
|
|
|
@ -96,7 +96,7 @@ use script_traits::{ProgressiveWebMetricType, Painter, ScriptMsg, ScriptThreadFa
|
|||
use script_traits::{ScriptToConstellationChan, TimerEvent, TimerSchedulerMsg};
|
||||
use script_traits::{TimerSource, TouchEventType, TouchId, UntrustedNodeAddress};
|
||||
use script_traits::{UpdatePipelineIdReason, WindowSizeData, WindowSizeType};
|
||||
use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent, TouchEvent};
|
||||
use script_traits::CompositorEvent::{KeyboardEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent, TouchEvent};
|
||||
use script_traits::webdriver_msg::WebDriverScriptCommand;
|
||||
use serviceworkerjob::{Job, JobQueue};
|
||||
use servo_atoms::Atom;
|
||||
|
@ -2823,6 +2823,7 @@ impl ScriptThread {
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
TouchEvent(event_type, identifier, point, node_address) => {
|
||||
let touch_result = self.handle_touch_event(
|
||||
pipeline_id,
|
||||
|
@ -2848,12 +2849,12 @@ impl ScriptThread {
|
|||
}
|
||||
},
|
||||
|
||||
KeyEvent(ch, key, state, modifiers) => {
|
||||
KeyboardEvent(key_event) => {
|
||||
let document = match { self.documents.borrow().find_document(pipeline_id) } {
|
||||
Some(document) => document,
|
||||
None => return warn!("Message sent to closed pipeline {}.", pipeline_id),
|
||||
};
|
||||
document.dispatch_key_event(ch, key, state, modifiers);
|
||||
document.dispatch_key_event(key_event);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
use clipboard_provider::ClipboardProvider;
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::keyboardevent::KeyboardEvent;
|
||||
use msg::constellation_msg::{Key, KeyModifiers};
|
||||
use keyboard_types::{Key, KeyState, Modifiers, ShortcutMatcher};
|
||||
use std::borrow::ToOwned;
|
||||
use std::cmp::{max, min};
|
||||
use std::default::Default;
|
||||
|
@ -130,17 +130,11 @@ pub enum Direction {
|
|||
Backward,
|
||||
}
|
||||
|
||||
/// Was the keyboard event accompanied by the standard control modifier,
|
||||
/// i.e. cmd on Mac OS or ctrl on other platforms.
|
||||
// Some shortcuts use Cmd on Mac and Control on other systems.
|
||||
#[cfg(target_os = "macos")]
|
||||
fn is_control_key(mods: KeyModifiers) -> bool {
|
||||
mods.contains(KeyModifiers::SUPER) && !mods.contains(KeyModifiers::CONTROL | KeyModifiers::ALT)
|
||||
}
|
||||
|
||||
pub const CMD_OR_CONTROL: Modifiers = Modifiers::META;
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
fn is_control_key(mods: KeyModifiers) -> bool {
|
||||
mods.contains(KeyModifiers::CONTROL) && !mods.contains(KeyModifiers::SUPER | KeyModifiers::ALT)
|
||||
}
|
||||
pub const CMD_OR_CONTROL: Modifiers = Modifiers::CONTROL;
|
||||
|
||||
/// The length in bytes of the first n characters in a UTF-8 string.
|
||||
///
|
||||
|
@ -685,155 +679,139 @@ impl<T: ClipboardProvider> TextInput<T> {
|
|||
|
||||
/// Process a given `KeyboardEvent` and return an action for the caller to execute.
|
||||
pub fn handle_keydown(&mut self, event: &KeyboardEvent) -> KeyReaction {
|
||||
if let Some(key) = event.get_key() {
|
||||
self.handle_keydown_aux(event.printable(), key, event.get_key_modifiers())
|
||||
} else {
|
||||
KeyReaction::Nothing
|
||||
}
|
||||
let key = event.key();
|
||||
let mods = event.modifiers();
|
||||
self.handle_keydown_aux(key, mods, cfg!(target_os = "macos"))
|
||||
}
|
||||
|
||||
// This function exists for easy unit testing.
|
||||
// To test Mac OS shortcuts on other systems a flag is passed.
|
||||
pub fn handle_keydown_aux(
|
||||
&mut self,
|
||||
printable: Option<char>,
|
||||
key: Key,
|
||||
mods: KeyModifiers,
|
||||
mut mods: Modifiers,
|
||||
macos: bool,
|
||||
) -> KeyReaction {
|
||||
let maybe_select = if mods.contains(KeyModifiers::SHIFT) {
|
||||
let maybe_select = if mods.contains(Modifiers::SHIFT) {
|
||||
Selection::Selected
|
||||
} else {
|
||||
Selection::NotSelected
|
||||
};
|
||||
|
||||
match (printable, key) {
|
||||
(_, Key::B) if mods.contains(KeyModifiers::CONTROL | KeyModifiers::ALT) => {
|
||||
mods.remove(Modifiers::SHIFT);
|
||||
ShortcutMatcher::new(KeyState::Down, key.clone(), mods)
|
||||
.shortcut(Modifiers::CONTROL | Modifiers::ALT, 'B', || {
|
||||
self.adjust_horizontal_by_word(Direction::Backward, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
(_, Key::F) if mods.contains(KeyModifiers::CONTROL | KeyModifiers::ALT) => {
|
||||
})
|
||||
.shortcut(Modifiers::CONTROL | Modifiers::ALT, 'F', || {
|
||||
self.adjust_horizontal_by_word(Direction::Forward, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
(_, Key::A) if mods.contains(KeyModifiers::CONTROL | KeyModifiers::ALT) => {
|
||||
})
|
||||
.shortcut(Modifiers::CONTROL | Modifiers::ALT, 'A', || {
|
||||
self.adjust_horizontal_to_line_end(Direction::Backward, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
(_, Key::E) if mods.contains(KeyModifiers::CONTROL | KeyModifiers::ALT) => {
|
||||
})
|
||||
.shortcut(Modifiers::CONTROL | Modifiers::ALT, 'E', || {
|
||||
self.adjust_horizontal_to_line_end(Direction::Forward, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
#[cfg(target_os = "macos")]
|
||||
(None, Key::A) if mods == KeyModifiers::CONTROL =>
|
||||
{
|
||||
})
|
||||
.optional_shortcut(macos, Modifiers::CONTROL, 'A', || {
|
||||
self.adjust_horizontal_to_line_end(Direction::Backward, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
(None, Key::E) if mods == KeyModifiers::CONTROL =>
|
||||
{
|
||||
})
|
||||
.optional_shortcut(macos, Modifiers::CONTROL, 'E', || {
|
||||
self.adjust_horizontal_to_line_end(Direction::Forward, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
}
|
||||
(_, Key::A) if is_control_key(mods) => {
|
||||
})
|
||||
.shortcut(CMD_OR_CONTROL, 'A', || {
|
||||
self.select_all();
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
(_, Key::C) if is_control_key(mods) => {
|
||||
})
|
||||
.shortcut(CMD_OR_CONTROL, 'C', || {
|
||||
if let Some(text) = self.get_selection_text() {
|
||||
self.clipboard_provider.set_clipboard_contents(text);
|
||||
}
|
||||
KeyReaction::DispatchInput
|
||||
},
|
||||
(_, Key::V) if is_control_key(mods) => {
|
||||
})
|
||||
.shortcut(CMD_OR_CONTROL, 'V', || {
|
||||
let contents = self.clipboard_provider.clipboard_contents();
|
||||
self.insert_string(contents);
|
||||
KeyReaction::DispatchInput
|
||||
},
|
||||
(Some(c), _) => {
|
||||
self.insert_char(c);
|
||||
KeyReaction::DispatchInput
|
||||
},
|
||||
(None, Key::Delete) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::Delete, || {
|
||||
self.delete_char(Direction::Forward);
|
||||
KeyReaction::DispatchInput
|
||||
},
|
||||
(None, Key::Backspace) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::Backspace, || {
|
||||
self.delete_char(Direction::Backward);
|
||||
KeyReaction::DispatchInput
|
||||
},
|
||||
#[cfg(target_os = "macos")]
|
||||
(None, Key::Left) if mods.contains(KeyModifiers::SUPER) =>
|
||||
{
|
||||
})
|
||||
.optional_shortcut(macos, Modifiers::META, Key::ArrowLeft, || {
|
||||
self.adjust_horizontal_to_line_end(Direction::Backward, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
(None, Key::Right) if mods.contains(KeyModifiers::SUPER) =>
|
||||
{
|
||||
})
|
||||
.optional_shortcut(macos, Modifiers::META, Key::ArrowRight, || {
|
||||
self.adjust_horizontal_to_line_end(Direction::Forward, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
(None, Key::Up) if mods.contains(KeyModifiers::SUPER) =>
|
||||
{
|
||||
})
|
||||
.optional_shortcut(macos, Modifiers::META, Key::ArrowUp, || {
|
||||
self.adjust_horizontal_to_limit(Direction::Backward, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
(None, Key::Down) if mods.contains(KeyModifiers::SUPER) =>
|
||||
{
|
||||
})
|
||||
.optional_shortcut(macos, Modifiers::META, Key::ArrowDown, || {
|
||||
self.adjust_horizontal_to_limit(Direction::Forward, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
}
|
||||
(None, Key::Left) if mods.contains(KeyModifiers::ALT) => {
|
||||
})
|
||||
.shortcut(Modifiers::ALT, Key::ArrowLeft, || {
|
||||
self.adjust_horizontal_by_word(Direction::Backward, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
(None, Key::Right) if mods.contains(KeyModifiers::ALT) => {
|
||||
})
|
||||
.shortcut(Modifiers::ALT, Key::ArrowRight, || {
|
||||
self.adjust_horizontal_by_word(Direction::Forward, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
(None, Key::Left) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::ArrowLeft, || {
|
||||
self.adjust_horizontal_by_one(Direction::Backward, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
(None, Key::Right) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::ArrowRight, || {
|
||||
self.adjust_horizontal_by_one(Direction::Forward, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
(None, Key::Up) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::ArrowUp, || {
|
||||
self.adjust_vertical(-1, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
(None, Key::Down) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::ArrowDown, || {
|
||||
self.adjust_vertical(1, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
(None, Key::Enter) | (None, Key::KpEnter) => self.handle_return(),
|
||||
(None, Key::Home) => {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
self.edit_point.index = 0;
|
||||
}
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::Enter, || self.handle_return())
|
||||
.optional_shortcut(macos, Modifiers::empty(), Key::Home, || {
|
||||
self.edit_point.index = 0;
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
(None, Key::End) => {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
self.edit_point.index = self.current_line_length();
|
||||
self.assert_ok_selection();
|
||||
}
|
||||
})
|
||||
.optional_shortcut(macos, Modifiers::empty(), Key::End, || {
|
||||
self.edit_point.index = self.current_line_length();
|
||||
self.assert_ok_selection();
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
(None, Key::PageUp) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::PageUp, || {
|
||||
self.adjust_vertical(-28, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
(None, Key::PageDown) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::PageDown, || {
|
||||
self.adjust_vertical(28, maybe_select);
|
||||
KeyReaction::RedrawSelection
|
||||
},
|
||||
_ => KeyReaction::Nothing,
|
||||
}
|
||||
})
|
||||
.otherwise(|| {
|
||||
if let Key::Character(ref c) = key {
|
||||
self.insert_string(c.as_str());
|
||||
return KeyReaction::DispatchInput;
|
||||
}
|
||||
KeyReaction::Nothing
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Whether the content is empty.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue