mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00: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
21
Cargo.lock
generated
21
Cargo.lock
generated
|
@ -498,6 +498,7 @@ dependencies = [
|
|||
"gleam 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"keyboard-types 0.4.2-servo (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"msg 0.0.1",
|
||||
|
@ -534,6 +535,7 @@ dependencies = [
|
|||
"gfx_traits 0.0.1",
|
||||
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"keyboard-types 0.4.2-servo (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"layout_traits 0.0.1",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"metrics 0.0.1",
|
||||
|
@ -895,6 +897,7 @@ name = "embedder_traits"
|
|||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"keyboard-types 0.4.2-servo (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"msg 0.0.1",
|
||||
|
@ -1726,6 +1729,15 @@ dependencies = [
|
|||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keyboard-types"
|
||||
version = "0.4.2-servo"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "khronos_api"
|
||||
version = "2.1.0"
|
||||
|
@ -2013,6 +2025,7 @@ dependencies = [
|
|||
"hashglobe 0.1.0",
|
||||
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper_serde 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"keyboard-types 0.4.2-servo (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mozjs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"selectors 0.20.0",
|
||||
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2249,7 +2262,6 @@ dependencies = [
|
|||
name = "msg"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"malloc_size_of 0.0.1",
|
||||
"malloc_size_of_derive 0.0.1",
|
||||
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2981,6 +2993,7 @@ dependencies = [
|
|||
"ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"jstraceable_derive 0.0.1",
|
||||
"keyboard-types 0.4.2-servo (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3084,7 +3097,7 @@ name = "script_tests"
|
|||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"msg 0.0.1",
|
||||
"keyboard-types 0.4.2-servo (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"script 0.0.1",
|
||||
"servo_url 0.0.1",
|
||||
]
|
||||
|
@ -3103,6 +3116,7 @@ dependencies = [
|
|||
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper_serde 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"keyboard-types 0.4.2-servo (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"malloc_size_of 0.0.1",
|
||||
"malloc_size_of_derive 0.0.1",
|
||||
|
@ -3191,6 +3205,7 @@ dependencies = [
|
|||
"gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gleam 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glutin 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"keyboard-types 0.4.2-servo (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libservo 0.0.1",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -4032,6 +4047,7 @@ dependencies = [
|
|||
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"keyboard-types 0.4.2-servo (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"msg 0.0.1",
|
||||
"net_traits 0.0.1",
|
||||
|
@ -4458,6 +4474,7 @@ dependencies = [
|
|||
"checksum jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||
"checksum jpeg-decoder 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0dfe27a6c0dabd772d0f9b9f8701c4ca12c4d1eebcadf2be1f6f70396f6a1434"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum keyboard-types 0.4.2-servo (registry+https://github.com/rust-lang/crates.io-index)" = "75082c134a78e0fc2232d2f30bf3dfdea1cd28591846b85a73b4b46cd776b482"
|
||||
"checksum khronos_api 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ef23fcc4059260c5936f638c9805ebfc87cb172fa6661d130cba7f97d58f55"
|
||||
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
||||
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
||||
|
|
|
@ -21,6 +21,7 @@ gleam = {version = "0.6", optional = true}
|
|||
image = "0.19"
|
||||
ipc-channel = "0.11"
|
||||
libc = "0.2"
|
||||
keyboard-types = {version = "0.4.2-servo", features = ["serde"]}
|
||||
log = "0.4"
|
||||
msg = {path = "../msg"}
|
||||
net_traits = {path = "../net_traits"}
|
||||
|
|
|
@ -12,6 +12,7 @@ extern crate gleam;
|
|||
#[cfg(feature = "gleam")]
|
||||
extern crate image;
|
||||
extern crate ipc_channel;
|
||||
extern crate keyboard_types;
|
||||
extern crate libc;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
|
|
@ -8,7 +8,8 @@ use embedder_traits::EventLoopWaker;
|
|||
use euclid::TypedScale;
|
||||
#[cfg(feature = "gleam")]
|
||||
use gleam::gl;
|
||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState, TopLevelBrowsingContextId, TraversalDirection};
|
||||
use keyboard_types::KeyboardEvent;
|
||||
use msg::constellation_msg::{TopLevelBrowsingContextId, TraversalDirection};
|
||||
use script_traits::{MouseButton, TouchEventType, TouchId};
|
||||
use servo_geometry::{DeviceIndependentPixel, DeviceUintLength};
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -70,7 +71,7 @@ pub enum WindowEvent {
|
|||
/// Sent when the user quits the application
|
||||
Quit,
|
||||
/// Sent when a key input state changes
|
||||
KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
|
||||
Keyboard(KeyboardEvent),
|
||||
/// Sent when Ctr+R/Apple+R is called to reload the current page.
|
||||
Reload(TopLevelBrowsingContextId),
|
||||
/// Create a new top level browsing context
|
||||
|
@ -94,7 +95,7 @@ impl Debug for WindowEvent {
|
|||
WindowEvent::Idle => write!(f, "Idle"),
|
||||
WindowEvent::Refresh => write!(f, "Refresh"),
|
||||
WindowEvent::Resize => write!(f, "Resize"),
|
||||
WindowEvent::KeyEvent(..) => write!(f, "Key"),
|
||||
WindowEvent::Keyboard(..) => write!(f, "Keyboard"),
|
||||
WindowEvent::LoadUrl(..) => write!(f, "LoadUrl"),
|
||||
WindowEvent::MouseWindowEventClass(..) => write!(f, "Mouse"),
|
||||
WindowEvent::MouseWindowMoveEventClass(..) => write!(f, "MouseMove"),
|
||||
|
|
|
@ -25,6 +25,7 @@ gfx_traits = {path = "../gfx_traits"}
|
|||
hyper = "0.10"
|
||||
ipc-channel = "0.11"
|
||||
layout_traits = {path = "../layout_traits"}
|
||||
keyboard-types = {version = "0.4.2-servo", features = ["serde"]}
|
||||
log = "0.4"
|
||||
metrics = {path = "../metrics"}
|
||||
msg = {path = "../msg"}
|
||||
|
|
|
@ -111,10 +111,10 @@ use gfx_traits::Epoch;
|
|||
use ipc_channel::{Error as IpcError};
|
||||
use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use keyboard_types::KeyboardEvent;
|
||||
use layout_traits::LayoutThreadFactory;
|
||||
use log::{Log, Level, LevelFilter, Metadata, Record};
|
||||
use msg::constellation_msg::{BrowsingContextId, PipelineId, HistoryStateId, TopLevelBrowsingContextId};
|
||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
||||
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
|
||||
use net_traits::{self, IpcSend, FetchResponseMsg, ResourceThreads};
|
||||
use net_traits::pub_domains::reg_host;
|
||||
|
@ -972,8 +972,8 @@ where
|
|||
});
|
||||
let _ = resp_chan.send(focus_browsing_context);
|
||||
},
|
||||
FromCompositorMsg::KeyEvent(ch, key, state, modifiers) => {
|
||||
self.handle_key_msg(ch, key, state, modifiers);
|
||||
FromCompositorMsg::Keyboard(key_event) => {
|
||||
self.handle_key_msg(key_event);
|
||||
},
|
||||
// Load a new page from a typed url
|
||||
// If there is already a pending page (self.pending_changes), it will not be overridden;
|
||||
|
@ -2622,12 +2622,12 @@ where
|
|||
session_history.replace_history_state(pipeline_id, history_state_id, url);
|
||||
}
|
||||
|
||||
fn handle_key_msg(&mut self, ch: Option<char>, key: Key, state: KeyState, mods: KeyModifiers) {
|
||||
fn handle_key_msg(&mut self, event: KeyboardEvent) {
|
||||
// Send to the focused browsing contexts' current pipeline. If it
|
||||
// doesn't exist, fall back to sending to the compositor.
|
||||
match self.focused_browsing_context_id {
|
||||
Some(browsing_context_id) => {
|
||||
let event = CompositorEvent::KeyEvent(ch, key, state, mods);
|
||||
let event = CompositorEvent::KeyboardEvent(event);
|
||||
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
|
||||
Some(ctx) => ctx.pipeline_id,
|
||||
None => return warn!(
|
||||
|
@ -2647,7 +2647,7 @@ where
|
|||
}
|
||||
},
|
||||
None => {
|
||||
let event = (None, EmbedderMsg::KeyEvent(ch, key, state, mods));
|
||||
let event = (None, EmbedderMsg::Keyboard(event));
|
||||
self.embedder_proxy.clone().send(event);
|
||||
},
|
||||
}
|
||||
|
@ -2942,8 +2942,8 @@ where
|
|||
Some(pipeline) => pipeline.event_loop.clone(),
|
||||
None => return warn!("Pipeline {} SendKeys after closure.", pipeline_id),
|
||||
};
|
||||
for (key, mods, state) in cmd {
|
||||
let event = CompositorEvent::KeyEvent(None, key, state, mods);
|
||||
for event in cmd {
|
||||
let event = CompositorEvent::KeyboardEvent(event);
|
||||
let control_msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
|
||||
if let Err(e) = event_loop.send(control_msg) {
|
||||
return self.handle_send_error(pipeline_id, e);
|
||||
|
|
|
@ -22,6 +22,7 @@ extern crate gfx;
|
|||
extern crate gfx_traits;
|
||||
extern crate hyper;
|
||||
extern crate ipc_channel;
|
||||
extern crate keyboard_types;
|
||||
extern crate layout_traits;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
|
|
@ -11,6 +11,7 @@ path = "lib.rs"
|
|||
|
||||
[dependencies]
|
||||
ipc-channel = "0.11"
|
||||
keyboard-types = {version = "0.4.2-servo", features = ["serde"]}
|
||||
lazy_static = "1"
|
||||
log = "0.4"
|
||||
msg = {path = "../msg"}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
extern crate ipc_channel;
|
||||
extern crate keyboard_types;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[macro_use]
|
||||
|
@ -18,7 +19,8 @@ extern crate webrender_api;
|
|||
pub mod resources;
|
||||
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use msg::constellation_msg::{InputMethodType, Key, KeyModifiers, KeyState, TopLevelBrowsingContextId};
|
||||
use keyboard_types::KeyboardEvent;
|
||||
use msg::constellation_msg::{InputMethodType, TopLevelBrowsingContextId};
|
||||
use servo_channel::{Receiver, Sender};
|
||||
use servo_url::ServoUrl;
|
||||
use std::fmt::{Debug, Error, Formatter};
|
||||
|
@ -93,7 +95,7 @@ pub enum EmbedderMsg {
|
|||
/// Wether or not to unload a document
|
||||
AllowUnload(IpcSender<bool>),
|
||||
/// Sends an unconsumed key event back to the embedder.
|
||||
KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
|
||||
Keyboard(KeyboardEvent),
|
||||
/// Changes the cursor.
|
||||
SetCursor(CursorKind),
|
||||
/// A favicon was detected
|
||||
|
@ -134,7 +136,7 @@ impl Debug for EmbedderMsg {
|
|||
EmbedderMsg::Alert(..) => write!(f, "Alert"),
|
||||
EmbedderMsg::AllowUnload(..) => write!(f, "AllowUnload"),
|
||||
EmbedderMsg::AllowNavigation(..) => write!(f, "AllowNavigation"),
|
||||
EmbedderMsg::KeyEvent(..) => write!(f, "KeyEvent"),
|
||||
EmbedderMsg::Keyboard(..) => write!(f, "Keyboard"),
|
||||
EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"),
|
||||
EmbedderMsg::NewFavicon(..) => write!(f, "NewFavicon"),
|
||||
EmbedderMsg::HeadParsed => write!(f, "HeadParsed"),
|
||||
|
|
|
@ -12,6 +12,7 @@ path = "lib.rs"
|
|||
servo = [
|
||||
"hyper",
|
||||
"hyper_serde",
|
||||
"keyboard-types",
|
||||
"mozjs",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
|
@ -30,6 +31,7 @@ euclid = "0.19"
|
|||
hashglobe = { path = "../hashglobe" }
|
||||
hyper = { version = "0.10", optional = true }
|
||||
hyper_serde = { version = "0.8", optional = true }
|
||||
keyboard-types = {version = "0.4.2-servo", features = ["serde"], optional = true}
|
||||
mozjs = { version = "0.9.0", optional = true }
|
||||
selectors = { path = "../selectors" }
|
||||
serde = { version = "1.0.27", optional = true }
|
||||
|
|
|
@ -52,6 +52,8 @@ extern crate hyper;
|
|||
#[cfg(feature = "servo")]
|
||||
extern crate hyper_serde;
|
||||
#[cfg(feature = "servo")]
|
||||
extern crate keyboard_types;
|
||||
#[cfg(feature = "servo")]
|
||||
extern crate mozjs as js;
|
||||
extern crate selectors;
|
||||
#[cfg(feature = "servo")]
|
||||
|
@ -955,6 +957,19 @@ malloc_size_of_is_0!(webrender_api::StickyOffsetBounds);
|
|||
#[cfg(feature = "webrender_api")]
|
||||
malloc_size_of_is_0!(webrender_api::TransformStyle);
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
impl MallocSizeOf for keyboard_types::Key {
|
||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
match self {
|
||||
keyboard_types::Key::Character(ref s) => s.size_of(ops),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
malloc_size_of_is_0!(keyboard_types::Modifiers);
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
impl MallocSizeOf for xml5ever::QualName {
|
||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||
|
|
|
@ -12,7 +12,6 @@ test = false
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
malloc_size_of = { path = "../malloc_size_of" }
|
||||
malloc_size_of_derive = { path = "../malloc_size_of_derive" }
|
||||
serde = "1.0.60"
|
||||
|
|
|
@ -10,153 +10,6 @@ use std::fmt;
|
|||
use std::num::NonZeroU32;
|
||||
use webrender_api;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub enum KeyState {
|
||||
Pressed,
|
||||
Released,
|
||||
Repeated,
|
||||
}
|
||||
|
||||
//N.B. Based on the glutin key enum
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
|
||||
pub enum Key {
|
||||
Space,
|
||||
Apostrophe,
|
||||
Comma,
|
||||
Minus,
|
||||
Period,
|
||||
Slash,
|
||||
Num0,
|
||||
Num1,
|
||||
Num2,
|
||||
Num3,
|
||||
Num4,
|
||||
Num5,
|
||||
Num6,
|
||||
Num7,
|
||||
Num8,
|
||||
Num9,
|
||||
Semicolon,
|
||||
Equal,
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
E,
|
||||
F,
|
||||
G,
|
||||
H,
|
||||
I,
|
||||
J,
|
||||
K,
|
||||
L,
|
||||
M,
|
||||
N,
|
||||
O,
|
||||
P,
|
||||
Q,
|
||||
R,
|
||||
S,
|
||||
T,
|
||||
U,
|
||||
V,
|
||||
W,
|
||||
X,
|
||||
Y,
|
||||
Z,
|
||||
LeftBracket,
|
||||
Backslash,
|
||||
RightBracket,
|
||||
GraveAccent,
|
||||
World1,
|
||||
World2,
|
||||
|
||||
Escape,
|
||||
Enter,
|
||||
Tab,
|
||||
Backspace,
|
||||
Insert,
|
||||
Delete,
|
||||
Right,
|
||||
Left,
|
||||
Down,
|
||||
Up,
|
||||
PageUp,
|
||||
PageDown,
|
||||
Home,
|
||||
End,
|
||||
CapsLock,
|
||||
ScrollLock,
|
||||
NumLock,
|
||||
PrintScreen,
|
||||
Pause,
|
||||
F1,
|
||||
F2,
|
||||
F3,
|
||||
F4,
|
||||
F5,
|
||||
F6,
|
||||
F7,
|
||||
F8,
|
||||
F9,
|
||||
F10,
|
||||
F11,
|
||||
F12,
|
||||
F13,
|
||||
F14,
|
||||
F15,
|
||||
F16,
|
||||
F17,
|
||||
F18,
|
||||
F19,
|
||||
F20,
|
||||
F21,
|
||||
F22,
|
||||
F23,
|
||||
F24,
|
||||
F25,
|
||||
Kp0,
|
||||
Kp1,
|
||||
Kp2,
|
||||
Kp3,
|
||||
Kp4,
|
||||
Kp5,
|
||||
Kp6,
|
||||
Kp7,
|
||||
Kp8,
|
||||
Kp9,
|
||||
KpDecimal,
|
||||
KpDivide,
|
||||
KpMultiply,
|
||||
KpSubtract,
|
||||
KpAdd,
|
||||
KpEnter,
|
||||
KpEqual,
|
||||
LeftShift,
|
||||
LeftControl,
|
||||
LeftAlt,
|
||||
LeftSuper,
|
||||
RightShift,
|
||||
RightControl,
|
||||
RightAlt,
|
||||
RightSuper,
|
||||
Menu,
|
||||
|
||||
NavigateBackward,
|
||||
NavigateForward,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct KeyModifiers: u8 {
|
||||
const NONE = 0x00;
|
||||
const SHIFT = 0x01;
|
||||
const CONTROL = 0x02;
|
||||
const ALT = 0x04;
|
||||
const SUPER = 0x08;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
pub enum TraversalDirection {
|
||||
Forward(usize),
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
#[macro_use]
|
||||
extern crate malloc_size_of;
|
||||
#[macro_use]
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -20,6 +20,7 @@ gfx_traits = {path = "../gfx_traits"}
|
|||
hyper = "0.10"
|
||||
hyper_serde = "0.8"
|
||||
ipc-channel = "0.11"
|
||||
keyboard-types = {version = "0.4.2-servo", features = ["serde"]}
|
||||
libc = "0.2"
|
||||
malloc_size_of = { path = "../malloc_size_of" }
|
||||
malloc_size_of_derive = { path = "../malloc_size_of_derive" }
|
||||
|
|
|
@ -19,6 +19,7 @@ extern crate gfx_traits;
|
|||
extern crate hyper;
|
||||
extern crate hyper_serde;
|
||||
extern crate ipc_channel;
|
||||
extern crate keyboard_types;
|
||||
extern crate libc;
|
||||
#[macro_use]
|
||||
extern crate malloc_size_of;
|
||||
|
@ -50,8 +51,9 @@ use hyper::header::Headers;
|
|||
use hyper::method::Method;
|
||||
use ipc_channel::{Error as IpcError};
|
||||
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||
use keyboard_types::KeyboardEvent;
|
||||
use libc::c_void;
|
||||
use msg::constellation_msg::{BrowsingContextId, HistoryStateId, Key, KeyModifiers, KeyState, PipelineId};
|
||||
use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId};
|
||||
use msg::constellation_msg::{PipelineNamespaceId, TraversalDirection, TopLevelBrowsingContextId};
|
||||
use net_traits::{FetchResponseMsg, ReferrerPolicy, ResourceThreads};
|
||||
use net_traits::image::base::Image;
|
||||
|
@ -477,7 +479,7 @@ pub enum CompositorEvent {
|
|||
Option<UntrustedNodeAddress>,
|
||||
),
|
||||
/// A key was pressed.
|
||||
KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
|
||||
KeyboardEvent(KeyboardEvent),
|
||||
}
|
||||
|
||||
/// Requests a TimerEvent-Message be sent after the given duration.
|
||||
|
@ -708,7 +710,7 @@ pub enum WebDriverCommandMsg {
|
|||
/// of a browsing context.
|
||||
ScriptCommand(BrowsingContextId, WebDriverScriptCommand),
|
||||
/// Act as if keys were pressed in the browsing context with the given ID.
|
||||
SendKeys(BrowsingContextId, Vec<(Key, KeyModifiers, KeyState)>),
|
||||
SendKeys(BrowsingContextId, Vec<KeyboardEvent>),
|
||||
/// Set the window size.
|
||||
SetWindowSize(
|
||||
TopLevelBrowsingContextId,
|
||||
|
@ -736,7 +738,7 @@ pub enum ConstellationMsg {
|
|||
/// Query the constellation to see if the current compositor output is stable
|
||||
IsReadyToSaveImage(HashMap<PipelineId, Epoch>),
|
||||
/// Inform the constellation of a key event.
|
||||
KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
|
||||
Keyboard(KeyboardEvent),
|
||||
/// Request to load a page.
|
||||
LoadUrl(TopLevelBrowsingContextId, ServoUrl),
|
||||
/// Request to traverse the joint session history of the provided browsing context.
|
||||
|
@ -780,7 +782,7 @@ impl fmt::Debug for ConstellationMsg {
|
|||
GetPipeline(..) => "GetPipeline",
|
||||
GetFocusTopLevelBrowsingContext(..) => "GetFocusTopLevelBrowsingContext",
|
||||
IsReadyToSaveImage(..) => "IsReadyToSaveImage",
|
||||
KeyEvent(..) => "KeyEvent",
|
||||
Keyboard(..) => "Keyboard",
|
||||
LoadUrl(..) => "LoadUrl",
|
||||
TraverseHistory(..) => "TraverseHistory",
|
||||
WindowSize(..) => "WindowSize",
|
||||
|
|
|
@ -109,7 +109,7 @@ use webvr::{WebVRThread, WebVRCompositorHandler};
|
|||
pub use gleam::gl;
|
||||
pub use servo_config as config;
|
||||
pub use servo_url as url;
|
||||
pub use msg::constellation_msg::{KeyState, TopLevelBrowsingContextId as BrowserId};
|
||||
pub use msg::constellation_msg::{TopLevelBrowsingContextId as BrowserId};
|
||||
|
||||
/// The in-process interface to Servo.
|
||||
///
|
||||
|
@ -320,10 +320,10 @@ where
|
|||
}
|
||||
},
|
||||
|
||||
WindowEvent::KeyEvent(ch, key, state, modifiers) => {
|
||||
let msg = ConstellationMsg::KeyEvent(ch, key, state, modifiers);
|
||||
WindowEvent::Keyboard(key_event) => {
|
||||
let msg = ConstellationMsg::Keyboard(key_event);
|
||||
if let Err(e) = self.constellation_chan.send(msg) {
|
||||
warn!("Sending key event to constellation failed ({:?}).", e);
|
||||
warn!("Sending keyboard event to constellation failed ({:?}).", e);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -399,12 +399,12 @@ where
|
|||
(_, ShutdownState::ShuttingDown) => {},
|
||||
|
||||
(
|
||||
EmbedderMsg::KeyEvent(ch, key, state, modified),
|
||||
EmbedderMsg::Keyboard(key_event),
|
||||
ShutdownState::NotShuttingDown,
|
||||
) => {
|
||||
let event = (
|
||||
top_level_browsing_context,
|
||||
EmbedderMsg::KeyEvent(ch, key, state, modified),
|
||||
EmbedderMsg::Keyboard(key_event),
|
||||
);
|
||||
self.embedder_events.push(event);
|
||||
},
|
||||
|
|
|
@ -16,6 +16,7 @@ euclid = "0.19"
|
|||
hyper = "0.10"
|
||||
image = "0.19"
|
||||
ipc-channel = "0.11"
|
||||
keyboard-types = {version = "0.4.2-servo", features = ["serde"]}
|
||||
log = "0.4"
|
||||
msg = {path = "../msg"}
|
||||
net_traits = {path = "../net_traits"}
|
||||
|
|
|
@ -2,184 +2,105 @@
|
|||
* 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 msg::constellation_msg::{Key, KeyState, KeyModifiers};
|
||||
use keyboard_types::{Key, KeyboardEvent};
|
||||
|
||||
/// Takes a character and returns an Option containing a tuple of the
|
||||
/// corresponding keycode and whether shift is required. This is
|
||||
/// currently pretty much ascii-only and the webdriver spec isn't
|
||||
/// entirely clear on how to deal with characters outside this
|
||||
/// range. Returns None if no key corresponding to the character is
|
||||
/// matched.
|
||||
fn key_from_char(key_string: &char) -> Option<(Key, bool)> {
|
||||
match *key_string {
|
||||
' ' => Some((Key::Space, false)),
|
||||
'\'' => Some((Key::Apostrophe, true)),
|
||||
'\"' => Some((Key::Apostrophe, false)),
|
||||
'<' => Some((Key::Comma, true)),
|
||||
',' => Some((Key::Comma, false)),
|
||||
'_' => Some((Key::Minus, true)),
|
||||
'-' => Some((Key::Minus, false)),
|
||||
'>' => Some((Key::Period, true)),
|
||||
'.' => Some((Key::Period, false)),
|
||||
'?' => Some((Key::Slash, true)),
|
||||
'/' => Some((Key::Slash, false)),
|
||||
'~' => Some((Key::GraveAccent, true)),
|
||||
'`' => Some((Key::GraveAccent, false)),
|
||||
')' => Some((Key::Num0, true)),
|
||||
'0' => Some((Key::Num0, false)),
|
||||
'!' => Some((Key::Num1, true)),
|
||||
'1' => Some((Key::Num1, false)),
|
||||
'@' => Some((Key::Num2, true)),
|
||||
'2' => Some((Key::Num2, false)),
|
||||
'#' => Some((Key::Num3, true)),
|
||||
'3' => Some((Key::Num3, false)),
|
||||
'$' => Some((Key::Num4, true)),
|
||||
'4' => Some((Key::Num4, false)),
|
||||
'%' => Some((Key::Num5, true)),
|
||||
'5' => Some((Key::Num5, false)),
|
||||
'^' => Some((Key::Num6, true)),
|
||||
'6' => Some((Key::Num6, false)),
|
||||
'&' => Some((Key::Num7, true)),
|
||||
'7' => Some((Key::Num7, false)),
|
||||
'*' => Some((Key::Num8, true)),
|
||||
'8' => Some((Key::Num8, false)),
|
||||
'(' => Some((Key::Num9, true)),
|
||||
'9' => Some((Key::Num9, false)),
|
||||
':' => Some((Key::Semicolon, true)),
|
||||
';' => Some((Key::Semicolon, false)),
|
||||
'+' => Some((Key::Equal, true)),
|
||||
'=' => Some((Key::Equal, false)),
|
||||
'A' => Some((Key::A, true)),
|
||||
'a' => Some((Key::A, false)),
|
||||
'B' => Some((Key::B, true)),
|
||||
'b' => Some((Key::B, false)),
|
||||
'C' => Some((Key::C, true)),
|
||||
'c' => Some((Key::C, false)),
|
||||
'D' => Some((Key::D, true)),
|
||||
'd' => Some((Key::D, false)),
|
||||
'E' => Some((Key::E, true)),
|
||||
'e' => Some((Key::E, false)),
|
||||
'F' => Some((Key::F, true)),
|
||||
'f' => Some((Key::F, false)),
|
||||
'G' => Some((Key::G, true)),
|
||||
'g' => Some((Key::G, false)),
|
||||
'H' => Some((Key::H, true)),
|
||||
'h' => Some((Key::H, false)),
|
||||
'I' => Some((Key::I, true)),
|
||||
'i' => Some((Key::I, false)),
|
||||
'J' => Some((Key::J, true)),
|
||||
'j' => Some((Key::J, false)),
|
||||
'K' => Some((Key::K, true)),
|
||||
'k' => Some((Key::K, false)),
|
||||
'L' => Some((Key::L, true)),
|
||||
'l' => Some((Key::L, false)),
|
||||
'M' => Some((Key::M, true)),
|
||||
'm' => Some((Key::M, false)),
|
||||
'N' => Some((Key::N, true)),
|
||||
'n' => Some((Key::N, false)),
|
||||
'O' => Some((Key::O, true)),
|
||||
'o' => Some((Key::O, false)),
|
||||
'P' => Some((Key::P, true)),
|
||||
'p' => Some((Key::P, false)),
|
||||
'Q' => Some((Key::Q, true)),
|
||||
'q' => Some((Key::Q, false)),
|
||||
'R' => Some((Key::R, true)),
|
||||
'r' => Some((Key::R, false)),
|
||||
'S' => Some((Key::S, true)),
|
||||
's' => Some((Key::S, false)),
|
||||
'T' => Some((Key::T, true)),
|
||||
't' => Some((Key::T, false)),
|
||||
'U' => Some((Key::U, true)),
|
||||
'u' => Some((Key::U, false)),
|
||||
'V' => Some((Key::V, true)),
|
||||
'v' => Some((Key::V, false)),
|
||||
'W' => Some((Key::W, true)),
|
||||
'w' => Some((Key::W, false)),
|
||||
'X' => Some((Key::X, true)),
|
||||
'x' => Some((Key::X, false)),
|
||||
'Y' => Some((Key::Y, true)),
|
||||
'y' => Some((Key::Y, false)),
|
||||
'Z' => Some((Key::Z, true)),
|
||||
'z' => Some((Key::Z, false)),
|
||||
'{' => Some((Key::LeftBracket, true)),
|
||||
'[' => Some((Key::LeftBracket, false)),
|
||||
'|' => Some((Key::Backslash, true)),
|
||||
'\\' => Some((Key::Backslash, false)),
|
||||
'}' => Some((Key::RightBracket, true)),
|
||||
']' => Some((Key::RightBracket, false)),
|
||||
'\u{E000}' => None,
|
||||
'\u{E001}' => None,
|
||||
'\u{E002}' => None,
|
||||
'\u{E003}' => Some((Key::Backspace, false)),
|
||||
'\u{E004}' => Some((Key::Tab, false)),
|
||||
'\u{E005}' => None,
|
||||
'\u{E006}' => Some((Key::Enter, false)), // This is supposed to be the Return key
|
||||
'\u{E007}' => Some((Key::Enter, false)),
|
||||
'\u{E008}' => Some((Key::LeftShift, false)),
|
||||
'\u{E009}' => Some((Key::LeftShift, false)),
|
||||
'\u{E00A}' => Some((Key::LeftAlt, false)),
|
||||
'\u{E00B}' => Some((Key::Pause, false)),
|
||||
'\u{E00C}' => Some((Key::Escape, false)),
|
||||
'\u{E00D}' => Some((Key::Space, false)),
|
||||
'\u{E00E}' => Some((Key::PageUp, false)),
|
||||
'\u{E00F}' => Some((Key::PageDown, false)),
|
||||
'\u{E010}' => Some((Key::End, false)),
|
||||
'\u{E011}' => Some((Key::Home, false)),
|
||||
'\u{E012}' => Some((Key::Right, false)),
|
||||
'\u{E013}' => Some((Key::Left, false)),
|
||||
'\u{E014}' => Some((Key::Down, false)),
|
||||
'\u{E015}' => Some((Key::Up, false)),
|
||||
'\u{E016}' => Some((Key::Insert, false)),
|
||||
'\u{E017}' => Some((Key::Delete, false)),
|
||||
'\u{E018}' => Some((Key::Semicolon, false)),
|
||||
'\u{E019}' => Some((Key::Equal, false)),
|
||||
'\u{E01A}' => Some((Key::Kp0, false)),
|
||||
'\u{E01B}' => Some((Key::Kp1, false)),
|
||||
'\u{E01C}' => Some((Key::Kp2, false)),
|
||||
'\u{E01D}' => Some((Key::Kp3, false)),
|
||||
'\u{E01E}' => Some((Key::Kp4, false)),
|
||||
'\u{E01F}' => Some((Key::Kp5, false)),
|
||||
'\u{E020}' => Some((Key::Kp6, false)),
|
||||
'\u{E021}' => Some((Key::Kp7, false)),
|
||||
'\u{E022}' => Some((Key::Kp8, false)),
|
||||
'\u{E023}' => Some((Key::Kp9, false)),
|
||||
'\u{E024}' => Some((Key::KpMultiply, false)),
|
||||
'\u{E025}' => Some((Key::KpAdd, false)),
|
||||
'\u{E026}' => Some((Key::KpEnter, false)),
|
||||
'\u{E027}' => Some((Key::KpSubtract, false)),
|
||||
'\u{E028}' => Some((Key::KpDecimal, false)),
|
||||
'\u{E029}' => Some((Key::KpDivide, false)),
|
||||
'\u{E031}' => Some((Key::F1, false)),
|
||||
'\u{E032}' => Some((Key::F2, false)),
|
||||
'\u{E033}' => Some((Key::F3, false)),
|
||||
'\u{E034}' => Some((Key::F4, false)),
|
||||
'\u{E035}' => Some((Key::F5, false)),
|
||||
'\u{E036}' => Some((Key::F6, false)),
|
||||
'\u{E037}' => Some((Key::F7, false)),
|
||||
'\u{E038}' => Some((Key::F8, false)),
|
||||
'\u{E039}' => Some((Key::F9, false)),
|
||||
'\u{E03A}' => Some((Key::F10, false)),
|
||||
'\u{E03B}' => Some((Key::F11, false)),
|
||||
'\u{E03C}' => Some((Key::F12, false)),
|
||||
'\u{E03D}' => None,
|
||||
'\u{E040}' => None,
|
||||
_ => None,
|
||||
// spec: https://w3c.github.io/webdriver/#keyboard-actions
|
||||
// normalised (sic) as in british spelling
|
||||
fn get_normalised_key_value(key: char) -> Key {
|
||||
match key {
|
||||
'\u{E000}' => Key::Unidentified,
|
||||
'\u{E001}' => Key::Cancel,
|
||||
'\u{E002}' => Key::Help,
|
||||
'\u{E003}' => Key::Backspace,
|
||||
'\u{E004}' => Key::Tab,
|
||||
'\u{E005}' => Key::Clear,
|
||||
// FIXME(pyfisch): spec says "Return"
|
||||
'\u{E006}' => Key::Enter,
|
||||
'\u{E007}' => Key::Enter,
|
||||
'\u{E008}' => Key::Shift,
|
||||
'\u{E009}' => Key::Control,
|
||||
'\u{E00A}' => Key::Alt,
|
||||
'\u{E00B}' => Key::Pause,
|
||||
'\u{E00C}' => Key::Escape,
|
||||
'\u{E00D}' => Key::Character(" ".to_string()),
|
||||
'\u{E00E}' => Key::PageUp,
|
||||
'\u{E00F}' => Key::PageDown,
|
||||
'\u{E010}' => Key::End,
|
||||
'\u{E011}' => Key::Home,
|
||||
'\u{E012}' => Key::ArrowLeft,
|
||||
'\u{E013}' => Key::ArrowUp,
|
||||
'\u{E014}' => Key::ArrowRight,
|
||||
'\u{E015}' => Key::ArrowDown,
|
||||
'\u{E016}' => Key::Insert,
|
||||
'\u{E017}' => Key::Delete,
|
||||
'\u{E018}' => Key::Character(";".to_string()),
|
||||
'\u{E019}' => Key::Character("=".to_string()),
|
||||
'\u{E01A}' => Key::Character("0".to_string()),
|
||||
'\u{E01B}' => Key::Character("1".to_string()),
|
||||
'\u{E01C}' => Key::Character("2".to_string()),
|
||||
'\u{E01D}' => Key::Character("3".to_string()),
|
||||
'\u{E01E}' => Key::Character("4".to_string()),
|
||||
'\u{E01F}' => Key::Character("5".to_string()),
|
||||
'\u{E020}' => Key::Character("6".to_string()),
|
||||
'\u{E021}' => Key::Character("7".to_string()),
|
||||
'\u{E022}' => Key::Character("8".to_string()),
|
||||
'\u{E023}' => Key::Character("9".to_string()),
|
||||
'\u{E024}' => Key::Character("*".to_string()),
|
||||
'\u{E025}' => Key::Character("+".to_string()),
|
||||
'\u{E026}' => Key::Character(",".to_string()),
|
||||
'\u{E027}' => Key::Character("-".to_string()),
|
||||
'\u{E028}' => Key::Character(".".to_string()),
|
||||
'\u{E029}' => Key::Character("/".to_string()),
|
||||
'\u{E031}' => Key::F1,
|
||||
'\u{E032}' => Key::F2,
|
||||
'\u{E033}' => Key::F3,
|
||||
'\u{E034}' => Key::F4,
|
||||
'\u{E035}' => Key::F5,
|
||||
'\u{E036}' => Key::F6,
|
||||
'\u{E037}' => Key::F7,
|
||||
'\u{E038}' => Key::F8,
|
||||
'\u{E039}' => Key::F9,
|
||||
'\u{E03A}' => Key::F10,
|
||||
'\u{E03B}' => Key::F11,
|
||||
'\u{E03C}' => Key::F12,
|
||||
'\u{E03D}' => Key::Meta,
|
||||
'\u{E040}' => Key::ZenkakuHankaku,
|
||||
'\u{E050}' => Key::Shift,
|
||||
'\u{E051}' => Key::Control,
|
||||
'\u{E052}' => Key::Alt,
|
||||
'\u{E053}' => Key::Meta,
|
||||
'\u{E054}' => Key::PageUp,
|
||||
'\u{E055}' => Key::PageDown,
|
||||
'\u{E056}' => Key::End,
|
||||
'\u{E057}' => Key::Home,
|
||||
'\u{E058}' => Key::ArrowLeft,
|
||||
'\u{E059}' => Key::ArrowUp,
|
||||
'\u{E05A}' => Key::ArrowRight,
|
||||
'\u{E05B}' => Key::ArrowDown,
|
||||
'\u{E05C}' => Key::Insert,
|
||||
'\u{E05D}' => Key::Delete,
|
||||
_ => Key::Character(key.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keycodes_to_keys(key_codes: &str) -> Result<Vec<(Key, KeyModifiers, KeyState)>, String> {
|
||||
pub fn keycodes_to_keys(key_codes: &str) -> Vec<KeyboardEvent> {
|
||||
let mut rv = vec![];
|
||||
|
||||
for char_code in key_codes.chars() {
|
||||
let (key, with_shift) =
|
||||
key_from_char(&char_code).ok_or(format!("Unsupported character code {}", char_code))?;
|
||||
let modifiers = if with_shift {
|
||||
KeyModifiers::SHIFT
|
||||
} else {
|
||||
KeyModifiers::empty()
|
||||
// TODO(pyfisch): compute code, location, modifiers according to spec
|
||||
let key = get_normalised_key_value(char_code);
|
||||
let mut event = KeyboardEvent {
|
||||
state: ::keyboard_types::KeyState::Down,
|
||||
key,
|
||||
code: ::keyboard_types::Code::Unidentified,
|
||||
location: ::keyboard_types::Location::Standard,
|
||||
modifiers: ::keyboard_types::Modifiers::empty(),
|
||||
repeat: false,
|
||||
is_composing: false,
|
||||
};
|
||||
rv.push((key, modifiers, KeyState::Pressed));
|
||||
rv.push((key, modifiers, KeyState::Released));
|
||||
rv.push(event.clone());
|
||||
event.state = ::keyboard_types::KeyState::Up;
|
||||
rv.push(event);
|
||||
}
|
||||
Ok(rv)
|
||||
rv
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ extern crate euclid;
|
|||
extern crate hyper;
|
||||
extern crate image;
|
||||
extern crate ipc_channel;
|
||||
extern crate keyboard_types;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate msg;
|
||||
|
@ -995,12 +996,7 @@ impl Handler {
|
|||
))
|
||||
})?;
|
||||
|
||||
let keys = keycodes_to_keys(&keys.text).or_else(|_| {
|
||||
Err(WebDriverError::new(
|
||||
ErrorStatus::UnsupportedOperation,
|
||||
"Failed to convert keycodes",
|
||||
))
|
||||
})?;
|
||||
let keys = keycodes_to_keys(&keys.text);
|
||||
|
||||
// TODO: there's a race condition caused by the focus command and the
|
||||
// send keys command being two separate messages,
|
||||
|
|
|
@ -408,7 +408,7 @@ impl ServoGlue {
|
|||
EmbedderMsg::SelectFiles(..) |
|
||||
EmbedderMsg::MoveTo(..) |
|
||||
EmbedderMsg::ResizeTo(..) |
|
||||
EmbedderMsg::KeyEvent(..) |
|
||||
EmbedderMsg::Keyboard(..) |
|
||||
EmbedderMsg::SetCursor(..) |
|
||||
EmbedderMsg::NewFavicon(..) |
|
||||
EmbedderMsg::HeadParsed |
|
||||
|
|
|
@ -40,6 +40,7 @@ crossbeam-channel = "0.2"
|
|||
euclid = "0.19"
|
||||
gleam = "0.6"
|
||||
glutin = "0.18"
|
||||
keyboard-types = {version = "0.4.2-servo", features = ["serde"]}
|
||||
lazy_static = "1"
|
||||
libservo = {path = "../../components/servo"}
|
||||
log = "0.4"
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
use euclid::{TypedPoint2D, TypedVector2D};
|
||||
use glutin_app::keyutils::{CMD_OR_CONTROL, CMD_OR_ALT};
|
||||
use glutin_app::window::{Window, LINE_HEIGHT};
|
||||
use keyboard_types::{Key, KeyboardEvent, Modifiers, ShortcutMatcher};
|
||||
use servo::compositing::windowing::{WebRenderDebugOption, WindowEvent};
|
||||
use servo::embedder_traits::{EmbedderMsg, FilterPattern};
|
||||
use servo::msg::constellation_msg::{Key, TopLevelBrowsingContextId as BrowserId};
|
||||
use servo::msg::constellation_msg::{KeyModifiers, KeyState, TraversalDirection};
|
||||
use servo::msg::constellation_msg::{TopLevelBrowsingContextId as BrowserId};
|
||||
use servo::msg::constellation_msg::TraversalDirection;
|
||||
use servo::net_traits::pub_domains::is_reg_domain;
|
||||
use servo::script_traits::TouchEventType;
|
||||
use servo::servo_config::opts;
|
||||
|
@ -70,8 +71,8 @@ impl Browser {
|
|||
pub fn handle_window_events(&mut self, events: Vec<WindowEvent>) {
|
||||
for event in events {
|
||||
match event {
|
||||
WindowEvent::KeyEvent(ch, key, state, mods) => {
|
||||
self.handle_key_from_window(ch, key, state, mods);
|
||||
WindowEvent::Keyboard(key_event) => {
|
||||
self.handle_key_from_window(key_event);
|
||||
},
|
||||
event => {
|
||||
self.event_queue.push(event);
|
||||
|
@ -85,22 +86,14 @@ impl Browser {
|
|||
}
|
||||
|
||||
/// Handle key events before sending them to Servo.
|
||||
fn handle_key_from_window(
|
||||
&mut self,
|
||||
ch: Option<char>,
|
||||
key: Key,
|
||||
state: KeyState,
|
||||
mods: KeyModifiers,
|
||||
) {
|
||||
let pressed = state == KeyState::Pressed;
|
||||
// We don't match the state in the parent `match` because we don't want to do anything
|
||||
// on KeyState::Released when it's a combo that we handle on Pressed. For example,
|
||||
// if we catch Alt-Left on pressed, we don't want the Release event to be sent to Servo.
|
||||
match (mods, ch, key, self.browser_id) {
|
||||
(CMD_OR_CONTROL, _, Key::R, Some(id)) => if pressed {
|
||||
self.event_queue.push(WindowEvent::Reload(id));
|
||||
},
|
||||
(CMD_OR_CONTROL, _, Key::L, Some(id)) => if pressed {
|
||||
fn handle_key_from_window(&mut self, key_event: KeyboardEvent) {
|
||||
ShortcutMatcher::from_event(key_event.clone())
|
||||
.shortcut(CMD_OR_CONTROL, 'R', || {
|
||||
if let Some(id) = self.browser_id {
|
||||
self.event_queue.push(WindowEvent::Reload(id));
|
||||
}
|
||||
})
|
||||
.shortcut(CMD_OR_CONTROL, 'L', || {
|
||||
let url: String = if let Some(ref current_url) = self.current_url {
|
||||
current_url.to_string()
|
||||
} else {
|
||||
|
@ -110,163 +103,130 @@ impl Browser {
|
|||
let input = tinyfiledialogs::input_box(title, title, &url);
|
||||
if let Some(input) = input {
|
||||
if let Some(url) = sanitize_url(&input) {
|
||||
self.event_queue.push(WindowEvent::LoadUrl(id, url));
|
||||
if let Some(id) = self.browser_id {
|
||||
self.event_queue.push(WindowEvent::LoadUrl(id, url));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
(CMD_OR_CONTROL, _, Key::Q, _) => if pressed {
|
||||
})
|
||||
.shortcut(CMD_OR_CONTROL, 'Q', || {
|
||||
self.event_queue.push(WindowEvent::Quit);
|
||||
},
|
||||
(_, Some('3'), _, _) if mods ^ KeyModifiers::CONTROL == KeyModifiers::SHIFT => {
|
||||
if pressed {
|
||||
self.event_queue.push(WindowEvent::CaptureWebRender);
|
||||
})
|
||||
.shortcut(Modifiers::CONTROL, Key::F9, || {
|
||||
self.event_queue.push(WindowEvent::CaptureWebRender)
|
||||
})
|
||||
.shortcut(Modifiers::CONTROL, Key::F10, || {
|
||||
self.event_queue.push(WindowEvent::ToggleWebRenderDebug(
|
||||
WebRenderDebugOption::RenderTargetDebug,
|
||||
));
|
||||
})
|
||||
.shortcut(Modifiers::CONTROL, Key::F11, || {
|
||||
self.event_queue.push(WindowEvent::ToggleWebRenderDebug(
|
||||
WebRenderDebugOption::TextureCacheDebug,
|
||||
));
|
||||
})
|
||||
.shortcut(Modifiers::CONTROL, Key::F12, || {
|
||||
self.event_queue.push(WindowEvent::ToggleWebRenderDebug(
|
||||
WebRenderDebugOption::Profiler,
|
||||
));
|
||||
})
|
||||
.shortcut(CMD_OR_ALT, Key::ArrowRight, || {
|
||||
if let Some(id) = self.browser_id {
|
||||
let event = WindowEvent::Navigation(id, TraversalDirection::Forward(1));
|
||||
self.event_queue.push(event);
|
||||
}
|
||||
},
|
||||
(KeyModifiers::CONTROL, None, Key::F10, _) => if pressed {
|
||||
let event =
|
||||
WindowEvent::ToggleWebRenderDebug(WebRenderDebugOption::RenderTargetDebug);
|
||||
self.event_queue.push(event);
|
||||
},
|
||||
(KeyModifiers::CONTROL, None, Key::F11, _) => if pressed {
|
||||
let event =
|
||||
WindowEvent::ToggleWebRenderDebug(WebRenderDebugOption::TextureCacheDebug);
|
||||
self.event_queue.push(event);
|
||||
},
|
||||
(KeyModifiers::CONTROL, None, Key::F12, _) => if pressed {
|
||||
let event = WindowEvent::ToggleWebRenderDebug(WebRenderDebugOption::Profiler);
|
||||
self.event_queue.push(event);
|
||||
},
|
||||
(CMD_OR_ALT, None, Key::Right, Some(id)) |
|
||||
(KeyModifiers::NONE, None, Key::NavigateForward, Some(id)) => if pressed {
|
||||
let event = WindowEvent::Navigation(id, TraversalDirection::Forward(1));
|
||||
self.event_queue.push(event);
|
||||
},
|
||||
(CMD_OR_ALT, None, Key::Left, Some(id)) |
|
||||
(KeyModifiers::NONE, None, Key::NavigateBackward, Some(id)) => if pressed {
|
||||
let event = WindowEvent::Navigation(id, TraversalDirection::Back(1));
|
||||
self.event_queue.push(event);
|
||||
},
|
||||
(KeyModifiers::NONE, None, Key::Escape, _) => if pressed {
|
||||
})
|
||||
.shortcut(CMD_OR_ALT, Key::ArrowLeft, || {
|
||||
if let Some(id) = self.browser_id {
|
||||
let event = WindowEvent::Navigation(id, TraversalDirection::Back(1));
|
||||
self.event_queue.push(event);
|
||||
}
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::Escape, || {
|
||||
self.event_queue.push(WindowEvent::Quit);
|
||||
},
|
||||
_ => {
|
||||
self.platform_handle_key(ch, key, mods, state);
|
||||
},
|
||||
}
|
||||
})
|
||||
.otherwise(|| self.platform_handle_key(key_event));
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "win"))]
|
||||
fn platform_handle_key(
|
||||
&mut self,
|
||||
ch: Option<char>,
|
||||
key: Key,
|
||||
mods: KeyModifiers,
|
||||
state: KeyState,
|
||||
) {
|
||||
let pressed = state == KeyState::Pressed;
|
||||
match (mods, key, self.browser_id) {
|
||||
(CMD_OR_CONTROL, Key::LeftBracket, Some(id)) => if pressed {
|
||||
let event = WindowEvent::Navigation(id, TraversalDirection::Back(1));
|
||||
self.event_queue.push(event);
|
||||
},
|
||||
(CMD_OR_CONTROL, Key::RightBracket, Some(id)) => if pressed {
|
||||
let event = WindowEvent::Navigation(id, TraversalDirection::Back(1));
|
||||
self.event_queue.push(event);
|
||||
},
|
||||
_ => {
|
||||
self.event_queue
|
||||
.push(WindowEvent::KeyEvent(ch, key, state, mods));
|
||||
},
|
||||
fn platform_handle_key(&mut self, key_event: KeyboardEvent) {
|
||||
if let Some(id) = self.browser_id {
|
||||
if let Some(event) = ShortcutMatcher::from_event(key_event.clone())
|
||||
.shortcut(CMD_OR_CONTROL, '[', || {
|
||||
WindowEvent::Navigation(id, TraversalDirection::Back(1))
|
||||
})
|
||||
.shortcut(CMD_OR_CONTROL, ']', || {
|
||||
WindowEvent::Navigation(id, TraversalDirection::Forward(1))
|
||||
})
|
||||
.otherwise(|| WindowEvent::Keyboard(key_event))
|
||||
{
|
||||
self.event_queue.push(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "win")]
|
||||
fn platform_handle_key(
|
||||
&mut self,
|
||||
_ch: Option<char>,
|
||||
_key: Key,
|
||||
_mods: KeyModifiers,
|
||||
_state: KeyState,
|
||||
) {
|
||||
}
|
||||
fn platform_handle_key(&mut self, _key_event: KeyboardEvent) {}
|
||||
|
||||
/// Handle key events after they have been handled by Servo.
|
||||
fn handle_key_from_servo(
|
||||
&mut self,
|
||||
_: Option<BrowserId>,
|
||||
ch: Option<char>,
|
||||
key: Key,
|
||||
state: KeyState,
|
||||
mods: KeyModifiers,
|
||||
) {
|
||||
if state == KeyState::Released {
|
||||
return;
|
||||
}
|
||||
|
||||
match (mods, ch, key) {
|
||||
(CMD_OR_CONTROL, Some('='), _) | (CMD_OR_CONTROL, Some('+'), _) => {
|
||||
self.event_queue.push(WindowEvent::Zoom(1.1));
|
||||
},
|
||||
(_, Some('='), _) if mods == (CMD_OR_CONTROL | KeyModifiers::SHIFT) => {
|
||||
self.event_queue.push(WindowEvent::Zoom(1.1));
|
||||
},
|
||||
(CMD_OR_CONTROL, Some('-'), _) => {
|
||||
self.event_queue.push(WindowEvent::Zoom(1.0 / 1.1));
|
||||
},
|
||||
(CMD_OR_CONTROL, Some('0'), _) => {
|
||||
self.event_queue.push(WindowEvent::ResetZoom);
|
||||
},
|
||||
|
||||
(KeyModifiers::NONE, None, Key::PageDown) => {
|
||||
fn handle_key_from_servo(&mut self, _: Option<BrowserId>, event: KeyboardEvent) {
|
||||
ShortcutMatcher::from_event(event)
|
||||
.shortcut(CMD_OR_CONTROL, '=', || {
|
||||
self.event_queue.push(WindowEvent::Zoom(1.1))
|
||||
})
|
||||
.shortcut(CMD_OR_CONTROL, '+', || {
|
||||
self.event_queue.push(WindowEvent::Zoom(1.1))
|
||||
})
|
||||
.shortcut(CMD_OR_CONTROL, '-', || {
|
||||
self.event_queue.push(WindowEvent::Zoom(1.0 / 1.1))
|
||||
})
|
||||
.shortcut(CMD_OR_CONTROL, '0', || {
|
||||
self.event_queue.push(WindowEvent::ResetZoom)
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::PageDown, || {
|
||||
let scroll_location = ScrollLocation::Delta(TypedVector2D::new(
|
||||
0.0,
|
||||
-self.window.page_height() + 2.0 * LINE_HEIGHT,
|
||||
));
|
||||
self.scroll_window_from_key(scroll_location, TouchEventType::Move);
|
||||
},
|
||||
(KeyModifiers::NONE, None, Key::PageUp) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::PageUp, || {
|
||||
let scroll_location = ScrollLocation::Delta(TypedVector2D::new(
|
||||
0.0,
|
||||
self.window.page_height() - 2.0 * LINE_HEIGHT,
|
||||
));
|
||||
self.scroll_window_from_key(scroll_location, TouchEventType::Move);
|
||||
},
|
||||
|
||||
(KeyModifiers::NONE, None, Key::Home) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::Home, || {
|
||||
self.scroll_window_from_key(ScrollLocation::Start, TouchEventType::Move);
|
||||
},
|
||||
|
||||
(KeyModifiers::NONE, None, Key::End) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::End, || {
|
||||
self.scroll_window_from_key(ScrollLocation::End, TouchEventType::Move);
|
||||
},
|
||||
|
||||
(KeyModifiers::NONE, None, Key::Up) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::ArrowUp, || {
|
||||
self.scroll_window_from_key(
|
||||
ScrollLocation::Delta(TypedVector2D::new(0.0, 3.0 * LINE_HEIGHT)),
|
||||
TouchEventType::Move,
|
||||
);
|
||||
},
|
||||
(KeyModifiers::NONE, None, Key::Down) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::ArrowDown, || {
|
||||
self.scroll_window_from_key(
|
||||
ScrollLocation::Delta(TypedVector2D::new(0.0, -3.0 * LINE_HEIGHT)),
|
||||
TouchEventType::Move,
|
||||
);
|
||||
},
|
||||
(KeyModifiers::NONE, None, Key::Left) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::ArrowLeft, || {
|
||||
self.scroll_window_from_key(
|
||||
ScrollLocation::Delta(TypedVector2D::new(LINE_HEIGHT, 0.0)),
|
||||
TouchEventType::Move,
|
||||
);
|
||||
},
|
||||
(KeyModifiers::NONE, None, Key::Right) => {
|
||||
})
|
||||
.shortcut(Modifiers::empty(), Key::ArrowRight, || {
|
||||
self.scroll_window_from_key(
|
||||
ScrollLocation::Delta(TypedVector2D::new(-LINE_HEIGHT, 0.0)),
|
||||
TouchEventType::Move,
|
||||
);
|
||||
},
|
||||
|
||||
_ => {},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn scroll_window_from_key(&mut self, scroll_location: ScrollLocation, phase: TouchEventType) {
|
||||
|
@ -311,7 +271,8 @@ impl Browser {
|
|||
&message,
|
||||
MessageBoxIcon::Warning,
|
||||
);
|
||||
}).unwrap()
|
||||
})
|
||||
.unwrap()
|
||||
.join()
|
||||
.expect("Thread spawning failed");
|
||||
}
|
||||
|
@ -350,8 +311,8 @@ impl Browser {
|
|||
self.event_queue
|
||||
.push(WindowEvent::SelectBrowser(new_browser_id));
|
||||
},
|
||||
EmbedderMsg::KeyEvent(ch, key, state, modified) => {
|
||||
self.handle_key_from_servo(browser_id, ch, key, state, modified);
|
||||
EmbedderMsg::Keyboard(key_event) => {
|
||||
self.handle_key_from_servo(browser_id, key_event);
|
||||
},
|
||||
EmbedderMsg::SetCursor(cursor) => {
|
||||
self.window.set_cursor(cursor);
|
||||
|
@ -438,7 +399,8 @@ fn platform_get_selected_devices(devices: Vec<String>) -> Option<String> {
|
|||
},
|
||||
None => None,
|
||||
}
|
||||
}).unwrap()
|
||||
})
|
||||
.unwrap()
|
||||
.join()
|
||||
.expect("Thread spawning failed")
|
||||
}
|
||||
|
@ -480,7 +442,8 @@ fn get_selected_files(patterns: Vec<FilterPattern>, multiple_files: bool) -> Opt
|
|||
let file = tinyfiledialogs::open_file_dialog(picker_name, "", filter_opt);
|
||||
file.map(|x| vec![x])
|
||||
}
|
||||
}).unwrap()
|
||||
})
|
||||
.unwrap()
|
||||
.join()
|
||||
.expect("Thread spawning failed")
|
||||
}
|
||||
|
@ -495,7 +458,8 @@ fn sanitize_url(request: &str) -> Option<ServoUrl> {
|
|||
} else {
|
||||
None
|
||||
}
|
||||
}).or_else(|| {
|
||||
})
|
||||
.or_else(|| {
|
||||
PREFS
|
||||
.get("shell.searchpage")
|
||||
.as_string()
|
||||
|
|
|
@ -2,215 +2,34 @@
|
|||
* 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 servo::msg::constellation_msg::{self, Key, KeyModifiers};
|
||||
use winit::VirtualKeyCode;
|
||||
use keyboard_types::{Code, Key, KeyboardEvent, KeyState, Modifiers, Location};
|
||||
use winit::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode};
|
||||
|
||||
// Some shortcuts use Cmd on Mac and Control on other systems.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub const CMD_OR_CONTROL: KeyModifiers = KeyModifiers::SUPER;
|
||||
pub const CMD_OR_CONTROL: Modifiers = Modifiers::META;
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub const CMD_OR_CONTROL: KeyModifiers = KeyModifiers::CONTROL;
|
||||
pub const CMD_OR_CONTROL: Modifiers = Modifiers::CONTROL;
|
||||
|
||||
// Some shortcuts use Cmd on Mac and Alt on other systems.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub const CMD_OR_ALT: KeyModifiers = KeyModifiers::SUPER;
|
||||
pub const CMD_OR_ALT: Modifiers = Modifiers::META;
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub const CMD_OR_ALT: KeyModifiers = KeyModifiers::ALT;
|
||||
pub const CMD_OR_ALT: Modifiers = Modifiers::ALT;
|
||||
|
||||
pub fn char_to_script_key(c: char) -> Option<constellation_msg::Key> {
|
||||
match c {
|
||||
' ' => Some(Key::Space),
|
||||
'"' => Some(Key::Apostrophe),
|
||||
'\'' => Some(Key::Apostrophe),
|
||||
'<' => Some(Key::Comma),
|
||||
',' => Some(Key::Comma),
|
||||
'_' => Some(Key::Minus),
|
||||
'-' => Some(Key::Minus),
|
||||
'>' => Some(Key::Period),
|
||||
'.' => Some(Key::Period),
|
||||
'?' => Some(Key::Slash),
|
||||
'/' => Some(Key::Slash),
|
||||
'~' => Some(Key::GraveAccent),
|
||||
'`' => Some(Key::GraveAccent),
|
||||
')' => Some(Key::Num0),
|
||||
'0' => Some(Key::Num0),
|
||||
'!' => Some(Key::Num1),
|
||||
'1' => Some(Key::Num1),
|
||||
'@' => Some(Key::Num2),
|
||||
'2' => Some(Key::Num2),
|
||||
'#' => Some(Key::Num3),
|
||||
'3' => Some(Key::Num3),
|
||||
'$' => Some(Key::Num4),
|
||||
'4' => Some(Key::Num4),
|
||||
'%' => Some(Key::Num5),
|
||||
'5' => Some(Key::Num5),
|
||||
'^' => Some(Key::Num6),
|
||||
'6' => Some(Key::Num6),
|
||||
'&' => Some(Key::Num7),
|
||||
'7' => Some(Key::Num7),
|
||||
'*' => Some(Key::Num8),
|
||||
'8' => Some(Key::Num8),
|
||||
'(' => Some(Key::Num9),
|
||||
'9' => Some(Key::Num9),
|
||||
':' => Some(Key::Semicolon),
|
||||
';' => Some(Key::Semicolon),
|
||||
'+' => Some(Key::Equal),
|
||||
'=' => 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),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn winit_key_to_script_key(key: VirtualKeyCode) -> Result<constellation_msg::Key, ()> {
|
||||
fn get_servo_key_from_winit_key(key: Option<VirtualKeyCode>) -> Key {
|
||||
use winit::VirtualKeyCode::*;
|
||||
// TODO(negge): add more key mappings
|
||||
Ok(match key {
|
||||
A => Key::A,
|
||||
B => Key::B,
|
||||
C => Key::C,
|
||||
D => Key::D,
|
||||
E => Key::E,
|
||||
F => Key::F,
|
||||
G => Key::G,
|
||||
H => Key::H,
|
||||
I => Key::I,
|
||||
J => Key::J,
|
||||
K => Key::K,
|
||||
L => Key::L,
|
||||
M => Key::M,
|
||||
N => Key::N,
|
||||
O => Key::O,
|
||||
P => Key::P,
|
||||
Q => Key::Q,
|
||||
R => Key::R,
|
||||
S => Key::S,
|
||||
T => Key::T,
|
||||
U => Key::U,
|
||||
V => Key::V,
|
||||
W => Key::W,
|
||||
X => Key::X,
|
||||
Y => Key::Y,
|
||||
Z => Key::Z,
|
||||
|
||||
Numpad0 => Key::Kp0,
|
||||
Numpad1 => Key::Kp1,
|
||||
Numpad2 => Key::Kp2,
|
||||
Numpad3 => Key::Kp3,
|
||||
Numpad4 => Key::Kp4,
|
||||
Numpad5 => Key::Kp5,
|
||||
Numpad6 => Key::Kp6,
|
||||
Numpad7 => Key::Kp7,
|
||||
Numpad8 => Key::Kp8,
|
||||
Numpad9 => Key::Kp9,
|
||||
|
||||
Key0 => Key::Num0,
|
||||
Key1 => Key::Num1,
|
||||
Key2 => Key::Num2,
|
||||
Key3 => Key::Num3,
|
||||
Key4 => Key::Num4,
|
||||
Key5 => Key::Num5,
|
||||
Key6 => Key::Num6,
|
||||
Key7 => Key::Num7,
|
||||
Key8 => Key::Num8,
|
||||
Key9 => Key::Num9,
|
||||
|
||||
Return => Key::Enter,
|
||||
Space => Key::Space,
|
||||
// TODO: figure out how to map NavigateForward, NavigateBackward
|
||||
// TODO: map the remaining keys if possible
|
||||
let key = if let Some(key) = key {
|
||||
key
|
||||
} else {
|
||||
return Key::Unidentified;
|
||||
};
|
||||
match key {
|
||||
// printable: Key1 to Key0
|
||||
// printable: A to Z
|
||||
Escape => Key::Escape,
|
||||
Equals => Key::Equal,
|
||||
Minus => Key::Minus,
|
||||
Back => Key::Backspace,
|
||||
PageDown => Key::PageDown,
|
||||
PageUp => Key::PageUp,
|
||||
|
||||
Insert => Key::Insert,
|
||||
Home => Key::Home,
|
||||
Delete => Key::Delete,
|
||||
End => Key::End,
|
||||
|
||||
Left => Key::Left,
|
||||
Up => Key::Up,
|
||||
Right => Key::Right,
|
||||
Down => Key::Down,
|
||||
|
||||
LShift => Key::LeftShift,
|
||||
LControl => Key::LeftControl,
|
||||
LAlt => Key::LeftAlt,
|
||||
LWin => Key::LeftSuper,
|
||||
RShift => Key::RightShift,
|
||||
RControl => Key::RightControl,
|
||||
RAlt => Key::RightAlt,
|
||||
RWin => Key::RightSuper,
|
||||
|
||||
Apostrophe => Key::Apostrophe,
|
||||
Backslash => Key::Backslash,
|
||||
Comma => Key::Comma,
|
||||
Grave => Key::GraveAccent,
|
||||
LBracket => Key::LeftBracket,
|
||||
Period => Key::Period,
|
||||
RBracket => Key::RightBracket,
|
||||
Semicolon => Key::Semicolon,
|
||||
Slash => Key::Slash,
|
||||
Tab => Key::Tab,
|
||||
Subtract => Key::Minus,
|
||||
|
||||
F1 => Key::F1,
|
||||
F2 => Key::F2,
|
||||
F3 => Key::F3,
|
||||
|
@ -223,23 +42,226 @@ pub fn winit_key_to_script_key(key: VirtualKeyCode) -> Result<constellation_msg:
|
|||
F10 => Key::F10,
|
||||
F11 => Key::F11,
|
||||
F12 => Key::F12,
|
||||
|
||||
NavigateBackward => Key::NavigateBackward,
|
||||
NavigateForward => Key::NavigateForward,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_printable(key_code: VirtualKeyCode) -> bool {
|
||||
use winit::VirtualKeyCode::*;
|
||||
match key_code {
|
||||
Escape | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | F13 | F14 |
|
||||
F15 | Snapshot | Scroll | Pause | Insert | Home | Delete | End | PageDown | PageUp |
|
||||
Left | Up | Right | Down | Back | LAlt | LControl | LShift | LWin | Mail |
|
||||
MediaSelect | MediaStop | Mute | MyComputer | NavigateForward | NavigateBackward |
|
||||
NextTrack | NoConvert | PlayPause | Power | PrevTrack | RAlt | RControl | RShift |
|
||||
RWin | Sleep | Stop | VolumeDown | VolumeUp | Wake | WebBack | WebFavorites |
|
||||
WebForward | WebHome | WebRefresh | WebSearch | WebStop => false,
|
||||
_ => true,
|
||||
// F13 to F15 are not mapped
|
||||
Snapshot => Key::PrintScreen,
|
||||
// Scroll not mapped
|
||||
Pause => Key::Pause,
|
||||
Insert => Key::Insert,
|
||||
Home => Key::Home,
|
||||
Delete => Key::Delete,
|
||||
End => Key::End,
|
||||
PageDown => Key::PageDown,
|
||||
PageUp => Key::PageUp,
|
||||
Left => Key::ArrowLeft,
|
||||
Up => Key::ArrowUp,
|
||||
Right => Key::ArrowRight,
|
||||
Down => Key::ArrowDown,
|
||||
Back => Key::Backspace,
|
||||
Return => Key::Enter,
|
||||
// printable: Space
|
||||
Compose => Key::Compose,
|
||||
// Caret not mapped
|
||||
Numlock => Key::NumLock,
|
||||
// printable: Numpad0 to Numpad9
|
||||
// AbntC1 and AbntC2 not mapped
|
||||
// printable: Add, Apostrophe,
|
||||
// Apps, At, Ax not mapped
|
||||
// printable: Backslash,
|
||||
Calculator => Key::LaunchApplication2,
|
||||
Capital => Key::CapsLock,
|
||||
// printable: Colon, Comma,
|
||||
Convert => Key::Convert,
|
||||
// not mapped: Decimal,
|
||||
// printable: Divide, Equals, Grave,
|
||||
Kana => Key::KanaMode,
|
||||
Kanji => Key::KanjiMode,
|
||||
LAlt => Key::Alt,
|
||||
// printable: LBracket,
|
||||
LControl => Key::Control,
|
||||
LShift => Key::Shift,
|
||||
LWin => Key::Meta,
|
||||
Mail => Key::LaunchMail,
|
||||
// not mapped: MediaSelect,
|
||||
MediaStop => Key::MediaStop,
|
||||
// printable: Minus, Multiply,
|
||||
Mute => Key::AudioVolumeMute,
|
||||
MyComputer => Key::LaunchApplication1,
|
||||
// not mapped: NavigateForward, NavigateBackward
|
||||
NextTrack => Key::MediaTrackNext,
|
||||
NoConvert => Key::NonConvert,
|
||||
// printable: NumpadComma, NumpadEnter, NumpadEquals,
|
||||
// not mapped: OEM102,
|
||||
// printable: Period,
|
||||
PlayPause => Key::MediaPlayPause,
|
||||
Power => Key::Power,
|
||||
PrevTrack => Key::MediaTrackPrevious,
|
||||
RAlt => Key::Alt,
|
||||
// printable RBracket
|
||||
RControl => Key::Control,
|
||||
RShift => Key::Shift,
|
||||
RWin => Key::Meta,
|
||||
// printable Semicolon, Slash
|
||||
Sleep => Key::Standby,
|
||||
// not mapped: Stop,
|
||||
// printable Subtract,
|
||||
// not mapped: Sysrq,
|
||||
Tab => Key::Tab,
|
||||
// printable: Underline,
|
||||
// not mapped: Unlabeled,
|
||||
VolumeDown => Key::AudioVolumeDown,
|
||||
VolumeUp => Key::AudioVolumeUp,
|
||||
Wake => Key::WakeUp,
|
||||
WebBack => Key::BrowserBack,
|
||||
WebFavorites => Key::BrowserFavorites,
|
||||
WebForward => Key::BrowserForward,
|
||||
WebHome => Key::BrowserHome,
|
||||
WebRefresh => Key::BrowserRefresh,
|
||||
WebSearch => Key::BrowserSearch,
|
||||
WebStop => Key::BrowserStop,
|
||||
// printable Yen,
|
||||
Copy => Key::Copy,
|
||||
Paste => Key::Paste,
|
||||
Cut => Key::Cut,
|
||||
_ => Key::Unidentified,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_servo_location_from_winit_key(key: Option<VirtualKeyCode>) -> Location {
|
||||
use winit::VirtualKeyCode::*;
|
||||
// TODO: add more numpad keys
|
||||
let key = if let Some(key) = key {
|
||||
key
|
||||
} else {
|
||||
return Location::Standard;
|
||||
};
|
||||
match key {
|
||||
LShift | LControl | LAlt | LWin => Location::Left,
|
||||
RShift | RControl | RAlt | RWin => Location::Right,
|
||||
Numpad0 | Numpad1 | Numpad2 | Numpad3 | Numpad4 | Numpad5 | Numpad6 | Numpad7 |
|
||||
Numpad8 | Numpad9 => Location::Numpad,
|
||||
NumpadComma | NumpadEnter | NumpadEquals => Location::Numpad,
|
||||
_ => Location::Standard,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_servo_code_from_scancode(scancode: u32) -> Code {
|
||||
// TODO: Map more codes
|
||||
use keyboard_types::Code::*;
|
||||
match scancode {
|
||||
1 => Escape,
|
||||
2 => Digit1,
|
||||
3 => Digit2,
|
||||
4 => Digit3,
|
||||
5 => Digit4,
|
||||
6 => Digit5,
|
||||
7 => Digit6,
|
||||
8 => Digit7,
|
||||
9 => Digit8,
|
||||
10 => Digit9,
|
||||
11 => Digit0,
|
||||
|
||||
14 => Backspace,
|
||||
15 => Tab,
|
||||
16 => KeyQ,
|
||||
17 => KeyW,
|
||||
18 => KeyE,
|
||||
19 => KeyR,
|
||||
20 => KeyT,
|
||||
21 => KeyY,
|
||||
22 => KeyU,
|
||||
23 => KeyI,
|
||||
24 => KeyO,
|
||||
25 => KeyP,
|
||||
26 => BracketLeft,
|
||||
27 => BracketRight,
|
||||
28 => Enter,
|
||||
|
||||
30 => KeyA,
|
||||
31 => KeyS,
|
||||
32 => KeyD,
|
||||
33 => KeyF,
|
||||
34 => KeyG,
|
||||
35 => KeyH,
|
||||
36 => KeyJ,
|
||||
37 => KeyK,
|
||||
38 => KeyL,
|
||||
39 => Semicolon,
|
||||
40 => Quote,
|
||||
|
||||
42 => ShiftLeft,
|
||||
43 => Backslash,
|
||||
44 => KeyZ,
|
||||
45 => KeyX,
|
||||
46 => KeyC,
|
||||
47 => KeyV,
|
||||
48 => KeyB,
|
||||
49 => KeyN,
|
||||
50 => KeyM,
|
||||
51 => Comma,
|
||||
52 => Period,
|
||||
53 => Slash,
|
||||
54 => ShiftRight,
|
||||
|
||||
57 => Space,
|
||||
|
||||
59 => F1,
|
||||
60 => F2,
|
||||
61 => F3,
|
||||
62 => F4,
|
||||
63 => F5,
|
||||
64 => F6,
|
||||
65 => F7,
|
||||
66 => F8,
|
||||
67 => F9,
|
||||
68 => F10,
|
||||
|
||||
87 => F11,
|
||||
88 => F12,
|
||||
|
||||
103 => ArrowUp,
|
||||
104 => PageUp,
|
||||
105 => ArrowLeft,
|
||||
106 => ArrowRight,
|
||||
|
||||
102 => Home,
|
||||
107 => End,
|
||||
108 => ArrowDown,
|
||||
109 => PageDown,
|
||||
110 => Insert,
|
||||
111 => Delete,
|
||||
|
||||
_ => Unidentified,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn get_servo_code_from_scancode(_scancode: u32) -> Code {
|
||||
// TODO: Implement for Windows and Mac OS
|
||||
Code::Unidentified
|
||||
}
|
||||
|
||||
fn get_modifiers(mods: ModifiersState) -> Modifiers {
|
||||
let mut modifiers = Modifiers::empty();
|
||||
modifiers.set(Modifiers::CONTROL, mods.ctrl);
|
||||
modifiers.set(Modifiers::SHIFT, mods.shift);
|
||||
modifiers.set(Modifiers::ALT, mods.alt);
|
||||
modifiers.set(Modifiers::META, mods.logo);
|
||||
modifiers
|
||||
}
|
||||
|
||||
pub fn keyboard_event_from_winit(input: KeyboardInput) -> KeyboardEvent {
|
||||
info!("winit keyboard input: {:?}", input);
|
||||
KeyboardEvent {
|
||||
state: match input.state {
|
||||
ElementState::Pressed => KeyState::Down,
|
||||
ElementState::Released => KeyState::Up,
|
||||
},
|
||||
key: get_servo_key_from_winit_key(input.virtual_keycode),
|
||||
code: get_servo_code_from_scancode(input.scancode),
|
||||
location: get_servo_location_from_winit_key(input.virtual_keycode),
|
||||
modifiers: get_modifiers(input.modifiers),
|
||||
repeat: false,
|
||||
is_composing: false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,12 @@ use euclid::{Length, TypedPoint2D, TypedVector2D, TypedScale, TypedSize2D};
|
|||
use gdi32;
|
||||
use gleam::gl;
|
||||
use glutin::{Api, ContextBuilder, GlContext, GlRequest, GlWindow};
|
||||
use keyboard_types::{Key, KeyboardEvent, KeyState};
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
use osmesa_sys;
|
||||
use servo::compositing::windowing::{AnimationState, MouseWindowEvent, WindowEvent};
|
||||
use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods};
|
||||
use servo::embedder_traits::EventLoopWaker;
|
||||
use servo::msg::constellation_msg::{Key, KeyState, KeyModifiers};
|
||||
use servo::script_traits::TouchEventType;
|
||||
use servo::servo_config::opts;
|
||||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
|
@ -31,13 +31,13 @@ use std::rc::Rc;
|
|||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
use super::keyutils;
|
||||
use super::keyutils::keyboard_event_from_winit;
|
||||
#[cfg(target_os = "windows")]
|
||||
use user32;
|
||||
#[cfg(target_os = "windows")]
|
||||
use winapi;
|
||||
use winit;
|
||||
use winit::{ElementState, Event, ModifiersState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
|
||||
use winit::{ElementState, Event, MouseButton, MouseScrollDelta, TouchPhase, KeyboardInput};
|
||||
use winit::dpi::{LogicalPosition, LogicalSize, PhysicalSize};
|
||||
#[cfg(target_os = "macos")]
|
||||
use winit::os::macos::{ActivationPolicy, WindowBuilderExt};
|
||||
|
@ -150,8 +150,7 @@ pub struct Window {
|
|||
mouse_down_point: Cell<TypedPoint2D<i32, DevicePixel>>,
|
||||
event_queue: RefCell<Vec<WindowEvent>>,
|
||||
mouse_pos: Cell<TypedPoint2D<i32, DevicePixel>>,
|
||||
key_modifiers: Cell<KeyModifiers>,
|
||||
last_pressed_key: Cell<Option<Key>>,
|
||||
last_pressed: Cell<Option<KeyboardEvent>>,
|
||||
animation_state: Cell<AnimationState>,
|
||||
fullscreen: Cell<bool>,
|
||||
gl: Rc<gl::Gl>,
|
||||
|
@ -276,11 +275,8 @@ impl Window {
|
|||
event_queue: RefCell::new(vec![]),
|
||||
mouse_down_button: Cell::new(None),
|
||||
mouse_down_point: Cell::new(TypedPoint2D::new(0, 0)),
|
||||
|
||||
mouse_pos: Cell::new(TypedPoint2D::new(0, 0)),
|
||||
key_modifiers: Cell::new(KeyModifiers::empty()),
|
||||
|
||||
last_pressed_key: Cell::new(None),
|
||||
last_pressed: Cell::new(None),
|
||||
gl: gl.clone(),
|
||||
animation_state: Cell::new(AnimationState::Idle),
|
||||
fullscreen: Cell::new(false),
|
||||
|
@ -408,56 +404,46 @@ impl Window {
|
|||
GlRequest::Specific(Api::OpenGlEs, (3, 0))
|
||||
}
|
||||
|
||||
fn handle_received_character(&self, ch: char) {
|
||||
let last_key = if let Some(key) = self.last_pressed_key.get() {
|
||||
key
|
||||
fn handle_received_character(&self, mut ch: char) {
|
||||
info!("winit received character: {:?}", ch);
|
||||
if ch.is_control() {
|
||||
if ch as u8 >= 32 {
|
||||
return;
|
||||
}
|
||||
// shift ASCII control characters to lowercase
|
||||
ch = (ch as u8 + 96) as char;
|
||||
}
|
||||
let mut event = if let Some(event) = self.last_pressed.replace(None) {
|
||||
event
|
||||
} else if ch.is_ascii() {
|
||||
// Some keys like Backspace emit a control character in winit
|
||||
// but they are already dealt with in handle_keyboard_input
|
||||
// so just ignore the character.
|
||||
return
|
||||
} else {
|
||||
return;
|
||||
// For combined characters like the letter e with an acute accent
|
||||
// no keyboard event is emitted. A dummy event is created in this case.
|
||||
KeyboardEvent::default()
|
||||
};
|
||||
|
||||
self.last_pressed_key.set(None);
|
||||
|
||||
let (key, ch) = if let Some(key) = keyutils::char_to_script_key(ch) {
|
||||
(key, Some(ch))
|
||||
} else {
|
||||
(last_key, None)
|
||||
};
|
||||
|
||||
let modifiers = self.key_modifiers.get();
|
||||
let event = WindowEvent::KeyEvent(ch, key, KeyState::Pressed, modifiers);
|
||||
self.event_queue.borrow_mut().push(event);
|
||||
}
|
||||
|
||||
fn toggle_keyboard_modifiers(&self, mods: ModifiersState) {
|
||||
self.toggle_modifier(KeyModifiers::CONTROL, mods.ctrl);
|
||||
self.toggle_modifier(KeyModifiers::SHIFT, mods.shift);
|
||||
self.toggle_modifier(KeyModifiers::ALT, mods.alt);
|
||||
self.toggle_modifier(KeyModifiers::SUPER, mods.logo);
|
||||
event.key = Key::Character(ch.to_string());
|
||||
self.event_queue
|
||||
.borrow_mut()
|
||||
.push(WindowEvent::Keyboard(event));
|
||||
}
|
||||
|
||||
fn handle_keyboard_input(
|
||||
&self,
|
||||
element_state: ElementState,
|
||||
code: VirtualKeyCode,
|
||||
mods: ModifiersState,
|
||||
input: KeyboardInput,
|
||||
) {
|
||||
self.toggle_keyboard_modifiers(mods);
|
||||
|
||||
if let Ok(key) = keyutils::winit_key_to_script_key(code) {
|
||||
let state = match element_state {
|
||||
ElementState::Pressed => KeyState::Pressed,
|
||||
ElementState::Released => KeyState::Released,
|
||||
};
|
||||
if element_state == ElementState::Pressed && keyutils::is_printable(code) {
|
||||
// If pressed and printable, we expect a ReceivedCharacter event.
|
||||
self.last_pressed_key.set(Some(key));
|
||||
} else {
|
||||
self.last_pressed_key.set(None);
|
||||
let modifiers = self.key_modifiers.get();
|
||||
self.event_queue
|
||||
.borrow_mut()
|
||||
.push(WindowEvent::KeyEvent(None, key, state, modifiers));
|
||||
}
|
||||
let event = keyboard_event_from_winit(input);
|
||||
if event.state == KeyState::Down && event.key == Key::Unidentified {
|
||||
// If pressed and probably printable, we expect a ReceivedCharacter event.
|
||||
self.last_pressed.set(Some(event));
|
||||
} else if event.key != Key::Unidentified {
|
||||
self.last_pressed.set(None);
|
||||
self.event_queue
|
||||
.borrow_mut()
|
||||
.push(WindowEvent::Keyboard(event));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -470,17 +456,11 @@ impl Window {
|
|||
Event::WindowEvent {
|
||||
event:
|
||||
winit::WindowEvent::KeyboardInput {
|
||||
input:
|
||||
winit::KeyboardInput {
|
||||
state,
|
||||
virtual_keycode: Some(virtual_keycode),
|
||||
modifiers,
|
||||
..
|
||||
},
|
||||
input,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => self.handle_keyboard_input(state, virtual_keycode, modifiers),
|
||||
} => self.handle_keyboard_input(input),
|
||||
Event::WindowEvent {
|
||||
event: winit::WindowEvent::MouseInput { state, button, .. },
|
||||
..
|
||||
|
@ -584,16 +564,6 @@ impl Window {
|
|||
}
|
||||
}
|
||||
|
||||
fn toggle_modifier(&self, modifier: KeyModifiers, pressed: bool) {
|
||||
let mut modifiers = self.key_modifiers.get();
|
||||
if pressed {
|
||||
modifiers.insert(modifier);
|
||||
} else {
|
||||
modifiers.remove(modifier);
|
||||
}
|
||||
self.key_modifiers.set(modifiers);
|
||||
}
|
||||
|
||||
/// Helper function to handle a click
|
||||
fn handle_mouse(
|
||||
&self,
|
||||
|
|
|
@ -8,6 +8,7 @@ extern crate euclid;
|
|||
extern crate gdi32;
|
||||
extern crate gleam;
|
||||
extern crate glutin;
|
||||
extern crate keyboard_types;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
|
|
|
@ -10,6 +10,6 @@ path = "lib.rs"
|
|||
|
||||
[dependencies]
|
||||
euclid = "0.19"
|
||||
msg = {path = "../../../components/msg"}
|
||||
keyboard-types = "0.4.2-servo"
|
||||
script = {path = "../../../components/script"}
|
||||
servo_url = {path = "../../../components/url"}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#[cfg(test)] extern crate euclid;
|
||||
#[cfg(test)] extern crate msg;
|
||||
#[cfg(test)] extern crate keyboard_types;
|
||||
#[cfg(test)] extern crate script;
|
||||
#[cfg(test)] extern crate servo_url;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use msg::constellation_msg::{Key, KeyModifiers};
|
||||
use keyboard_types::{Key, Modifiers};
|
||||
use script::clipboard_provider::DummyClipboardContext;
|
||||
use script::test::DOMString;
|
||||
use script::textinput::{TextInput, TextPoint, Selection, Lines, Direction, SelectionDirection};
|
||||
|
@ -420,34 +420,33 @@ fn test_textinput_adjust_horizontal_to_line_end() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "macos")]
|
||||
fn test_navigation_keyboard_shortcuts() {
|
||||
let mut textinput = text_input(Lines::Multiple, "hello áéc");
|
||||
|
||||
// Test that CMD + Right moves to the end of the current line.
|
||||
textinput.handle_keydown_aux(None, Key::Right, KeyModifiers::SUPER);
|
||||
textinput.handle_keydown_aux(Key::ArrowRight, Modifiers::META, true);
|
||||
assert_eq!(textinput.edit_point().index, 11);
|
||||
// Test that CMD + Right moves to the beginning of the current line.
|
||||
textinput.handle_keydown_aux(None, Key::Left, KeyModifiers::SUPER);
|
||||
textinput.handle_keydown_aux(Key::ArrowLeft, Modifiers::META, true);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
// Test that CTRL + ALT + E moves to the end of the current line also.
|
||||
textinput.handle_keydown_aux(None, Key::E, KeyModifiers::CONTROL | KeyModifiers::ALT);
|
||||
textinput.handle_keydown_aux(Key::Character("e".to_owned()), Modifiers::CONTROL | Modifiers::ALT, true);
|
||||
assert_eq!(textinput.edit_point().index, 11);
|
||||
// Test that CTRL + ALT + A moves to the beginning of the current line also.
|
||||
textinput.handle_keydown_aux(None, Key::A, KeyModifiers::CONTROL | KeyModifiers::ALT);
|
||||
textinput.handle_keydown_aux(Key::Character("a".to_owned()), Modifiers::CONTROL | Modifiers::ALT, true);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
|
||||
// Test that ALT + Right moves to the end of the word.
|
||||
textinput.handle_keydown_aux(None, Key::Right, KeyModifiers::ALT);
|
||||
textinput.handle_keydown_aux(Key::ArrowRight, Modifiers::ALT, true);
|
||||
assert_eq!(textinput.edit_point().index, 5);
|
||||
// Test that CTRL + ALT + F moves to the end of the word also.
|
||||
textinput.handle_keydown_aux(None, Key::F, KeyModifiers::CONTROL | KeyModifiers::ALT);
|
||||
textinput.handle_keydown_aux(Key::Character("f".to_owned()), Modifiers::CONTROL | Modifiers::ALT, true);
|
||||
assert_eq!(textinput.edit_point().index, 11);
|
||||
// Test that ALT + Left moves to the end of the word.
|
||||
textinput.handle_keydown_aux(None, Key::Left, KeyModifiers::ALT);
|
||||
textinput.handle_keydown_aux(Key::ArrowLeft, Modifiers::ALT, true);
|
||||
assert_eq!(textinput.edit_point().index, 6);
|
||||
// Test that CTRL + ALT + B moves to the end of the word also.
|
||||
textinput.handle_keydown_aux(None, Key::B, KeyModifiers::CONTROL | KeyModifiers::ALT);
|
||||
textinput.handle_keydown_aux(Key::Character("b".to_owned()), Modifiers::CONTROL | Modifiers::ALT, true);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
}
|
||||
|
||||
|
@ -507,9 +506,9 @@ fn test_textinput_set_content() {
|
|||
#[test]
|
||||
fn test_clipboard_paste() {
|
||||
#[cfg(target_os = "macos")]
|
||||
const MODIFIERS: KeyModifiers = KeyModifiers::SUPER;
|
||||
const MODIFIERS: Modifiers = Modifiers::META;
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
const MODIFIERS: KeyModifiers = KeyModifiers::CONTROL;
|
||||
const MODIFIERS: Modifiers = Modifiers::CONTROL;
|
||||
|
||||
let mut textinput = TextInput::new(Lines::Single,
|
||||
DOMString::from("defg"),
|
||||
|
@ -519,7 +518,7 @@ fn test_clipboard_paste() {
|
|||
SelectionDirection::None);
|
||||
assert_eq!(textinput.get_content(), "defg");
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
textinput.handle_keydown_aux(Some('v'), Key::V, MODIFIERS);
|
||||
textinput.handle_keydown_aux(Key::Character("v".to_owned()), MODIFIERS, false);
|
||||
assert_eq!(textinput.get_content(), "abcdefg");
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue