mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
Auto merge of #21881 - pyfisch:keyboard-types, r=paulrouget
Use keyboard-types crate Have embedders send DOM keys to servo and use a strongly typed KeyboardEvent from the W3C UI Events spec. All keyboard handling now uses the new types. Introduce a ShortcutMatcher to recognize key bindings. Shortcuts are now recognized in a uniform way. Updated the winit port. Updated webdriver integration. part of #20331 What this PR does: * allow the use non-ASCII keyboards for text input * decouple keyboard event "key" from "code" (key meaning vs location) What this PR does not do: * completely improve keyboard events send from winit and webdriver * add support for CompositionEvent or IME Notes: * The winit embedder does not send keyup events for printable keys (this is a regression) * keyboard-types is on crates.io because I believe it to be useful outside of servo. If you prefer I can add a copy in this repo. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21881) <!-- Reviewable:end -->
This commit is contained in:
commit
9a0404ac5f
35 changed files with 747 additions and 1673 deletions
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)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"msg 0.0.1",
|
"msg 0.0.1",
|
||||||
|
@ -534,6 +535,7 @@ dependencies = [
|
||||||
"gfx_traits 0.0.1",
|
"gfx_traits 0.0.1",
|
||||||
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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",
|
"layout_traits 0.0.1",
|
||||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"metrics 0.0.1",
|
"metrics 0.0.1",
|
||||||
|
@ -895,6 +897,7 @@ name = "embedder_traits"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ipc-channel 0.11.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)",
|
||||||
"lazy_static 1.0.0 (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)",
|
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"msg 0.0.1",
|
"msg 0.0.1",
|
||||||
|
@ -1726,6 +1729,15 @@ dependencies = [
|
||||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "khronos_api"
|
name = "khronos_api"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -2013,6 +2025,7 @@ dependencies = [
|
||||||
"hashglobe 0.1.0",
|
"hashglobe 0.1.0",
|
||||||
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"mozjs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"selectors 0.20.0",
|
"selectors 0.20.0",
|
||||||
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -2249,7 +2262,6 @@ dependencies = [
|
||||||
name = "msg"
|
name = "msg"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"malloc_size_of 0.0.1",
|
"malloc_size_of 0.0.1",
|
||||||
"malloc_size_of_derive 0.0.1",
|
"malloc_size_of_derive 0.0.1",
|
||||||
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jstraceable_derive 0.0.1",
|
"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)",
|
"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)",
|
"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)",
|
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -3084,7 +3097,7 @@ name = "script_tests"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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",
|
"script 0.0.1",
|
||||||
"servo_url 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 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)",
|
"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)",
|
"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)",
|
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"malloc_size_of 0.0.1",
|
"malloc_size_of 0.0.1",
|
||||||
"malloc_size_of_derive 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)",
|
"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)",
|
"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)",
|
"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)",
|
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libservo 0.0.1",
|
"libservo 0.0.1",
|
||||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"msg 0.0.1",
|
"msg 0.0.1",
|
||||||
"net_traits 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 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 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 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 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 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"
|
"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"
|
image = "0.19"
|
||||||
ipc-channel = "0.11"
|
ipc-channel = "0.11"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
keyboard-types = {version = "0.4.2-servo", features = ["serde"]}
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
msg = {path = "../msg"}
|
msg = {path = "../msg"}
|
||||||
net_traits = {path = "../net_traits"}
|
net_traits = {path = "../net_traits"}
|
||||||
|
|
|
@ -12,6 +12,7 @@ extern crate gleam;
|
||||||
#[cfg(feature = "gleam")]
|
#[cfg(feature = "gleam")]
|
||||||
extern crate image;
|
extern crate image;
|
||||||
extern crate ipc_channel;
|
extern crate ipc_channel;
|
||||||
|
extern crate keyboard_types;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
|
@ -8,7 +8,8 @@ use embedder_traits::EventLoopWaker;
|
||||||
use euclid::TypedScale;
|
use euclid::TypedScale;
|
||||||
#[cfg(feature = "gleam")]
|
#[cfg(feature = "gleam")]
|
||||||
use gleam::gl;
|
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 script_traits::{MouseButton, TouchEventType, TouchId};
|
||||||
use servo_geometry::{DeviceIndependentPixel, DeviceUintLength};
|
use servo_geometry::{DeviceIndependentPixel, DeviceUintLength};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
|
@ -70,7 +71,7 @@ pub enum WindowEvent {
|
||||||
/// Sent when the user quits the application
|
/// Sent when the user quits the application
|
||||||
Quit,
|
Quit,
|
||||||
/// Sent when a key input state changes
|
/// 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.
|
/// Sent when Ctr+R/Apple+R is called to reload the current page.
|
||||||
Reload(TopLevelBrowsingContextId),
|
Reload(TopLevelBrowsingContextId),
|
||||||
/// Create a new top level browsing context
|
/// Create a new top level browsing context
|
||||||
|
@ -94,7 +95,7 @@ impl Debug for WindowEvent {
|
||||||
WindowEvent::Idle => write!(f, "Idle"),
|
WindowEvent::Idle => write!(f, "Idle"),
|
||||||
WindowEvent::Refresh => write!(f, "Refresh"),
|
WindowEvent::Refresh => write!(f, "Refresh"),
|
||||||
WindowEvent::Resize => write!(f, "Resize"),
|
WindowEvent::Resize => write!(f, "Resize"),
|
||||||
WindowEvent::KeyEvent(..) => write!(f, "Key"),
|
WindowEvent::Keyboard(..) => write!(f, "Keyboard"),
|
||||||
WindowEvent::LoadUrl(..) => write!(f, "LoadUrl"),
|
WindowEvent::LoadUrl(..) => write!(f, "LoadUrl"),
|
||||||
WindowEvent::MouseWindowEventClass(..) => write!(f, "Mouse"),
|
WindowEvent::MouseWindowEventClass(..) => write!(f, "Mouse"),
|
||||||
WindowEvent::MouseWindowMoveEventClass(..) => write!(f, "MouseMove"),
|
WindowEvent::MouseWindowMoveEventClass(..) => write!(f, "MouseMove"),
|
||||||
|
|
|
@ -25,6 +25,7 @@ gfx_traits = {path = "../gfx_traits"}
|
||||||
hyper = "0.10"
|
hyper = "0.10"
|
||||||
ipc-channel = "0.11"
|
ipc-channel = "0.11"
|
||||||
layout_traits = {path = "../layout_traits"}
|
layout_traits = {path = "../layout_traits"}
|
||||||
|
keyboard-types = {version = "0.4.2-servo", features = ["serde"]}
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
metrics = {path = "../metrics"}
|
metrics = {path = "../metrics"}
|
||||||
msg = {path = "../msg"}
|
msg = {path = "../msg"}
|
||||||
|
|
|
@ -111,10 +111,10 @@ use gfx_traits::Epoch;
|
||||||
use ipc_channel::{Error as IpcError};
|
use ipc_channel::{Error as IpcError};
|
||||||
use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
|
use ipc_channel::ipc::{self, IpcSender, IpcReceiver};
|
||||||
use ipc_channel::router::ROUTER;
|
use ipc_channel::router::ROUTER;
|
||||||
|
use keyboard_types::KeyboardEvent;
|
||||||
use layout_traits::LayoutThreadFactory;
|
use layout_traits::LayoutThreadFactory;
|
||||||
use log::{Log, Level, LevelFilter, Metadata, Record};
|
use log::{Log, Level, LevelFilter, Metadata, Record};
|
||||||
use msg::constellation_msg::{BrowsingContextId, PipelineId, HistoryStateId, TopLevelBrowsingContextId};
|
use msg::constellation_msg::{BrowsingContextId, PipelineId, HistoryStateId, TopLevelBrowsingContextId};
|
||||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
|
||||||
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
|
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
|
||||||
use net_traits::{self, IpcSend, FetchResponseMsg, ResourceThreads};
|
use net_traits::{self, IpcSend, FetchResponseMsg, ResourceThreads};
|
||||||
use net_traits::pub_domains::reg_host;
|
use net_traits::pub_domains::reg_host;
|
||||||
|
@ -972,8 +972,8 @@ where
|
||||||
});
|
});
|
||||||
let _ = resp_chan.send(focus_browsing_context);
|
let _ = resp_chan.send(focus_browsing_context);
|
||||||
},
|
},
|
||||||
FromCompositorMsg::KeyEvent(ch, key, state, modifiers) => {
|
FromCompositorMsg::Keyboard(key_event) => {
|
||||||
self.handle_key_msg(ch, key, state, modifiers);
|
self.handle_key_msg(key_event);
|
||||||
},
|
},
|
||||||
// Load a new page from a typed url
|
// Load a new page from a typed url
|
||||||
// If there is already a pending page (self.pending_changes), it will not be overridden;
|
// 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);
|
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
|
// Send to the focused browsing contexts' current pipeline. If it
|
||||||
// doesn't exist, fall back to sending to the compositor.
|
// doesn't exist, fall back to sending to the compositor.
|
||||||
match self.focused_browsing_context_id {
|
match self.focused_browsing_context_id {
|
||||||
Some(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) {
|
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
|
||||||
Some(ctx) => ctx.pipeline_id,
|
Some(ctx) => ctx.pipeline_id,
|
||||||
None => return warn!(
|
None => return warn!(
|
||||||
|
@ -2647,7 +2647,7 @@ where
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let event = (None, EmbedderMsg::KeyEvent(ch, key, state, mods));
|
let event = (None, EmbedderMsg::Keyboard(event));
|
||||||
self.embedder_proxy.clone().send(event);
|
self.embedder_proxy.clone().send(event);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -2942,8 +2942,8 @@ where
|
||||||
Some(pipeline) => pipeline.event_loop.clone(),
|
Some(pipeline) => pipeline.event_loop.clone(),
|
||||||
None => return warn!("Pipeline {} SendKeys after closure.", pipeline_id),
|
None => return warn!("Pipeline {} SendKeys after closure.", pipeline_id),
|
||||||
};
|
};
|
||||||
for (key, mods, state) in cmd {
|
for event in cmd {
|
||||||
let event = CompositorEvent::KeyEvent(None, key, state, mods);
|
let event = CompositorEvent::KeyboardEvent(event);
|
||||||
let control_msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
|
let control_msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
|
||||||
if let Err(e) = event_loop.send(control_msg) {
|
if let Err(e) = event_loop.send(control_msg) {
|
||||||
return self.handle_send_error(pipeline_id, e);
|
return self.handle_send_error(pipeline_id, e);
|
||||||
|
|
|
@ -22,6 +22,7 @@ extern crate gfx;
|
||||||
extern crate gfx_traits;
|
extern crate gfx_traits;
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
extern crate ipc_channel;
|
extern crate ipc_channel;
|
||||||
|
extern crate keyboard_types;
|
||||||
extern crate layout_traits;
|
extern crate layout_traits;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
|
@ -11,6 +11,7 @@ path = "lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ipc-channel = "0.11"
|
ipc-channel = "0.11"
|
||||||
|
keyboard-types = {version = "0.4.2-servo", features = ["serde"]}
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
msg = {path = "../msg"}
|
msg = {path = "../msg"}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
extern crate ipc_channel;
|
extern crate ipc_channel;
|
||||||
|
extern crate keyboard_types;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -18,7 +19,8 @@ extern crate webrender_api;
|
||||||
pub mod resources;
|
pub mod resources;
|
||||||
|
|
||||||
use ipc_channel::ipc::IpcSender;
|
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_channel::{Receiver, Sender};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use std::fmt::{Debug, Error, Formatter};
|
use std::fmt::{Debug, Error, Formatter};
|
||||||
|
@ -93,7 +95,7 @@ pub enum EmbedderMsg {
|
||||||
/// Wether or not to unload a document
|
/// Wether or not to unload a document
|
||||||
AllowUnload(IpcSender<bool>),
|
AllowUnload(IpcSender<bool>),
|
||||||
/// Sends an unconsumed key event back to the embedder.
|
/// Sends an unconsumed key event back to the embedder.
|
||||||
KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
|
Keyboard(KeyboardEvent),
|
||||||
/// Changes the cursor.
|
/// Changes the cursor.
|
||||||
SetCursor(CursorKind),
|
SetCursor(CursorKind),
|
||||||
/// A favicon was detected
|
/// A favicon was detected
|
||||||
|
@ -134,7 +136,7 @@ impl Debug for EmbedderMsg {
|
||||||
EmbedderMsg::Alert(..) => write!(f, "Alert"),
|
EmbedderMsg::Alert(..) => write!(f, "Alert"),
|
||||||
EmbedderMsg::AllowUnload(..) => write!(f, "AllowUnload"),
|
EmbedderMsg::AllowUnload(..) => write!(f, "AllowUnload"),
|
||||||
EmbedderMsg::AllowNavigation(..) => write!(f, "AllowNavigation"),
|
EmbedderMsg::AllowNavigation(..) => write!(f, "AllowNavigation"),
|
||||||
EmbedderMsg::KeyEvent(..) => write!(f, "KeyEvent"),
|
EmbedderMsg::Keyboard(..) => write!(f, "Keyboard"),
|
||||||
EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"),
|
EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"),
|
||||||
EmbedderMsg::NewFavicon(..) => write!(f, "NewFavicon"),
|
EmbedderMsg::NewFavicon(..) => write!(f, "NewFavicon"),
|
||||||
EmbedderMsg::HeadParsed => write!(f, "HeadParsed"),
|
EmbedderMsg::HeadParsed => write!(f, "HeadParsed"),
|
||||||
|
|
|
@ -12,6 +12,7 @@ path = "lib.rs"
|
||||||
servo = [
|
servo = [
|
||||||
"hyper",
|
"hyper",
|
||||||
"hyper_serde",
|
"hyper_serde",
|
||||||
|
"keyboard-types",
|
||||||
"mozjs",
|
"mozjs",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_bytes",
|
"serde_bytes",
|
||||||
|
@ -30,6 +31,7 @@ euclid = "0.19"
|
||||||
hashglobe = { path = "../hashglobe" }
|
hashglobe = { path = "../hashglobe" }
|
||||||
hyper = { version = "0.10", optional = true }
|
hyper = { version = "0.10", optional = true }
|
||||||
hyper_serde = { version = "0.8", 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 }
|
mozjs = { version = "0.9.0", optional = true }
|
||||||
selectors = { path = "../selectors" }
|
selectors = { path = "../selectors" }
|
||||||
serde = { version = "1.0.27", optional = true }
|
serde = { version = "1.0.27", optional = true }
|
||||||
|
|
|
@ -52,6 +52,8 @@ extern crate hyper;
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
extern crate hyper_serde;
|
extern crate hyper_serde;
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
|
extern crate keyboard_types;
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
extern crate mozjs as js;
|
extern crate mozjs as js;
|
||||||
extern crate selectors;
|
extern crate selectors;
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
|
@ -955,6 +957,19 @@ malloc_size_of_is_0!(webrender_api::StickyOffsetBounds);
|
||||||
#[cfg(feature = "webrender_api")]
|
#[cfg(feature = "webrender_api")]
|
||||||
malloc_size_of_is_0!(webrender_api::TransformStyle);
|
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")]
|
#[cfg(feature = "servo")]
|
||||||
impl MallocSizeOf for xml5ever::QualName {
|
impl MallocSizeOf for xml5ever::QualName {
|
||||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||||
|
|
|
@ -12,7 +12,6 @@ test = false
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "1.0"
|
|
||||||
malloc_size_of = { path = "../malloc_size_of" }
|
malloc_size_of = { path = "../malloc_size_of" }
|
||||||
malloc_size_of_derive = { path = "../malloc_size_of_derive" }
|
malloc_size_of_derive = { path = "../malloc_size_of_derive" }
|
||||||
serde = "1.0.60"
|
serde = "1.0.60"
|
||||||
|
|
|
@ -10,153 +10,6 @@ use std::fmt;
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use webrender_api;
|
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)]
|
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
pub enum TraversalDirection {
|
pub enum TraversalDirection {
|
||||||
Forward(usize),
|
Forward(usize),
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate bitflags;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate malloc_size_of;
|
extern crate malloc_size_of;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -58,6 +58,7 @@ image = "0.19"
|
||||||
ipc-channel = "0.11"
|
ipc-channel = "0.11"
|
||||||
itertools = "0.7.6"
|
itertools = "0.7.6"
|
||||||
jstraceable_derive = {path = "../jstraceable_derive"}
|
jstraceable_derive = {path = "../jstraceable_derive"}
|
||||||
|
keyboard-types = {version = "0.4.2-servo", features = ["serde"]}
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
|
@ -100,9 +100,10 @@ use hyper_serde::Serde;
|
||||||
use ipc_channel::ipc::{self, IpcSender};
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
use js::jsapi::{JSContext, JSObject, JSRuntime};
|
use js::jsapi::{JSContext, JSObject, JSRuntime};
|
||||||
use js::jsapi::JS_GetRuntime;
|
use js::jsapi::JS_GetRuntime;
|
||||||
|
use keyboard_types::{Key, KeyState, Modifiers};
|
||||||
use metrics::{InteractiveFlag, InteractiveMetrics, InteractiveWindow, ProfilerMetadataFactory, ProgressiveWebMetric};
|
use metrics::{InteractiveFlag, InteractiveMetrics, InteractiveWindow, ProfilerMetadataFactory, ProgressiveWebMetric};
|
||||||
use mime::{Mime, TopLevel, SubLevel};
|
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::{FetchResponseMsg, IpcSend, ReferrerPolicy};
|
||||||
use net_traits::CookieSource::NonHTTP;
|
use net_traits::CookieSource::NonHTTP;
|
||||||
use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
|
use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
|
||||||
|
@ -769,7 +770,9 @@ impl Document {
|
||||||
// Step 1 is not handled here; the fragid is already obtained by the calling function
|
// 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 2: Simply use None to indicate the top of the document.
|
||||||
// Step 3 & 4
|
// Step 3 & 4
|
||||||
percent_decode(fragid.as_bytes()).decode_utf8().ok()
|
percent_decode(fragid.as_bytes())
|
||||||
|
.decode_utf8()
|
||||||
|
.ok()
|
||||||
// Step 5
|
// Step 5
|
||||||
.and_then(|decoded_fragid| self.get_element_by_id(&Atom::from(decoded_fragid)))
|
.and_then(|decoded_fragid| self.get_element_by_id(&Atom::from(decoded_fragid)))
|
||||||
// Step 6
|
// Step 6
|
||||||
|
@ -805,7 +808,8 @@ impl Document {
|
||||||
rect.origin.x.to_nearest_px() as f32,
|
rect.origin.x.to_nearest_px() as f32,
|
||||||
rect.origin.y.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") {
|
if fragment.is_empty() || fragment.eq_ignore_ascii_case("top") {
|
||||||
// FIXME(stshine): this should be the origin of the stacking context space,
|
// FIXME(stshine): this should be the origin of the stacking context space,
|
||||||
// which may differ under the influence of writing mode.
|
// 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
|
/// The entry point for all key processing for web content
|
||||||
pub fn dispatch_key_event(
|
pub fn dispatch_key_event(&self, keyboard_event: ::keyboard_types::KeyboardEvent) {
|
||||||
&self,
|
|
||||||
ch: Option<char>,
|
|
||||||
key: Key,
|
|
||||||
state: KeyState,
|
|
||||||
modifiers: KeyModifiers,
|
|
||||||
) {
|
|
||||||
let focused = self.get_focused_element();
|
let focused = self.get_focused_element();
|
||||||
let body = self.GetBody();
|
let body = self.GetBody();
|
||||||
|
|
||||||
|
@ -1364,50 +1362,29 @@ impl Document {
|
||||||
(&None, &None) => self.window.upcast(),
|
(&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(
|
let keyevent = KeyboardEvent::new(
|
||||||
&self.window,
|
&self.window,
|
||||||
ev_type,
|
DOMString::from(keyboard_event.state.to_string()),
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
Some(&self.window),
|
Some(&self.window),
|
||||||
0,
|
0,
|
||||||
ch,
|
keyboard_event.key.clone(),
|
||||||
Some(key),
|
DOMString::from(keyboard_event.code.to_string()),
|
||||||
DOMString::from(props.key_string.clone()),
|
keyboard_event.location as u32,
|
||||||
DOMString::from(props.code),
|
keyboard_event.repeat,
|
||||||
props.location,
|
keyboard_event.is_composing,
|
||||||
is_repeating,
|
keyboard_event.modifiers,
|
||||||
is_composing,
|
0,
|
||||||
ctrl,
|
keyboard_event.key.legacy_keycode(),
|
||||||
alt,
|
|
||||||
shift,
|
|
||||||
meta,
|
|
||||||
None,
|
|
||||||
props.key_code,
|
|
||||||
);
|
);
|
||||||
let event = keyevent.upcast::<Event>();
|
let event = keyevent.upcast::<Event>();
|
||||||
event.fire(target);
|
event.fire(target);
|
||||||
let mut cancel_state = event.get_cancel_state();
|
let mut cancel_state = event.get_cancel_state();
|
||||||
|
|
||||||
// https://w3c.github.io/uievents/#keys-cancelable-keys
|
// https://w3c.github.io/uievents/#keys-cancelable-keys
|
||||||
if state != KeyState::Released &&
|
if keyboard_event.state == KeyState::Down &&
|
||||||
props.is_printable() &&
|
keyboard_event.key.legacy_charcode() != 0 &&
|
||||||
cancel_state != EventDefault::Prevented
|
cancel_state != EventDefault::Prevented
|
||||||
{
|
{
|
||||||
// https://w3c.github.io/uievents/#keypress-event-order
|
// https://w3c.github.io/uievents/#keypress-event-order
|
||||||
|
@ -1418,18 +1395,13 @@ impl Document {
|
||||||
true,
|
true,
|
||||||
Some(&self.window),
|
Some(&self.window),
|
||||||
0,
|
0,
|
||||||
ch,
|
keyboard_event.key.clone(),
|
||||||
Some(key),
|
DOMString::from(keyboard_event.code.to_string()),
|
||||||
DOMString::from(props.key_string),
|
keyboard_event.location as u32,
|
||||||
DOMString::from(props.code),
|
keyboard_event.repeat,
|
||||||
props.location,
|
keyboard_event.is_composing,
|
||||||
is_repeating,
|
keyboard_event.modifiers,
|
||||||
is_composing,
|
keyboard_event.key.legacy_charcode(),
|
||||||
ctrl,
|
|
||||||
alt,
|
|
||||||
shift,
|
|
||||||
meta,
|
|
||||||
props.char_code,
|
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
let ev = event.upcast::<Event>();
|
let ev = event.upcast::<Event>();
|
||||||
|
@ -1438,7 +1410,7 @@ impl Document {
|
||||||
}
|
}
|
||||||
|
|
||||||
if cancel_state == EventDefault::Allowed {
|
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);
|
self.send_to_embedder(msg);
|
||||||
|
|
||||||
// This behavior is unspecced
|
// This behavior is unspecced
|
||||||
|
@ -1446,8 +1418,10 @@ impl Document {
|
||||||
// however *when* we do it is up to us.
|
// 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
|
// 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
|
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=27337
|
||||||
match key {
|
match keyboard_event.key {
|
||||||
Key::Space if state == KeyState::Released => {
|
Key::Character(ref letter)
|
||||||
|
if letter == " " && keyboard_event.state == KeyState::Up =>
|
||||||
|
{
|
||||||
let maybe_elem = target.downcast::<Element>();
|
let maybe_elem = target.downcast::<Element>();
|
||||||
if let Some(el) = maybe_elem {
|
if let Some(el) = maybe_elem {
|
||||||
synthetic_click_activation(
|
synthetic_click_activation(
|
||||||
|
@ -1459,11 +1433,15 @@ impl Document {
|
||||||
ActivationSource::NotFromClick,
|
ActivationSource::NotFromClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Key::Enter if state == KeyState::Released => {
|
Key::Enter if keyboard_event.state == KeyState::Up => {
|
||||||
let maybe_elem = target.downcast::<Element>();
|
let maybe_elem = target.downcast::<Element>();
|
||||||
if let Some(el) = maybe_elem {
|
if let Some(el) = maybe_elem {
|
||||||
if let Some(a) = el.as_maybe_activatable() {
|
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);
|
a.implicit_submission(ctrl, alt, shift, meta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use dom::bindings::cell::DomRefCell;
|
use dom::bindings::cell::DomRefCell;
|
||||||
use dom::bindings::codegen::Bindings::KeyboardEventBinding;
|
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::codegen::Bindings::UIEventBinding::UIEventMethods;
|
||||||
use dom::bindings::error::Fallible;
|
use dom::bindings::error::Fallible;
|
||||||
use dom::bindings::inheritance::Castable;
|
use dom::bindings::inheritance::Castable;
|
||||||
|
@ -15,47 +15,39 @@ use dom::event::Event;
|
||||||
use dom::uievent::UIEvent;
|
use dom::uievent::UIEvent;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use msg::constellation_msg::{Key, KeyModifiers};
|
use keyboard_types::{Key, Modifiers};
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
|
||||||
unsafe_no_jsmanaged_fields!(Key);
|
unsafe_no_jsmanaged_fields!(Key);
|
||||||
|
unsafe_no_jsmanaged_fields!(Modifiers);
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct KeyboardEvent {
|
pub struct KeyboardEvent {
|
||||||
uievent: UIEvent,
|
uievent: UIEvent,
|
||||||
key: Cell<Option<Key>>,
|
key: DomRefCell<DOMString>,
|
||||||
key_string: DomRefCell<DOMString>,
|
typed_key: DomRefCell<Key>,
|
||||||
code: DomRefCell<DOMString>,
|
code: DomRefCell<DOMString>,
|
||||||
location: Cell<u32>,
|
location: Cell<u32>,
|
||||||
ctrl: Cell<bool>,
|
modifiers: Cell<Modifiers>,
|
||||||
alt: Cell<bool>,
|
|
||||||
shift: Cell<bool>,
|
|
||||||
meta: Cell<bool>,
|
|
||||||
repeat: Cell<bool>,
|
repeat: Cell<bool>,
|
||||||
is_composing: Cell<bool>,
|
is_composing: Cell<bool>,
|
||||||
char_code: Cell<Option<u32>>,
|
char_code: Cell<u32>,
|
||||||
key_code: Cell<u32>,
|
key_code: Cell<u32>,
|
||||||
printable: Cell<Option<char>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyboardEvent {
|
impl KeyboardEvent {
|
||||||
fn new_inherited() -> KeyboardEvent {
|
fn new_inherited() -> KeyboardEvent {
|
||||||
KeyboardEvent {
|
KeyboardEvent {
|
||||||
uievent: UIEvent::new_inherited(),
|
uievent: UIEvent::new_inherited(),
|
||||||
key: Cell::new(None),
|
key: DomRefCell::new(DOMString::new()),
|
||||||
key_string: DomRefCell::new(DOMString::new()),
|
typed_key: DomRefCell::new(Key::Unidentified),
|
||||||
code: DomRefCell::new(DOMString::new()),
|
code: DomRefCell::new(DOMString::new()),
|
||||||
location: Cell::new(0),
|
location: Cell::new(0),
|
||||||
ctrl: Cell::new(false),
|
modifiers: Cell::new(Modifiers::empty()),
|
||||||
alt: Cell::new(false),
|
|
||||||
shift: Cell::new(false),
|
|
||||||
meta: Cell::new(false),
|
|
||||||
repeat: Cell::new(false),
|
repeat: Cell::new(false),
|
||||||
is_composing: Cell::new(false),
|
is_composing: Cell::new(false),
|
||||||
char_code: Cell::new(None),
|
char_code: Cell::new(0),
|
||||||
key_code: Cell::new(0),
|
key_code: Cell::new(0),
|
||||||
printable: Cell::new(None),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,18 +66,13 @@ impl KeyboardEvent {
|
||||||
cancelable: bool,
|
cancelable: bool,
|
||||||
view: Option<&Window>,
|
view: Option<&Window>,
|
||||||
_detail: i32,
|
_detail: i32,
|
||||||
ch: Option<char>,
|
key: Key,
|
||||||
key: Option<Key>,
|
|
||||||
key_string: DOMString,
|
|
||||||
code: DOMString,
|
code: DOMString,
|
||||||
location: u32,
|
location: u32,
|
||||||
repeat: bool,
|
repeat: bool,
|
||||||
is_composing: bool,
|
is_composing: bool,
|
||||||
ctrl_key: bool,
|
modifiers: Modifiers,
|
||||||
alt_key: bool,
|
char_code: u32,
|
||||||
shift_key: bool,
|
|
||||||
meta_key: bool,
|
|
||||||
char_code: Option<u32>,
|
|
||||||
key_code: u32,
|
key_code: u32,
|
||||||
) -> DomRoot<KeyboardEvent> {
|
) -> DomRoot<KeyboardEvent> {
|
||||||
let ev = KeyboardEvent::new_uninitialized(window);
|
let ev = KeyboardEvent::new_uninitialized(window);
|
||||||
|
@ -94,22 +81,18 @@ impl KeyboardEvent {
|
||||||
can_bubble,
|
can_bubble,
|
||||||
cancelable,
|
cancelable,
|
||||||
view,
|
view,
|
||||||
key_string,
|
DOMString::from(key.to_string()),
|
||||||
location,
|
location,
|
||||||
DOMString::new(),
|
DOMString::new(),
|
||||||
repeat,
|
repeat,
|
||||||
DOMString::new(),
|
DOMString::new(),
|
||||||
);
|
);
|
||||||
ev.key.set(key);
|
*ev.typed_key.borrow_mut() = key;
|
||||||
*ev.code.borrow_mut() = code;
|
*ev.code.borrow_mut() = code;
|
||||||
ev.ctrl.set(ctrl_key);
|
ev.modifiers.set(modifiers);
|
||||||
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.is_composing.set(is_composing);
|
ev.is_composing.set(is_composing);
|
||||||
|
ev.char_code.set(char_code);
|
||||||
|
ev.key_code.set(key_code);
|
||||||
ev
|
ev
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,6 +101,11 @@ impl KeyboardEvent {
|
||||||
type_: DOMString,
|
type_: DOMString,
|
||||||
init: &KeyboardEventBinding::KeyboardEventInit,
|
init: &KeyboardEventBinding::KeyboardEventInit,
|
||||||
) -> Fallible<DomRoot<KeyboardEvent>> {
|
) -> 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(
|
let event = KeyboardEvent::new(
|
||||||
window,
|
window,
|
||||||
type_,
|
type_,
|
||||||
|
@ -125,680 +113,27 @@ impl KeyboardEvent {
|
||||||
init.parent.parent.parent.cancelable,
|
init.parent.parent.parent.cancelable,
|
||||||
init.parent.parent.view.r(),
|
init.parent.parent.view.r(),
|
||||||
init.parent.parent.detail,
|
init.parent.parent.detail,
|
||||||
None,
|
Key::Unidentified,
|
||||||
key_from_string(&init.key, init.location),
|
|
||||||
init.key.clone(),
|
|
||||||
init.code.clone(),
|
init.code.clone(),
|
||||||
init.location,
|
init.location,
|
||||||
init.repeat,
|
init.repeat,
|
||||||
init.isComposing,
|
init.isComposing,
|
||||||
init.parent.ctrlKey,
|
modifiers,
|
||||||
init.parent.altKey,
|
0,
|
||||||
init.parent.shiftKey,
|
|
||||||
init.parent.metaKey,
|
|
||||||
None,
|
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
*event.key.borrow_mut() = init.key.clone();
|
||||||
Ok(event)
|
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 {
|
impl KeyboardEvent {
|
||||||
pub fn printable(&self) -> Option<char> {
|
pub fn key(&self) -> Key {
|
||||||
self.printable.get()
|
self.typed_key.borrow().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_key(&self) -> Option<Key> {
|
pub fn modifiers(&self) -> Modifiers {
|
||||||
self.key.get().clone()
|
self.modifiers.get()
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -822,14 +157,14 @@ impl KeyboardEventMethods for KeyboardEvent {
|
||||||
|
|
||||||
self.upcast::<UIEvent>()
|
self.upcast::<UIEvent>()
|
||||||
.InitUIEvent(type_arg, can_bubble_arg, cancelable_arg, view_arg, 0);
|
.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.location.set(location_arg);
|
||||||
self.repeat.set(repeat);
|
self.repeat.set(repeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-key
|
// https://w3c.github.io/uievents/#widl-KeyboardEvent-key
|
||||||
fn Key(&self) -> DOMString {
|
fn Key(&self) -> DOMString {
|
||||||
self.key_string.borrow().clone()
|
self.key.borrow().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-code
|
// https://w3c.github.io/uievents/#widl-KeyboardEvent-code
|
||||||
|
@ -844,22 +179,22 @@ impl KeyboardEventMethods for KeyboardEvent {
|
||||||
|
|
||||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-ctrlKey
|
// https://w3c.github.io/uievents/#widl-KeyboardEvent-ctrlKey
|
||||||
fn CtrlKey(&self) -> bool {
|
fn CtrlKey(&self) -> bool {
|
||||||
self.ctrl.get()
|
self.modifiers.get().contains(Modifiers::CONTROL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-shiftKey
|
// https://w3c.github.io/uievents/#widl-KeyboardEvent-shiftKey
|
||||||
fn ShiftKey(&self) -> bool {
|
fn ShiftKey(&self) -> bool {
|
||||||
self.shift.get()
|
self.modifiers.get().contains(Modifiers::SHIFT)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-altKey
|
// https://w3c.github.io/uievents/#widl-KeyboardEvent-altKey
|
||||||
fn AltKey(&self) -> bool {
|
fn AltKey(&self) -> bool {
|
||||||
self.alt.get()
|
self.modifiers.get().contains(Modifiers::ALT)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-metaKey
|
// https://w3c.github.io/uievents/#widl-KeyboardEvent-metaKey
|
||||||
fn MetaKey(&self) -> bool {
|
fn MetaKey(&self) -> bool {
|
||||||
self.meta.get()
|
self.modifiers.get().contains(Modifiers::META)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-repeat
|
// https://w3c.github.io/uievents/#widl-KeyboardEvent-repeat
|
||||||
|
@ -874,20 +209,26 @@ impl KeyboardEventMethods for KeyboardEvent {
|
||||||
|
|
||||||
// https://w3c.github.io/uievents/#dom-keyboardevent-getmodifierstate
|
// https://w3c.github.io/uievents/#dom-keyboardevent-getmodifierstate
|
||||||
fn GetModifierState(&self, key_arg: DOMString) -> bool {
|
fn GetModifierState(&self, key_arg: DOMString) -> bool {
|
||||||
match &*key_arg {
|
self.modifiers.get().contains(match &*key_arg {
|
||||||
"Ctrl" => self.CtrlKey(),
|
"Alt" => Modifiers::ALT,
|
||||||
"Alt" => self.AltKey(),
|
"AltGraph" => Modifiers::ALT_GRAPH,
|
||||||
"Shift" => self.ShiftKey(),
|
"CapsLock" => Modifiers::CAPS_LOCK,
|
||||||
"Meta" => self.MetaKey(),
|
"Control" => Modifiers::CONTROL,
|
||||||
"AltGraph" | "CapsLock" | "NumLock" | "ScrollLock" | "Accel" | "Fn" | "FnLock" |
|
"Fn" => Modifiers::FN,
|
||||||
"Hyper" | "OS" | "Symbol" | "SymbolLock" => false, //FIXME
|
"FnLock" => Modifiers::FN_LOCK,
|
||||||
_ => false,
|
"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
|
// https://w3c.github.io/uievents/#widl-KeyboardEvent-charCode
|
||||||
fn CharCode(&self) -> u32 {
|
fn CharCode(&self) -> u32 {
|
||||||
self.char_code.get().unwrap_or(0)
|
self.char_code.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-keyCode
|
// https://w3c.github.io/uievents/#widl-KeyboardEvent-keyCode
|
||||||
|
@ -897,7 +238,11 @@ impl KeyboardEventMethods for KeyboardEvent {
|
||||||
|
|
||||||
// https://w3c.github.io/uievents/#widl-KeyboardEvent-which
|
// https://w3c.github.io/uievents/#widl-KeyboardEvent-which
|
||||||
fn Which(&self) -> u32 {
|
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
|
// https://dom.spec.whatwg.org/#dom-event-istrusted
|
||||||
|
|
|
@ -54,6 +54,7 @@ extern crate image;
|
||||||
extern crate ipc_channel;
|
extern crate ipc_channel;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate jstraceable_derive;
|
extern crate jstraceable_derive;
|
||||||
|
extern crate keyboard_types;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
|
@ -96,7 +96,7 @@ use script_traits::{ProgressiveWebMetricType, Painter, ScriptMsg, ScriptThreadFa
|
||||||
use script_traits::{ScriptToConstellationChan, TimerEvent, TimerSchedulerMsg};
|
use script_traits::{ScriptToConstellationChan, TimerEvent, TimerSchedulerMsg};
|
||||||
use script_traits::{TimerSource, TouchEventType, TouchId, UntrustedNodeAddress};
|
use script_traits::{TimerSource, TouchEventType, TouchId, UntrustedNodeAddress};
|
||||||
use script_traits::{UpdatePipelineIdReason, WindowSizeData, WindowSizeType};
|
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 script_traits::webdriver_msg::WebDriverScriptCommand;
|
||||||
use serviceworkerjob::{Job, JobQueue};
|
use serviceworkerjob::{Job, JobQueue};
|
||||||
use servo_atoms::Atom;
|
use servo_atoms::Atom;
|
||||||
|
@ -2823,6 +2823,7 @@ impl ScriptThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
TouchEvent(event_type, identifier, point, node_address) => {
|
TouchEvent(event_type, identifier, point, node_address) => {
|
||||||
let touch_result = self.handle_touch_event(
|
let touch_result = self.handle_touch_event(
|
||||||
pipeline_id,
|
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) } {
|
let document = match { self.documents.borrow().find_document(pipeline_id) } {
|
||||||
Some(document) => document,
|
Some(document) => document,
|
||||||
None => return warn!("Message sent to closed pipeline {}.", pipeline_id),
|
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 clipboard_provider::ClipboardProvider;
|
||||||
use dom::bindings::str::DOMString;
|
use dom::bindings::str::DOMString;
|
||||||
use dom::keyboardevent::KeyboardEvent;
|
use dom::keyboardevent::KeyboardEvent;
|
||||||
use msg::constellation_msg::{Key, KeyModifiers};
|
use keyboard_types::{Key, KeyState, Modifiers, ShortcutMatcher};
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
@ -130,17 +130,11 @@ pub enum Direction {
|
||||||
Backward,
|
Backward,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Was the keyboard event accompanied by the standard control modifier,
|
// Some shortcuts use Cmd on Mac and Control on other systems.
|
||||||
/// i.e. cmd on Mac OS or ctrl on other platforms.
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
fn is_control_key(mods: KeyModifiers) -> bool {
|
pub const CMD_OR_CONTROL: Modifiers = Modifiers::META;
|
||||||
mods.contains(KeyModifiers::SUPER) && !mods.contains(KeyModifiers::CONTROL | KeyModifiers::ALT)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
fn is_control_key(mods: KeyModifiers) -> bool {
|
pub const CMD_OR_CONTROL: Modifiers = Modifiers::CONTROL;
|
||||||
mods.contains(KeyModifiers::CONTROL) && !mods.contains(KeyModifiers::SUPER | KeyModifiers::ALT)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The length in bytes of the first n characters in a UTF-8 string.
|
/// 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.
|
/// Process a given `KeyboardEvent` and return an action for the caller to execute.
|
||||||
pub fn handle_keydown(&mut self, event: &KeyboardEvent) -> KeyReaction {
|
pub fn handle_keydown(&mut self, event: &KeyboardEvent) -> KeyReaction {
|
||||||
if let Some(key) = event.get_key() {
|
let key = event.key();
|
||||||
self.handle_keydown_aux(event.printable(), key, event.get_key_modifiers())
|
let mods = event.modifiers();
|
||||||
} else {
|
self.handle_keydown_aux(key, mods, cfg!(target_os = "macos"))
|
||||||
KeyReaction::Nothing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function exists for easy unit testing.
|
||||||
|
// To test Mac OS shortcuts on other systems a flag is passed.
|
||||||
pub fn handle_keydown_aux(
|
pub fn handle_keydown_aux(
|
||||||
&mut self,
|
&mut self,
|
||||||
printable: Option<char>,
|
|
||||||
key: Key,
|
key: Key,
|
||||||
mods: KeyModifiers,
|
mut mods: Modifiers,
|
||||||
|
macos: bool,
|
||||||
) -> KeyReaction {
|
) -> KeyReaction {
|
||||||
let maybe_select = if mods.contains(KeyModifiers::SHIFT) {
|
let maybe_select = if mods.contains(Modifiers::SHIFT) {
|
||||||
Selection::Selected
|
Selection::Selected
|
||||||
} else {
|
} else {
|
||||||
Selection::NotSelected
|
Selection::NotSelected
|
||||||
};
|
};
|
||||||
|
mods.remove(Modifiers::SHIFT);
|
||||||
match (printable, key) {
|
ShortcutMatcher::new(KeyState::Down, key.clone(), mods)
|
||||||
(_, Key::B) if mods.contains(KeyModifiers::CONTROL | KeyModifiers::ALT) => {
|
.shortcut(Modifiers::CONTROL | Modifiers::ALT, 'B', || {
|
||||||
self.adjust_horizontal_by_word(Direction::Backward, maybe_select);
|
self.adjust_horizontal_by_word(Direction::Backward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
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);
|
self.adjust_horizontal_by_word(Direction::Forward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
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);
|
self.adjust_horizontal_to_line_end(Direction::Backward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
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);
|
self.adjust_horizontal_to_line_end(Direction::Forward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
},
|
})
|
||||||
#[cfg(target_os = "macos")]
|
.optional_shortcut(macos, Modifiers::CONTROL, 'A', || {
|
||||||
(None, Key::A) if mods == KeyModifiers::CONTROL =>
|
|
||||||
{
|
|
||||||
self.adjust_horizontal_to_line_end(Direction::Backward, maybe_select);
|
self.adjust_horizontal_to_line_end(Direction::Backward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
}
|
})
|
||||||
#[cfg(target_os = "macos")]
|
.optional_shortcut(macos, Modifiers::CONTROL, 'E', || {
|
||||||
(None, Key::E) if mods == KeyModifiers::CONTROL =>
|
|
||||||
{
|
|
||||||
self.adjust_horizontal_to_line_end(Direction::Forward, maybe_select);
|
self.adjust_horizontal_to_line_end(Direction::Forward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
}
|
})
|
||||||
(_, Key::A) if is_control_key(mods) => {
|
.shortcut(CMD_OR_CONTROL, 'A', || {
|
||||||
self.select_all();
|
self.select_all();
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
},
|
})
|
||||||
(_, Key::C) if is_control_key(mods) => {
|
.shortcut(CMD_OR_CONTROL, 'C', || {
|
||||||
if let Some(text) = self.get_selection_text() {
|
if let Some(text) = self.get_selection_text() {
|
||||||
self.clipboard_provider.set_clipboard_contents(text);
|
self.clipboard_provider.set_clipboard_contents(text);
|
||||||
}
|
}
|
||||||
KeyReaction::DispatchInput
|
KeyReaction::DispatchInput
|
||||||
},
|
})
|
||||||
(_, Key::V) if is_control_key(mods) => {
|
.shortcut(CMD_OR_CONTROL, 'V', || {
|
||||||
let contents = self.clipboard_provider.clipboard_contents();
|
let contents = self.clipboard_provider.clipboard_contents();
|
||||||
self.insert_string(contents);
|
self.insert_string(contents);
|
||||||
KeyReaction::DispatchInput
|
KeyReaction::DispatchInput
|
||||||
},
|
})
|
||||||
(Some(c), _) => {
|
.shortcut(Modifiers::empty(), Key::Delete, || {
|
||||||
self.insert_char(c);
|
|
||||||
KeyReaction::DispatchInput
|
|
||||||
},
|
|
||||||
(None, Key::Delete) => {
|
|
||||||
self.delete_char(Direction::Forward);
|
self.delete_char(Direction::Forward);
|
||||||
KeyReaction::DispatchInput
|
KeyReaction::DispatchInput
|
||||||
},
|
})
|
||||||
(None, Key::Backspace) => {
|
.shortcut(Modifiers::empty(), Key::Backspace, || {
|
||||||
self.delete_char(Direction::Backward);
|
self.delete_char(Direction::Backward);
|
||||||
KeyReaction::DispatchInput
|
KeyReaction::DispatchInput
|
||||||
},
|
})
|
||||||
#[cfg(target_os = "macos")]
|
.optional_shortcut(macos, Modifiers::META, Key::ArrowLeft, || {
|
||||||
(None, Key::Left) if mods.contains(KeyModifiers::SUPER) =>
|
|
||||||
{
|
|
||||||
self.adjust_horizontal_to_line_end(Direction::Backward, maybe_select);
|
self.adjust_horizontal_to_line_end(Direction::Backward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
}
|
})
|
||||||
#[cfg(target_os = "macos")]
|
.optional_shortcut(macos, Modifiers::META, Key::ArrowRight, || {
|
||||||
(None, Key::Right) if mods.contains(KeyModifiers::SUPER) =>
|
|
||||||
{
|
|
||||||
self.adjust_horizontal_to_line_end(Direction::Forward, maybe_select);
|
self.adjust_horizontal_to_line_end(Direction::Forward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
}
|
})
|
||||||
#[cfg(target_os = "macos")]
|
.optional_shortcut(macos, Modifiers::META, Key::ArrowUp, || {
|
||||||
(None, Key::Up) if mods.contains(KeyModifiers::SUPER) =>
|
|
||||||
{
|
|
||||||
self.adjust_horizontal_to_limit(Direction::Backward, maybe_select);
|
self.adjust_horizontal_to_limit(Direction::Backward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
}
|
})
|
||||||
#[cfg(target_os = "macos")]
|
.optional_shortcut(macos, Modifiers::META, Key::ArrowDown, || {
|
||||||
(None, Key::Down) if mods.contains(KeyModifiers::SUPER) =>
|
|
||||||
{
|
|
||||||
self.adjust_horizontal_to_limit(Direction::Forward, maybe_select);
|
self.adjust_horizontal_to_limit(Direction::Forward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
}
|
})
|
||||||
(None, Key::Left) if mods.contains(KeyModifiers::ALT) => {
|
.shortcut(Modifiers::ALT, Key::ArrowLeft, || {
|
||||||
self.adjust_horizontal_by_word(Direction::Backward, maybe_select);
|
self.adjust_horizontal_by_word(Direction::Backward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
},
|
})
|
||||||
(None, Key::Right) if mods.contains(KeyModifiers::ALT) => {
|
.shortcut(Modifiers::ALT, Key::ArrowRight, || {
|
||||||
self.adjust_horizontal_by_word(Direction::Forward, maybe_select);
|
self.adjust_horizontal_by_word(Direction::Forward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
},
|
})
|
||||||
(None, Key::Left) => {
|
.shortcut(Modifiers::empty(), Key::ArrowLeft, || {
|
||||||
self.adjust_horizontal_by_one(Direction::Backward, maybe_select);
|
self.adjust_horizontal_by_one(Direction::Backward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
},
|
})
|
||||||
(None, Key::Right) => {
|
.shortcut(Modifiers::empty(), Key::ArrowRight, || {
|
||||||
self.adjust_horizontal_by_one(Direction::Forward, maybe_select);
|
self.adjust_horizontal_by_one(Direction::Forward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
},
|
})
|
||||||
(None, Key::Up) => {
|
.shortcut(Modifiers::empty(), Key::ArrowUp, || {
|
||||||
self.adjust_vertical(-1, maybe_select);
|
self.adjust_vertical(-1, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
},
|
})
|
||||||
(None, Key::Down) => {
|
.shortcut(Modifiers::empty(), Key::ArrowDown, || {
|
||||||
self.adjust_vertical(1, maybe_select);
|
self.adjust_vertical(1, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
},
|
})
|
||||||
(None, Key::Enter) | (None, Key::KpEnter) => self.handle_return(),
|
.shortcut(Modifiers::empty(), Key::Enter, || self.handle_return())
|
||||||
(None, Key::Home) => {
|
.optional_shortcut(macos, Modifiers::empty(), Key::Home, || {
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
{
|
|
||||||
self.edit_point.index = 0;
|
self.edit_point.index = 0;
|
||||||
}
|
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
},
|
})
|
||||||
(None, Key::End) => {
|
.optional_shortcut(macos, Modifiers::empty(), Key::End, || {
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
{
|
|
||||||
self.edit_point.index = self.current_line_length();
|
self.edit_point.index = self.current_line_length();
|
||||||
self.assert_ok_selection();
|
self.assert_ok_selection();
|
||||||
}
|
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
},
|
})
|
||||||
(None, Key::PageUp) => {
|
.shortcut(Modifiers::empty(), Key::PageUp, || {
|
||||||
self.adjust_vertical(-28, maybe_select);
|
self.adjust_vertical(-28, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
},
|
})
|
||||||
(None, Key::PageDown) => {
|
.shortcut(Modifiers::empty(), Key::PageDown, || {
|
||||||
self.adjust_vertical(28, maybe_select);
|
self.adjust_vertical(28, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
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.
|
/// Whether the content is empty.
|
||||||
|
|
|
@ -20,6 +20,7 @@ gfx_traits = {path = "../gfx_traits"}
|
||||||
hyper = "0.10"
|
hyper = "0.10"
|
||||||
hyper_serde = "0.8"
|
hyper_serde = "0.8"
|
||||||
ipc-channel = "0.11"
|
ipc-channel = "0.11"
|
||||||
|
keyboard-types = {version = "0.4.2-servo", features = ["serde"]}
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
malloc_size_of = { path = "../malloc_size_of" }
|
malloc_size_of = { path = "../malloc_size_of" }
|
||||||
malloc_size_of_derive = { path = "../malloc_size_of_derive" }
|
malloc_size_of_derive = { path = "../malloc_size_of_derive" }
|
||||||
|
|
|
@ -19,6 +19,7 @@ extern crate gfx_traits;
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
extern crate hyper_serde;
|
extern crate hyper_serde;
|
||||||
extern crate ipc_channel;
|
extern crate ipc_channel;
|
||||||
|
extern crate keyboard_types;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate malloc_size_of;
|
extern crate malloc_size_of;
|
||||||
|
@ -50,8 +51,9 @@ use hyper::header::Headers;
|
||||||
use hyper::method::Method;
|
use hyper::method::Method;
|
||||||
use ipc_channel::{Error as IpcError};
|
use ipc_channel::{Error as IpcError};
|
||||||
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||||
|
use keyboard_types::KeyboardEvent;
|
||||||
use libc::c_void;
|
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 msg::constellation_msg::{PipelineNamespaceId, TraversalDirection, TopLevelBrowsingContextId};
|
||||||
use net_traits::{FetchResponseMsg, ReferrerPolicy, ResourceThreads};
|
use net_traits::{FetchResponseMsg, ReferrerPolicy, ResourceThreads};
|
||||||
use net_traits::image::base::Image;
|
use net_traits::image::base::Image;
|
||||||
|
@ -477,7 +479,7 @@ pub enum CompositorEvent {
|
||||||
Option<UntrustedNodeAddress>,
|
Option<UntrustedNodeAddress>,
|
||||||
),
|
),
|
||||||
/// A key was pressed.
|
/// A key was pressed.
|
||||||
KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
|
KeyboardEvent(KeyboardEvent),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Requests a TimerEvent-Message be sent after the given duration.
|
/// Requests a TimerEvent-Message be sent after the given duration.
|
||||||
|
@ -708,7 +710,7 @@ pub enum WebDriverCommandMsg {
|
||||||
/// of a browsing context.
|
/// of a browsing context.
|
||||||
ScriptCommand(BrowsingContextId, WebDriverScriptCommand),
|
ScriptCommand(BrowsingContextId, WebDriverScriptCommand),
|
||||||
/// Act as if keys were pressed in the browsing context with the given ID.
|
/// 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.
|
/// Set the window size.
|
||||||
SetWindowSize(
|
SetWindowSize(
|
||||||
TopLevelBrowsingContextId,
|
TopLevelBrowsingContextId,
|
||||||
|
@ -736,7 +738,7 @@ pub enum ConstellationMsg {
|
||||||
/// Query the constellation to see if the current compositor output is stable
|
/// Query the constellation to see if the current compositor output is stable
|
||||||
IsReadyToSaveImage(HashMap<PipelineId, Epoch>),
|
IsReadyToSaveImage(HashMap<PipelineId, Epoch>),
|
||||||
/// Inform the constellation of a key event.
|
/// Inform the constellation of a key event.
|
||||||
KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
|
Keyboard(KeyboardEvent),
|
||||||
/// Request to load a page.
|
/// Request to load a page.
|
||||||
LoadUrl(TopLevelBrowsingContextId, ServoUrl),
|
LoadUrl(TopLevelBrowsingContextId, ServoUrl),
|
||||||
/// Request to traverse the joint session history of the provided browsing context.
|
/// Request to traverse the joint session history of the provided browsing context.
|
||||||
|
@ -780,7 +782,7 @@ impl fmt::Debug for ConstellationMsg {
|
||||||
GetPipeline(..) => "GetPipeline",
|
GetPipeline(..) => "GetPipeline",
|
||||||
GetFocusTopLevelBrowsingContext(..) => "GetFocusTopLevelBrowsingContext",
|
GetFocusTopLevelBrowsingContext(..) => "GetFocusTopLevelBrowsingContext",
|
||||||
IsReadyToSaveImage(..) => "IsReadyToSaveImage",
|
IsReadyToSaveImage(..) => "IsReadyToSaveImage",
|
||||||
KeyEvent(..) => "KeyEvent",
|
Keyboard(..) => "Keyboard",
|
||||||
LoadUrl(..) => "LoadUrl",
|
LoadUrl(..) => "LoadUrl",
|
||||||
TraverseHistory(..) => "TraverseHistory",
|
TraverseHistory(..) => "TraverseHistory",
|
||||||
WindowSize(..) => "WindowSize",
|
WindowSize(..) => "WindowSize",
|
||||||
|
|
|
@ -109,7 +109,7 @@ use webvr::{WebVRThread, WebVRCompositorHandler};
|
||||||
pub use gleam::gl;
|
pub use gleam::gl;
|
||||||
pub use servo_config as config;
|
pub use servo_config as config;
|
||||||
pub use servo_url as url;
|
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.
|
/// The in-process interface to Servo.
|
||||||
///
|
///
|
||||||
|
@ -320,10 +320,10 @@ where
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
WindowEvent::KeyEvent(ch, key, state, modifiers) => {
|
WindowEvent::Keyboard(key_event) => {
|
||||||
let msg = ConstellationMsg::KeyEvent(ch, key, state, modifiers);
|
let msg = ConstellationMsg::Keyboard(key_event);
|
||||||
if let Err(e) = self.constellation_chan.send(msg) {
|
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) => {},
|
(_, ShutdownState::ShuttingDown) => {},
|
||||||
|
|
||||||
(
|
(
|
||||||
EmbedderMsg::KeyEvent(ch, key, state, modified),
|
EmbedderMsg::Keyboard(key_event),
|
||||||
ShutdownState::NotShuttingDown,
|
ShutdownState::NotShuttingDown,
|
||||||
) => {
|
) => {
|
||||||
let event = (
|
let event = (
|
||||||
top_level_browsing_context,
|
top_level_browsing_context,
|
||||||
EmbedderMsg::KeyEvent(ch, key, state, modified),
|
EmbedderMsg::Keyboard(key_event),
|
||||||
);
|
);
|
||||||
self.embedder_events.push(event);
|
self.embedder_events.push(event);
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,6 +16,7 @@ euclid = "0.19"
|
||||||
hyper = "0.10"
|
hyper = "0.10"
|
||||||
image = "0.19"
|
image = "0.19"
|
||||||
ipc-channel = "0.11"
|
ipc-channel = "0.11"
|
||||||
|
keyboard-types = {version = "0.4.2-servo", features = ["serde"]}
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
msg = {path = "../msg"}
|
msg = {path = "../msg"}
|
||||||
net_traits = {path = "../net_traits"}
|
net_traits = {path = "../net_traits"}
|
||||||
|
|
|
@ -2,184 +2,105 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* 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
|
// spec: https://w3c.github.io/webdriver/#keyboard-actions
|
||||||
/// corresponding keycode and whether shift is required. This is
|
// normalised (sic) as in british spelling
|
||||||
/// currently pretty much ascii-only and the webdriver spec isn't
|
fn get_normalised_key_value(key: char) -> Key {
|
||||||
/// entirely clear on how to deal with characters outside this
|
match key {
|
||||||
/// range. Returns None if no key corresponding to the character is
|
'\u{E000}' => Key::Unidentified,
|
||||||
/// matched.
|
'\u{E001}' => Key::Cancel,
|
||||||
fn key_from_char(key_string: &char) -> Option<(Key, bool)> {
|
'\u{E002}' => Key::Help,
|
||||||
match *key_string {
|
'\u{E003}' => Key::Backspace,
|
||||||
' ' => Some((Key::Space, false)),
|
'\u{E004}' => Key::Tab,
|
||||||
'\'' => Some((Key::Apostrophe, true)),
|
'\u{E005}' => Key::Clear,
|
||||||
'\"' => Some((Key::Apostrophe, false)),
|
// FIXME(pyfisch): spec says "Return"
|
||||||
'<' => Some((Key::Comma, true)),
|
'\u{E006}' => Key::Enter,
|
||||||
',' => Some((Key::Comma, false)),
|
'\u{E007}' => Key::Enter,
|
||||||
'_' => Some((Key::Minus, true)),
|
'\u{E008}' => Key::Shift,
|
||||||
'-' => Some((Key::Minus, false)),
|
'\u{E009}' => Key::Control,
|
||||||
'>' => Some((Key::Period, true)),
|
'\u{E00A}' => Key::Alt,
|
||||||
'.' => Some((Key::Period, false)),
|
'\u{E00B}' => Key::Pause,
|
||||||
'?' => Some((Key::Slash, true)),
|
'\u{E00C}' => Key::Escape,
|
||||||
'/' => Some((Key::Slash, false)),
|
'\u{E00D}' => Key::Character(" ".to_string()),
|
||||||
'~' => Some((Key::GraveAccent, true)),
|
'\u{E00E}' => Key::PageUp,
|
||||||
'`' => Some((Key::GraveAccent, false)),
|
'\u{E00F}' => Key::PageDown,
|
||||||
')' => Some((Key::Num0, true)),
|
'\u{E010}' => Key::End,
|
||||||
'0' => Some((Key::Num0, false)),
|
'\u{E011}' => Key::Home,
|
||||||
'!' => Some((Key::Num1, true)),
|
'\u{E012}' => Key::ArrowLeft,
|
||||||
'1' => Some((Key::Num1, false)),
|
'\u{E013}' => Key::ArrowUp,
|
||||||
'@' => Some((Key::Num2, true)),
|
'\u{E014}' => Key::ArrowRight,
|
||||||
'2' => Some((Key::Num2, false)),
|
'\u{E015}' => Key::ArrowDown,
|
||||||
'#' => Some((Key::Num3, true)),
|
'\u{E016}' => Key::Insert,
|
||||||
'3' => Some((Key::Num3, false)),
|
'\u{E017}' => Key::Delete,
|
||||||
'$' => Some((Key::Num4, true)),
|
'\u{E018}' => Key::Character(";".to_string()),
|
||||||
'4' => Some((Key::Num4, false)),
|
'\u{E019}' => Key::Character("=".to_string()),
|
||||||
'%' => Some((Key::Num5, true)),
|
'\u{E01A}' => Key::Character("0".to_string()),
|
||||||
'5' => Some((Key::Num5, false)),
|
'\u{E01B}' => Key::Character("1".to_string()),
|
||||||
'^' => Some((Key::Num6, true)),
|
'\u{E01C}' => Key::Character("2".to_string()),
|
||||||
'6' => Some((Key::Num6, false)),
|
'\u{E01D}' => Key::Character("3".to_string()),
|
||||||
'&' => Some((Key::Num7, true)),
|
'\u{E01E}' => Key::Character("4".to_string()),
|
||||||
'7' => Some((Key::Num7, false)),
|
'\u{E01F}' => Key::Character("5".to_string()),
|
||||||
'*' => Some((Key::Num8, true)),
|
'\u{E020}' => Key::Character("6".to_string()),
|
||||||
'8' => Some((Key::Num8, false)),
|
'\u{E021}' => Key::Character("7".to_string()),
|
||||||
'(' => Some((Key::Num9, true)),
|
'\u{E022}' => Key::Character("8".to_string()),
|
||||||
'9' => Some((Key::Num9, false)),
|
'\u{E023}' => Key::Character("9".to_string()),
|
||||||
':' => Some((Key::Semicolon, true)),
|
'\u{E024}' => Key::Character("*".to_string()),
|
||||||
';' => Some((Key::Semicolon, false)),
|
'\u{E025}' => Key::Character("+".to_string()),
|
||||||
'+' => Some((Key::Equal, true)),
|
'\u{E026}' => Key::Character(",".to_string()),
|
||||||
'=' => Some((Key::Equal, false)),
|
'\u{E027}' => Key::Character("-".to_string()),
|
||||||
'A' => Some((Key::A, true)),
|
'\u{E028}' => Key::Character(".".to_string()),
|
||||||
'a' => Some((Key::A, false)),
|
'\u{E029}' => Key::Character("/".to_string()),
|
||||||
'B' => Some((Key::B, true)),
|
'\u{E031}' => Key::F1,
|
||||||
'b' => Some((Key::B, false)),
|
'\u{E032}' => Key::F2,
|
||||||
'C' => Some((Key::C, true)),
|
'\u{E033}' => Key::F3,
|
||||||
'c' => Some((Key::C, false)),
|
'\u{E034}' => Key::F4,
|
||||||
'D' => Some((Key::D, true)),
|
'\u{E035}' => Key::F5,
|
||||||
'd' => Some((Key::D, false)),
|
'\u{E036}' => Key::F6,
|
||||||
'E' => Some((Key::E, true)),
|
'\u{E037}' => Key::F7,
|
||||||
'e' => Some((Key::E, false)),
|
'\u{E038}' => Key::F8,
|
||||||
'F' => Some((Key::F, true)),
|
'\u{E039}' => Key::F9,
|
||||||
'f' => Some((Key::F, false)),
|
'\u{E03A}' => Key::F10,
|
||||||
'G' => Some((Key::G, true)),
|
'\u{E03B}' => Key::F11,
|
||||||
'g' => Some((Key::G, false)),
|
'\u{E03C}' => Key::F12,
|
||||||
'H' => Some((Key::H, true)),
|
'\u{E03D}' => Key::Meta,
|
||||||
'h' => Some((Key::H, false)),
|
'\u{E040}' => Key::ZenkakuHankaku,
|
||||||
'I' => Some((Key::I, true)),
|
'\u{E050}' => Key::Shift,
|
||||||
'i' => Some((Key::I, false)),
|
'\u{E051}' => Key::Control,
|
||||||
'J' => Some((Key::J, true)),
|
'\u{E052}' => Key::Alt,
|
||||||
'j' => Some((Key::J, false)),
|
'\u{E053}' => Key::Meta,
|
||||||
'K' => Some((Key::K, true)),
|
'\u{E054}' => Key::PageUp,
|
||||||
'k' => Some((Key::K, false)),
|
'\u{E055}' => Key::PageDown,
|
||||||
'L' => Some((Key::L, true)),
|
'\u{E056}' => Key::End,
|
||||||
'l' => Some((Key::L, false)),
|
'\u{E057}' => Key::Home,
|
||||||
'M' => Some((Key::M, true)),
|
'\u{E058}' => Key::ArrowLeft,
|
||||||
'm' => Some((Key::M, false)),
|
'\u{E059}' => Key::ArrowUp,
|
||||||
'N' => Some((Key::N, true)),
|
'\u{E05A}' => Key::ArrowRight,
|
||||||
'n' => Some((Key::N, false)),
|
'\u{E05B}' => Key::ArrowDown,
|
||||||
'O' => Some((Key::O, true)),
|
'\u{E05C}' => Key::Insert,
|
||||||
'o' => Some((Key::O, false)),
|
'\u{E05D}' => Key::Delete,
|
||||||
'P' => Some((Key::P, true)),
|
_ => Key::Character(key.to_string()),
|
||||||
'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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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![];
|
let mut rv = vec![];
|
||||||
|
|
||||||
for char_code in key_codes.chars() {
|
for char_code in key_codes.chars() {
|
||||||
let (key, with_shift) =
|
// TODO(pyfisch): compute code, location, modifiers according to spec
|
||||||
key_from_char(&char_code).ok_or(format!("Unsupported character code {}", char_code))?;
|
let key = get_normalised_key_value(char_code);
|
||||||
let modifiers = if with_shift {
|
let mut event = KeyboardEvent {
|
||||||
KeyModifiers::SHIFT
|
state: ::keyboard_types::KeyState::Down,
|
||||||
} else {
|
key,
|
||||||
KeyModifiers::empty()
|
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(event.clone());
|
||||||
rv.push((key, modifiers, KeyState::Released));
|
event.state = ::keyboard_types::KeyState::Up;
|
||||||
|
rv.push(event);
|
||||||
}
|
}
|
||||||
Ok(rv)
|
rv
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ extern crate euclid;
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
extern crate image;
|
extern crate image;
|
||||||
extern crate ipc_channel;
|
extern crate ipc_channel;
|
||||||
|
extern crate keyboard_types;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate msg;
|
extern crate msg;
|
||||||
|
@ -995,12 +996,7 @@ impl Handler {
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let keys = keycodes_to_keys(&keys.text).or_else(|_| {
|
let keys = keycodes_to_keys(&keys.text);
|
||||||
Err(WebDriverError::new(
|
|
||||||
ErrorStatus::UnsupportedOperation,
|
|
||||||
"Failed to convert keycodes",
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// TODO: there's a race condition caused by the focus command and the
|
// TODO: there's a race condition caused by the focus command and the
|
||||||
// send keys command being two separate messages,
|
// send keys command being two separate messages,
|
||||||
|
|
|
@ -408,7 +408,7 @@ impl ServoGlue {
|
||||||
EmbedderMsg::SelectFiles(..) |
|
EmbedderMsg::SelectFiles(..) |
|
||||||
EmbedderMsg::MoveTo(..) |
|
EmbedderMsg::MoveTo(..) |
|
||||||
EmbedderMsg::ResizeTo(..) |
|
EmbedderMsg::ResizeTo(..) |
|
||||||
EmbedderMsg::KeyEvent(..) |
|
EmbedderMsg::Keyboard(..) |
|
||||||
EmbedderMsg::SetCursor(..) |
|
EmbedderMsg::SetCursor(..) |
|
||||||
EmbedderMsg::NewFavicon(..) |
|
EmbedderMsg::NewFavicon(..) |
|
||||||
EmbedderMsg::HeadParsed |
|
EmbedderMsg::HeadParsed |
|
||||||
|
|
|
@ -40,6 +40,7 @@ crossbeam-channel = "0.2"
|
||||||
euclid = "0.19"
|
euclid = "0.19"
|
||||||
gleam = "0.6"
|
gleam = "0.6"
|
||||||
glutin = "0.18"
|
glutin = "0.18"
|
||||||
|
keyboard-types = {version = "0.4.2-servo", features = ["serde"]}
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
libservo = {path = "../../components/servo"}
|
libservo = {path = "../../components/servo"}
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
use euclid::{TypedPoint2D, TypedVector2D};
|
use euclid::{TypedPoint2D, TypedVector2D};
|
||||||
use glutin_app::keyutils::{CMD_OR_CONTROL, CMD_OR_ALT};
|
use glutin_app::keyutils::{CMD_OR_CONTROL, CMD_OR_ALT};
|
||||||
use glutin_app::window::{Window, LINE_HEIGHT};
|
use glutin_app::window::{Window, LINE_HEIGHT};
|
||||||
|
use keyboard_types::{Key, KeyboardEvent, Modifiers, ShortcutMatcher};
|
||||||
use servo::compositing::windowing::{WebRenderDebugOption, WindowEvent};
|
use servo::compositing::windowing::{WebRenderDebugOption, WindowEvent};
|
||||||
use servo::embedder_traits::{EmbedderMsg, FilterPattern};
|
use servo::embedder_traits::{EmbedderMsg, FilterPattern};
|
||||||
use servo::msg::constellation_msg::{Key, TopLevelBrowsingContextId as BrowserId};
|
use servo::msg::constellation_msg::{TopLevelBrowsingContextId as BrowserId};
|
||||||
use servo::msg::constellation_msg::{KeyModifiers, KeyState, TraversalDirection};
|
use servo::msg::constellation_msg::TraversalDirection;
|
||||||
use servo::net_traits::pub_domains::is_reg_domain;
|
use servo::net_traits::pub_domains::is_reg_domain;
|
||||||
use servo::script_traits::TouchEventType;
|
use servo::script_traits::TouchEventType;
|
||||||
use servo::servo_config::opts;
|
use servo::servo_config::opts;
|
||||||
|
@ -70,8 +71,8 @@ impl Browser {
|
||||||
pub fn handle_window_events(&mut self, events: Vec<WindowEvent>) {
|
pub fn handle_window_events(&mut self, events: Vec<WindowEvent>) {
|
||||||
for event in events {
|
for event in events {
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::KeyEvent(ch, key, state, mods) => {
|
WindowEvent::Keyboard(key_event) => {
|
||||||
self.handle_key_from_window(ch, key, state, mods);
|
self.handle_key_from_window(key_event);
|
||||||
},
|
},
|
||||||
event => {
|
event => {
|
||||||
self.event_queue.push(event);
|
self.event_queue.push(event);
|
||||||
|
@ -85,22 +86,14 @@ impl Browser {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle key events before sending them to Servo.
|
/// Handle key events before sending them to Servo.
|
||||||
fn handle_key_from_window(
|
fn handle_key_from_window(&mut self, key_event: KeyboardEvent) {
|
||||||
&mut self,
|
ShortcutMatcher::from_event(key_event.clone())
|
||||||
ch: Option<char>,
|
.shortcut(CMD_OR_CONTROL, 'R', || {
|
||||||
key: Key,
|
if let Some(id) = self.browser_id {
|
||||||
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));
|
self.event_queue.push(WindowEvent::Reload(id));
|
||||||
},
|
}
|
||||||
(CMD_OR_CONTROL, _, Key::L, Some(id)) => if pressed {
|
})
|
||||||
|
.shortcut(CMD_OR_CONTROL, 'L', || {
|
||||||
let url: String = if let Some(ref current_url) = self.current_url {
|
let url: String = if let Some(ref current_url) = self.current_url {
|
||||||
current_url.to_string()
|
current_url.to_string()
|
||||||
} else {
|
} else {
|
||||||
|
@ -110,163 +103,130 @@ impl Browser {
|
||||||
let input = tinyfiledialogs::input_box(title, title, &url);
|
let input = tinyfiledialogs::input_box(title, title, &url);
|
||||||
if let Some(input) = input {
|
if let Some(input) = input {
|
||||||
if let Some(url) = sanitize_url(&input) {
|
if let Some(url) = sanitize_url(&input) {
|
||||||
|
if let Some(id) = self.browser_id {
|
||||||
self.event_queue.push(WindowEvent::LoadUrl(id, url));
|
self.event_queue.push(WindowEvent::LoadUrl(id, url));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
(CMD_OR_CONTROL, _, Key::Q, _) => if pressed {
|
|
||||||
self.event_queue.push(WindowEvent::Quit);
|
|
||||||
},
|
|
||||||
(_, Some('3'), _, _) if mods ^ KeyModifiers::CONTROL == KeyModifiers::SHIFT => {
|
|
||||||
if pressed {
|
|
||||||
self.event_queue.push(WindowEvent::CaptureWebRender);
|
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
(KeyModifiers::CONTROL, None, Key::F10, _) => if pressed {
|
.shortcut(CMD_OR_CONTROL, 'Q', || {
|
||||||
let event =
|
self.event_queue.push(WindowEvent::Quit);
|
||||||
WindowEvent::ToggleWebRenderDebug(WebRenderDebugOption::RenderTargetDebug);
|
})
|
||||||
self.event_queue.push(event);
|
.shortcut(Modifiers::CONTROL, Key::F9, || {
|
||||||
},
|
self.event_queue.push(WindowEvent::CaptureWebRender)
|
||||||
(KeyModifiers::CONTROL, None, Key::F11, _) => if pressed {
|
})
|
||||||
let event =
|
.shortcut(Modifiers::CONTROL, Key::F10, || {
|
||||||
WindowEvent::ToggleWebRenderDebug(WebRenderDebugOption::TextureCacheDebug);
|
self.event_queue.push(WindowEvent::ToggleWebRenderDebug(
|
||||||
self.event_queue.push(event);
|
WebRenderDebugOption::RenderTargetDebug,
|
||||||
},
|
));
|
||||||
(KeyModifiers::CONTROL, None, Key::F12, _) => if pressed {
|
})
|
||||||
let event = WindowEvent::ToggleWebRenderDebug(WebRenderDebugOption::Profiler);
|
.shortcut(Modifiers::CONTROL, Key::F11, || {
|
||||||
self.event_queue.push(event);
|
self.event_queue.push(WindowEvent::ToggleWebRenderDebug(
|
||||||
},
|
WebRenderDebugOption::TextureCacheDebug,
|
||||||
(CMD_OR_ALT, None, Key::Right, Some(id)) |
|
));
|
||||||
(KeyModifiers::NONE, None, Key::NavigateForward, Some(id)) => if pressed {
|
})
|
||||||
|
.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));
|
let event = WindowEvent::Navigation(id, TraversalDirection::Forward(1));
|
||||||
self.event_queue.push(event);
|
self.event_queue.push(event);
|
||||||
},
|
}
|
||||||
(CMD_OR_ALT, None, Key::Left, Some(id)) |
|
})
|
||||||
(KeyModifiers::NONE, None, Key::NavigateBackward, Some(id)) => if pressed {
|
.shortcut(CMD_OR_ALT, Key::ArrowLeft, || {
|
||||||
|
if let Some(id) = self.browser_id {
|
||||||
let event = WindowEvent::Navigation(id, TraversalDirection::Back(1));
|
let event = WindowEvent::Navigation(id, TraversalDirection::Back(1));
|
||||||
self.event_queue.push(event);
|
self.event_queue.push(event);
|
||||||
},
|
|
||||||
(KeyModifiers::NONE, None, Key::Escape, _) => if pressed {
|
|
||||||
self.event_queue.push(WindowEvent::Quit);
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self.platform_handle_key(ch, key, mods, state);
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.shortcut(Modifiers::empty(), Key::Escape, || {
|
||||||
|
self.event_queue.push(WindowEvent::Quit);
|
||||||
|
})
|
||||||
|
.otherwise(|| self.platform_handle_key(key_event));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "win"))]
|
#[cfg(not(target_os = "win"))]
|
||||||
fn platform_handle_key(
|
fn platform_handle_key(&mut self, key_event: KeyboardEvent) {
|
||||||
&mut self,
|
if let Some(id) = self.browser_id {
|
||||||
ch: Option<char>,
|
if let Some(event) = ShortcutMatcher::from_event(key_event.clone())
|
||||||
key: Key,
|
.shortcut(CMD_OR_CONTROL, '[', || {
|
||||||
mods: KeyModifiers,
|
WindowEvent::Navigation(id, TraversalDirection::Back(1))
|
||||||
state: KeyState,
|
})
|
||||||
) {
|
.shortcut(CMD_OR_CONTROL, ']', || {
|
||||||
let pressed = state == KeyState::Pressed;
|
WindowEvent::Navigation(id, TraversalDirection::Forward(1))
|
||||||
match (mods, key, self.browser_id) {
|
})
|
||||||
(CMD_OR_CONTROL, Key::LeftBracket, Some(id)) => if pressed {
|
.otherwise(|| WindowEvent::Keyboard(key_event))
|
||||||
let event = WindowEvent::Navigation(id, TraversalDirection::Back(1));
|
{
|
||||||
self.event_queue.push(event);
|
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));
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "win")]
|
#[cfg(target_os = "win")]
|
||||||
fn platform_handle_key(
|
fn platform_handle_key(&mut self, _key_event: KeyboardEvent) {}
|
||||||
&mut self,
|
|
||||||
_ch: Option<char>,
|
|
||||||
_key: Key,
|
|
||||||
_mods: KeyModifiers,
|
|
||||||
_state: KeyState,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Handle key events after they have been handled by Servo.
|
/// Handle key events after they have been handled by Servo.
|
||||||
fn handle_key_from_servo(
|
fn handle_key_from_servo(&mut self, _: Option<BrowserId>, event: KeyboardEvent) {
|
||||||
&mut self,
|
ShortcutMatcher::from_event(event)
|
||||||
_: Option<BrowserId>,
|
.shortcut(CMD_OR_CONTROL, '=', || {
|
||||||
ch: Option<char>,
|
self.event_queue.push(WindowEvent::Zoom(1.1))
|
||||||
key: Key,
|
})
|
||||||
state: KeyState,
|
.shortcut(CMD_OR_CONTROL, '+', || {
|
||||||
mods: KeyModifiers,
|
self.event_queue.push(WindowEvent::Zoom(1.1))
|
||||||
) {
|
})
|
||||||
if state == KeyState::Released {
|
.shortcut(CMD_OR_CONTROL, '-', || {
|
||||||
return;
|
self.event_queue.push(WindowEvent::Zoom(1.0 / 1.1))
|
||||||
}
|
})
|
||||||
|
.shortcut(CMD_OR_CONTROL, '0', || {
|
||||||
match (mods, ch, key) {
|
self.event_queue.push(WindowEvent::ResetZoom)
|
||||||
(CMD_OR_CONTROL, Some('='), _) | (CMD_OR_CONTROL, Some('+'), _) => {
|
})
|
||||||
self.event_queue.push(WindowEvent::Zoom(1.1));
|
.shortcut(Modifiers::empty(), Key::PageDown, || {
|
||||||
},
|
|
||||||
(_, 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) => {
|
|
||||||
let scroll_location = ScrollLocation::Delta(TypedVector2D::new(
|
let scroll_location = ScrollLocation::Delta(TypedVector2D::new(
|
||||||
0.0,
|
0.0,
|
||||||
-self.window.page_height() + 2.0 * LINE_HEIGHT,
|
-self.window.page_height() + 2.0 * LINE_HEIGHT,
|
||||||
));
|
));
|
||||||
self.scroll_window_from_key(scroll_location, TouchEventType::Move);
|
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(
|
let scroll_location = ScrollLocation::Delta(TypedVector2D::new(
|
||||||
0.0,
|
0.0,
|
||||||
self.window.page_height() - 2.0 * LINE_HEIGHT,
|
self.window.page_height() - 2.0 * LINE_HEIGHT,
|
||||||
));
|
));
|
||||||
self.scroll_window_from_key(scroll_location, TouchEventType::Move);
|
self.scroll_window_from_key(scroll_location, TouchEventType::Move);
|
||||||
},
|
})
|
||||||
|
.shortcut(Modifiers::empty(), Key::Home, || {
|
||||||
(KeyModifiers::NONE, None, Key::Home) => {
|
|
||||||
self.scroll_window_from_key(ScrollLocation::Start, TouchEventType::Move);
|
self.scroll_window_from_key(ScrollLocation::Start, TouchEventType::Move);
|
||||||
},
|
})
|
||||||
|
.shortcut(Modifiers::empty(), Key::End, || {
|
||||||
(KeyModifiers::NONE, None, Key::End) => {
|
|
||||||
self.scroll_window_from_key(ScrollLocation::End, TouchEventType::Move);
|
self.scroll_window_from_key(ScrollLocation::End, TouchEventType::Move);
|
||||||
},
|
})
|
||||||
|
.shortcut(Modifiers::empty(), Key::ArrowUp, || {
|
||||||
(KeyModifiers::NONE, None, Key::Up) => {
|
|
||||||
self.scroll_window_from_key(
|
self.scroll_window_from_key(
|
||||||
ScrollLocation::Delta(TypedVector2D::new(0.0, 3.0 * LINE_HEIGHT)),
|
ScrollLocation::Delta(TypedVector2D::new(0.0, 3.0 * LINE_HEIGHT)),
|
||||||
TouchEventType::Move,
|
TouchEventType::Move,
|
||||||
);
|
);
|
||||||
},
|
})
|
||||||
(KeyModifiers::NONE, None, Key::Down) => {
|
.shortcut(Modifiers::empty(), Key::ArrowDown, || {
|
||||||
self.scroll_window_from_key(
|
self.scroll_window_from_key(
|
||||||
ScrollLocation::Delta(TypedVector2D::new(0.0, -3.0 * LINE_HEIGHT)),
|
ScrollLocation::Delta(TypedVector2D::new(0.0, -3.0 * LINE_HEIGHT)),
|
||||||
TouchEventType::Move,
|
TouchEventType::Move,
|
||||||
);
|
);
|
||||||
},
|
})
|
||||||
(KeyModifiers::NONE, None, Key::Left) => {
|
.shortcut(Modifiers::empty(), Key::ArrowLeft, || {
|
||||||
self.scroll_window_from_key(
|
self.scroll_window_from_key(
|
||||||
ScrollLocation::Delta(TypedVector2D::new(LINE_HEIGHT, 0.0)),
|
ScrollLocation::Delta(TypedVector2D::new(LINE_HEIGHT, 0.0)),
|
||||||
TouchEventType::Move,
|
TouchEventType::Move,
|
||||||
);
|
);
|
||||||
},
|
})
|
||||||
(KeyModifiers::NONE, None, Key::Right) => {
|
.shortcut(Modifiers::empty(), Key::ArrowRight, || {
|
||||||
self.scroll_window_from_key(
|
self.scroll_window_from_key(
|
||||||
ScrollLocation::Delta(TypedVector2D::new(-LINE_HEIGHT, 0.0)),
|
ScrollLocation::Delta(TypedVector2D::new(-LINE_HEIGHT, 0.0)),
|
||||||
TouchEventType::Move,
|
TouchEventType::Move,
|
||||||
);
|
);
|
||||||
},
|
});
|
||||||
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scroll_window_from_key(&mut self, scroll_location: ScrollLocation, phase: TouchEventType) {
|
fn scroll_window_from_key(&mut self, scroll_location: ScrollLocation, phase: TouchEventType) {
|
||||||
|
@ -311,7 +271,8 @@ impl Browser {
|
||||||
&message,
|
&message,
|
||||||
MessageBoxIcon::Warning,
|
MessageBoxIcon::Warning,
|
||||||
);
|
);
|
||||||
}).unwrap()
|
})
|
||||||
|
.unwrap()
|
||||||
.join()
|
.join()
|
||||||
.expect("Thread spawning failed");
|
.expect("Thread spawning failed");
|
||||||
}
|
}
|
||||||
|
@ -350,8 +311,8 @@ impl Browser {
|
||||||
self.event_queue
|
self.event_queue
|
||||||
.push(WindowEvent::SelectBrowser(new_browser_id));
|
.push(WindowEvent::SelectBrowser(new_browser_id));
|
||||||
},
|
},
|
||||||
EmbedderMsg::KeyEvent(ch, key, state, modified) => {
|
EmbedderMsg::Keyboard(key_event) => {
|
||||||
self.handle_key_from_servo(browser_id, ch, key, state, modified);
|
self.handle_key_from_servo(browser_id, key_event);
|
||||||
},
|
},
|
||||||
EmbedderMsg::SetCursor(cursor) => {
|
EmbedderMsg::SetCursor(cursor) => {
|
||||||
self.window.set_cursor(cursor);
|
self.window.set_cursor(cursor);
|
||||||
|
@ -438,7 +399,8 @@ fn platform_get_selected_devices(devices: Vec<String>) -> Option<String> {
|
||||||
},
|
},
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}).unwrap()
|
})
|
||||||
|
.unwrap()
|
||||||
.join()
|
.join()
|
||||||
.expect("Thread spawning failed")
|
.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);
|
let file = tinyfiledialogs::open_file_dialog(picker_name, "", filter_opt);
|
||||||
file.map(|x| vec![x])
|
file.map(|x| vec![x])
|
||||||
}
|
}
|
||||||
}).unwrap()
|
})
|
||||||
|
.unwrap()
|
||||||
.join()
|
.join()
|
||||||
.expect("Thread spawning failed")
|
.expect("Thread spawning failed")
|
||||||
}
|
}
|
||||||
|
@ -495,7 +458,8 @@ fn sanitize_url(request: &str) -> Option<ServoUrl> {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}).or_else(|| {
|
})
|
||||||
|
.or_else(|| {
|
||||||
PREFS
|
PREFS
|
||||||
.get("shell.searchpage")
|
.get("shell.searchpage")
|
||||||
.as_string()
|
.as_string()
|
||||||
|
|
|
@ -2,215 +2,34 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use servo::msg::constellation_msg::{self, Key, KeyModifiers};
|
use keyboard_types::{Code, Key, KeyboardEvent, KeyState, Modifiers, Location};
|
||||||
use winit::VirtualKeyCode;
|
use winit::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode};
|
||||||
|
|
||||||
// Some shortcuts use Cmd on Mac and Control on other systems.
|
// Some shortcuts use Cmd on Mac and Control on other systems.
|
||||||
#[cfg(target_os = "macos")]
|
#[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"))]
|
#[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.
|
// Some shortcuts use Cmd on Mac and Alt on other systems.
|
||||||
#[cfg(target_os = "macos")]
|
#[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"))]
|
#[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> {
|
fn get_servo_key_from_winit_key(key: Option<VirtualKeyCode>) -> 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, ()> {
|
|
||||||
use winit::VirtualKeyCode::*;
|
use winit::VirtualKeyCode::*;
|
||||||
// TODO(negge): add more key mappings
|
// TODO: figure out how to map NavigateForward, NavigateBackward
|
||||||
Ok(match key {
|
// TODO: map the remaining keys if possible
|
||||||
A => Key::A,
|
let key = if let Some(key) = key {
|
||||||
B => Key::B,
|
key
|
||||||
C => Key::C,
|
} else {
|
||||||
D => Key::D,
|
return Key::Unidentified;
|
||||||
E => Key::E,
|
};
|
||||||
F => Key::F,
|
match key {
|
||||||
G => Key::G,
|
// printable: Key1 to Key0
|
||||||
H => Key::H,
|
// printable: A to Z
|
||||||
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,
|
|
||||||
Escape => Key::Escape,
|
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,
|
F1 => Key::F1,
|
||||||
F2 => Key::F2,
|
F2 => Key::F2,
|
||||||
F3 => Key::F3,
|
F3 => Key::F3,
|
||||||
|
@ -223,23 +42,226 @@ pub fn winit_key_to_script_key(key: VirtualKeyCode) -> Result<constellation_msg:
|
||||||
F10 => Key::F10,
|
F10 => Key::F10,
|
||||||
F11 => Key::F11,
|
F11 => Key::F11,
|
||||||
F12 => Key::F12,
|
F12 => Key::F12,
|
||||||
|
// F13 to F15 are not mapped
|
||||||
NavigateBackward => Key::NavigateBackward,
|
Snapshot => Key::PrintScreen,
|
||||||
NavigateForward => Key::NavigateForward,
|
// Scroll not mapped
|
||||||
_ => return Err(()),
|
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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_printable(key_code: VirtualKeyCode) -> bool {
|
fn get_servo_location_from_winit_key(key: Option<VirtualKeyCode>) -> Location {
|
||||||
use winit::VirtualKeyCode::*;
|
use winit::VirtualKeyCode::*;
|
||||||
match key_code {
|
// TODO: add more numpad keys
|
||||||
Escape | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | F13 | F14 |
|
let key = if let Some(key) = key {
|
||||||
F15 | Snapshot | Scroll | Pause | Insert | Home | Delete | End | PageDown | PageUp |
|
key
|
||||||
Left | Up | Right | Down | Back | LAlt | LControl | LShift | LWin | Mail |
|
} else {
|
||||||
MediaSelect | MediaStop | Mute | MyComputer | NavigateForward | NavigateBackward |
|
return Location::Standard;
|
||||||
NextTrack | NoConvert | PlayPause | Power | PrevTrack | RAlt | RControl | RShift |
|
};
|
||||||
RWin | Sleep | Stop | VolumeDown | VolumeUp | Wake | WebBack | WebFavorites |
|
match key {
|
||||||
WebForward | WebHome | WebRefresh | WebSearch | WebStop => false,
|
LShift | LControl | LAlt | LWin => Location::Left,
|
||||||
_ => true,
|
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 gdi32;
|
||||||
use gleam::gl;
|
use gleam::gl;
|
||||||
use glutin::{Api, ContextBuilder, GlContext, GlRequest, GlWindow};
|
use glutin::{Api, ContextBuilder, GlContext, GlRequest, GlWindow};
|
||||||
|
use keyboard_types::{Key, KeyboardEvent, KeyState};
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
use osmesa_sys;
|
use osmesa_sys;
|
||||||
use servo::compositing::windowing::{AnimationState, MouseWindowEvent, WindowEvent};
|
use servo::compositing::windowing::{AnimationState, MouseWindowEvent, WindowEvent};
|
||||||
use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods};
|
use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods};
|
||||||
use servo::embedder_traits::EventLoopWaker;
|
use servo::embedder_traits::EventLoopWaker;
|
||||||
use servo::msg::constellation_msg::{Key, KeyState, KeyModifiers};
|
|
||||||
use servo::script_traits::TouchEventType;
|
use servo::script_traits::TouchEventType;
|
||||||
use servo::servo_config::opts;
|
use servo::servo_config::opts;
|
||||||
use servo::servo_geometry::DeviceIndependentPixel;
|
use servo::servo_geometry::DeviceIndependentPixel;
|
||||||
|
@ -31,13 +31,13 @@ use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time;
|
use std::time;
|
||||||
use super::keyutils;
|
use super::keyutils::keyboard_event_from_winit;
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
use user32;
|
use user32;
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
use winapi;
|
use winapi;
|
||||||
use winit;
|
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};
|
use winit::dpi::{LogicalPosition, LogicalSize, PhysicalSize};
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use winit::os::macos::{ActivationPolicy, WindowBuilderExt};
|
use winit::os::macos::{ActivationPolicy, WindowBuilderExt};
|
||||||
|
@ -150,8 +150,7 @@ pub struct Window {
|
||||||
mouse_down_point: Cell<TypedPoint2D<i32, DevicePixel>>,
|
mouse_down_point: Cell<TypedPoint2D<i32, DevicePixel>>,
|
||||||
event_queue: RefCell<Vec<WindowEvent>>,
|
event_queue: RefCell<Vec<WindowEvent>>,
|
||||||
mouse_pos: Cell<TypedPoint2D<i32, DevicePixel>>,
|
mouse_pos: Cell<TypedPoint2D<i32, DevicePixel>>,
|
||||||
key_modifiers: Cell<KeyModifiers>,
|
last_pressed: Cell<Option<KeyboardEvent>>,
|
||||||
last_pressed_key: Cell<Option<Key>>,
|
|
||||||
animation_state: Cell<AnimationState>,
|
animation_state: Cell<AnimationState>,
|
||||||
fullscreen: Cell<bool>,
|
fullscreen: Cell<bool>,
|
||||||
gl: Rc<gl::Gl>,
|
gl: Rc<gl::Gl>,
|
||||||
|
@ -276,11 +275,8 @@ impl Window {
|
||||||
event_queue: RefCell::new(vec![]),
|
event_queue: RefCell::new(vec![]),
|
||||||
mouse_down_button: Cell::new(None),
|
mouse_down_button: Cell::new(None),
|
||||||
mouse_down_point: Cell::new(TypedPoint2D::new(0, 0)),
|
mouse_down_point: Cell::new(TypedPoint2D::new(0, 0)),
|
||||||
|
|
||||||
mouse_pos: Cell::new(TypedPoint2D::new(0, 0)),
|
mouse_pos: Cell::new(TypedPoint2D::new(0, 0)),
|
||||||
key_modifiers: Cell::new(KeyModifiers::empty()),
|
last_pressed: Cell::new(None),
|
||||||
|
|
||||||
last_pressed_key: Cell::new(None),
|
|
||||||
gl: gl.clone(),
|
gl: gl.clone(),
|
||||||
animation_state: Cell::new(AnimationState::Idle),
|
animation_state: Cell::new(AnimationState::Idle),
|
||||||
fullscreen: Cell::new(false),
|
fullscreen: Cell::new(false),
|
||||||
|
@ -408,56 +404,46 @@ impl Window {
|
||||||
GlRequest::Specific(Api::OpenGlEs, (3, 0))
|
GlRequest::Specific(Api::OpenGlEs, (3, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_received_character(&self, ch: char) {
|
fn handle_received_character(&self, mut ch: char) {
|
||||||
let last_key = if let Some(key) = self.last_pressed_key.get() {
|
info!("winit received character: {:?}", ch);
|
||||||
key
|
if ch.is_control() {
|
||||||
} else {
|
if ch as u8 >= 32 {
|
||||||
return;
|
return;
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
// shift ASCII control characters to lowercase
|
||||||
fn toggle_keyboard_modifiers(&self, mods: ModifiersState) {
|
ch = (ch as u8 + 96) as char;
|
||||||
self.toggle_modifier(KeyModifiers::CONTROL, mods.ctrl);
|
}
|
||||||
self.toggle_modifier(KeyModifiers::SHIFT, mods.shift);
|
let mut event = if let Some(event) = self.last_pressed.replace(None) {
|
||||||
self.toggle_modifier(KeyModifiers::ALT, mods.alt);
|
event
|
||||||
self.toggle_modifier(KeyModifiers::SUPER, mods.logo);
|
} 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 {
|
||||||
|
// 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()
|
||||||
|
};
|
||||||
|
event.key = Key::Character(ch.to_string());
|
||||||
|
self.event_queue
|
||||||
|
.borrow_mut()
|
||||||
|
.push(WindowEvent::Keyboard(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_keyboard_input(
|
fn handle_keyboard_input(
|
||||||
&self,
|
&self,
|
||||||
element_state: ElementState,
|
input: KeyboardInput,
|
||||||
code: VirtualKeyCode,
|
|
||||||
mods: ModifiersState,
|
|
||||||
) {
|
) {
|
||||||
self.toggle_keyboard_modifiers(mods);
|
let event = keyboard_event_from_winit(input);
|
||||||
|
if event.state == KeyState::Down && event.key == Key::Unidentified {
|
||||||
if let Ok(key) = keyutils::winit_key_to_script_key(code) {
|
// If pressed and probably printable, we expect a ReceivedCharacter event.
|
||||||
let state = match element_state {
|
self.last_pressed.set(Some(event));
|
||||||
ElementState::Pressed => KeyState::Pressed,
|
} else if event.key != Key::Unidentified {
|
||||||
ElementState::Released => KeyState::Released,
|
self.last_pressed.set(None);
|
||||||
};
|
|
||||||
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
|
self.event_queue
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.push(WindowEvent::KeyEvent(None, key, state, modifiers));
|
.push(WindowEvent::Keyboard(event));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,17 +456,11 @@ impl Window {
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event:
|
event:
|
||||||
winit::WindowEvent::KeyboardInput {
|
winit::WindowEvent::KeyboardInput {
|
||||||
input:
|
input,
|
||||||
winit::KeyboardInput {
|
|
||||||
state,
|
|
||||||
virtual_keycode: Some(virtual_keycode),
|
|
||||||
modifiers,
|
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
..
|
..
|
||||||
},
|
} => self.handle_keyboard_input(input),
|
||||||
..
|
|
||||||
} => self.handle_keyboard_input(state, virtual_keycode, modifiers),
|
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: winit::WindowEvent::MouseInput { state, button, .. },
|
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
|
/// Helper function to handle a click
|
||||||
fn handle_mouse(
|
fn handle_mouse(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -8,6 +8,7 @@ extern crate euclid;
|
||||||
extern crate gdi32;
|
extern crate gdi32;
|
||||||
extern crate gleam;
|
extern crate gleam;
|
||||||
extern crate glutin;
|
extern crate glutin;
|
||||||
|
extern crate keyboard_types;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
|
|
|
@ -10,6 +10,6 @@ path = "lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
euclid = "0.19"
|
euclid = "0.19"
|
||||||
msg = {path = "../../../components/msg"}
|
keyboard-types = "0.4.2-servo"
|
||||||
script = {path = "../../../components/script"}
|
script = {path = "../../../components/script"}
|
||||||
servo_url = {path = "../../../components/url"}
|
servo_url = {path = "../../../components/url"}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#[cfg(test)] extern crate euclid;
|
#[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 script;
|
||||||
#[cfg(test)] extern crate servo_url;
|
#[cfg(test)] extern crate servo_url;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use msg::constellation_msg::{Key, KeyModifiers};
|
use keyboard_types::{Key, Modifiers};
|
||||||
use script::clipboard_provider::DummyClipboardContext;
|
use script::clipboard_provider::DummyClipboardContext;
|
||||||
use script::test::DOMString;
|
use script::test::DOMString;
|
||||||
use script::textinput::{TextInput, TextPoint, Selection, Lines, Direction, SelectionDirection};
|
use script::textinput::{TextInput, TextPoint, Selection, Lines, Direction, SelectionDirection};
|
||||||
|
@ -420,34 +420,33 @@ fn test_textinput_adjust_horizontal_to_line_end() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
fn test_navigation_keyboard_shortcuts() {
|
fn test_navigation_keyboard_shortcuts() {
|
||||||
let mut textinput = text_input(Lines::Multiple, "hello áéc");
|
let mut textinput = text_input(Lines::Multiple, "hello áéc");
|
||||||
|
|
||||||
// Test that CMD + Right moves to the end of the current line.
|
// 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);
|
assert_eq!(textinput.edit_point().index, 11);
|
||||||
// Test that CMD + Right moves to the beginning of the current line.
|
// 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);
|
assert_eq!(textinput.edit_point().index, 0);
|
||||||
// Test that CTRL + ALT + E moves to the end of the current line also.
|
// 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);
|
assert_eq!(textinput.edit_point().index, 11);
|
||||||
// Test that CTRL + ALT + A moves to the beginning of the current line also.
|
// 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);
|
assert_eq!(textinput.edit_point().index, 0);
|
||||||
|
|
||||||
// Test that ALT + Right moves to the end of the word.
|
// 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);
|
assert_eq!(textinput.edit_point().index, 5);
|
||||||
// Test that CTRL + ALT + F moves to the end of the word also.
|
// 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);
|
assert_eq!(textinput.edit_point().index, 11);
|
||||||
// Test that ALT + Left moves to the end of the word.
|
// 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);
|
assert_eq!(textinput.edit_point().index, 6);
|
||||||
// Test that CTRL + ALT + B moves to the end of the word also.
|
// 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);
|
assert_eq!(textinput.edit_point().index, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,9 +506,9 @@ fn test_textinput_set_content() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_clipboard_paste() {
|
fn test_clipboard_paste() {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
const MODIFIERS: KeyModifiers = KeyModifiers::SUPER;
|
const MODIFIERS: Modifiers = Modifiers::META;
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
const MODIFIERS: KeyModifiers = KeyModifiers::CONTROL;
|
const MODIFIERS: Modifiers = Modifiers::CONTROL;
|
||||||
|
|
||||||
let mut textinput = TextInput::new(Lines::Single,
|
let mut textinput = TextInput::new(Lines::Single,
|
||||||
DOMString::from("defg"),
|
DOMString::from("defg"),
|
||||||
|
@ -519,7 +518,7 @@ fn test_clipboard_paste() {
|
||||||
SelectionDirection::None);
|
SelectionDirection::None);
|
||||||
assert_eq!(textinput.get_content(), "defg");
|
assert_eq!(textinput.get_content(), "defg");
|
||||||
assert_eq!(textinput.edit_point().index, 0);
|
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");
|
assert_eq!(textinput.get_content(), "abcdefg");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue