aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/compositing/compositor.rs12
-rw-r--r--components/compositing/compositor_thread.rs2
-rw-r--r--components/compositing/windowing.rs4
-rw-r--r--components/constellation/constellation.rs16
-rw-r--r--components/script/dom/bindings/str.rs11
-rw-r--r--components/script/dom/bindings/trace.rs2
-rw-r--r--components/script/dom/document.rs9
-rw-r--r--components/script/dom/keyboardevent.rs42
-rw-r--r--components/script/script_thread.rs4
-rw-r--r--components/script/textinput.rs68
-rw-r--r--components/script_traits/lib.rs4
-rw-r--r--components/script_traits/script_msg.rs2
-rw-r--r--components/servo/Cargo.lock4
-rw-r--r--ports/cef/Cargo.lock4
-rw-r--r--ports/cef/browser_host.rs4
-rw-r--r--ports/cef/window.rs2
-rw-r--r--ports/geckolib/Cargo.lock4
-rw-r--r--ports/glutin/window.rs159
-rw-r--r--tests/unit/script/textinput.rs2
19 files changed, 233 insertions, 122 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs
index 270a6b656d0..8041fd7f1df 100644
--- a/components/compositing/compositor.rs
+++ b/components/compositing/compositor.rs
@@ -701,9 +701,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.composition_request = CompositionRequest::CompositeNow(reason)
}
- (Msg::KeyEvent(key, state, modified), ShutdownState::NotShuttingDown) => {
+ (Msg::KeyEvent(ch, key, state, modified), ShutdownState::NotShuttingDown) => {
if state == KeyState::Pressed {
- self.window.handle_key(key, modified);
+ self.window.handle_key(ch, key, modified);
}
}
@@ -1348,8 +1348,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.on_touchpad_pressure_event(cursor, pressure, stage);
}
- WindowEvent::KeyEvent(key, state, modifiers) => {
- self.on_key_event(key, state, modifiers);
+ WindowEvent::KeyEvent(ch, key, state, modifiers) => {
+ self.on_key_event(ch, key, state, modifiers);
}
WindowEvent::Quit => {
@@ -1880,8 +1880,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
}
- fn on_key_event(&self, key: Key, state: KeyState, modifiers: KeyModifiers) {
- let msg = ConstellationMsg::KeyEvent(key, state, modifiers);
+ fn on_key_event(&self, ch: Option<char>, key: Key, state: KeyState, modifiers: KeyModifiers) {
+ let msg = ConstellationMsg::KeyEvent(ch, key, state, modifiers);
if let Err(e) = self.constellation_chan.send(msg) {
warn!("Sending key event to constellation failed ({}).", e);
}
diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs
index 24b9caba0a7..49d0692e6c8 100644
--- a/components/compositing/compositor_thread.rs
+++ b/components/compositing/compositor_thread.rs
@@ -151,7 +151,7 @@ pub enum Msg {
/// Composite.
Recomposite(CompositingReason),
/// Sends an unconsumed key event back to the compositor.
- KeyEvent(Key, KeyState, KeyModifiers),
+ KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
/// Script has handled a touch event, and either prevented or allowed default actions.
TouchEventProcessed(EventResult),
/// Changes the cursor.
diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs
index b67803b07c6..2da658a9661 100644
--- a/components/compositing/windowing.rs
+++ b/components/compositing/windowing.rs
@@ -76,7 +76,7 @@ pub enum WindowEvent {
/// Sent when the user quits the application
Quit,
/// Sent when a key input state changes
- KeyEvent(Key, KeyState, KeyModifiers),
+ KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
/// Sent when Ctr+R/Apple+R is called to reload the current page.
Reload,
}
@@ -159,7 +159,7 @@ pub trait WindowMethods {
fn set_cursor(&self, cursor: Cursor);
/// Process a key event.
- fn handle_key(&self, key: Key, mods: KeyModifiers);
+ fn handle_key(&self, ch: Option<char>, key: Key, mods: KeyModifiers);
/// Does this window support a clipboard
fn supports_clipboard(&self) -> bool;
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs
index 7c3a95dbc54..0920a4a523f 100644
--- a/components/constellation/constellation.rs
+++ b/components/constellation/constellation.rs
@@ -574,9 +574,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
debug!("constellation got get-pipeline-title message");
self.handle_get_pipeline_title_msg(pipeline_id);
}
- FromCompositorMsg::KeyEvent(key, state, modifiers) => {
+ FromCompositorMsg::KeyEvent(ch, key, state, modifiers) => {
debug!("constellation got key event message");
- self.handle_key_msg(key, state, modifiers);
+ self.handle_key_msg(ch, key, state, modifiers);
}
// Load a new page from a typed url
// If there is already a pending page (self.pending_frames), it will not be overridden;
@@ -803,8 +803,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.compositor_proxy.send(ToCompositorMsg::ChangePageTitle(pipeline_id, title))
}
- FromScriptMsg::SendKeyEvent(key, key_state, key_modifiers) => {
- self.compositor_proxy.send(ToCompositorMsg::KeyEvent(key, key_state, key_modifiers))
+ FromScriptMsg::SendKeyEvent(ch, key, key_state, key_modifiers) => {
+ self.compositor_proxy.send(ToCompositorMsg::KeyEvent(ch, key, key_state, key_modifiers))
}
FromScriptMsg::TouchEventProcessed(result) => {
@@ -1396,7 +1396,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}
- fn handle_key_msg(&mut self, key: Key, state: KeyState, mods: KeyModifiers) {
+ fn handle_key_msg(&mut self, ch: Option<char>, key: Key, state: KeyState, mods: KeyModifiers) {
// Send to the explicitly focused pipeline (if it exists), or the root
// frame's current pipeline. If neither exist, fall back to sending to
// the compositor below.
@@ -1407,7 +1407,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
match pipeline_id {
Some(pipeline_id) => {
- let event = CompositorEvent::KeyEvent(key, state, mods);
+ let event = CompositorEvent::KeyEvent(ch, key, state, mods);
let msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
let result = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => pipeline.script_chan.send(msg),
@@ -1418,7 +1418,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
},
None => {
- let event = ToCompositorMsg::KeyEvent(key, state, mods);
+ let event = ToCompositorMsg::KeyEvent(ch, key, state, mods);
self.compositor_proxy.clone_compositor_proxy().send(event);
}
}
@@ -1629,7 +1629,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
None => return warn!("Pipeline {:?} SendKeys after closure.", pipeline_id),
};
for (key, mods, state) in cmd {
- let event = CompositorEvent::KeyEvent(key, state, mods);
+ let event = CompositorEvent::KeyEvent(None, key, state, mods);
let control_msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
if let Err(e) = script_channel.send(control_msg) {
return self.handle_send_error(pipeline_id, e);
diff --git a/components/script/dom/bindings/str.rs b/components/script/dom/bindings/str.rs
index 69565520899..310285a8bcd 100644
--- a/components/script/dom/bindings/str.rs
+++ b/components/script/dom/bindings/str.rs
@@ -5,7 +5,7 @@
//! The `ByteString` struct.
use std::ascii::AsciiExt;
-use std::borrow::ToOwned;
+use std::borrow::{ToOwned, Cow};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops;
@@ -204,6 +204,15 @@ impl<'a> From<&'a str> for DOMString {
}
}
+impl<'a> From<Cow<'a, str>> for DOMString {
+ fn from(contents: Cow<'a, str>) -> DOMString {
+ match contents {
+ Cow::Owned(s) => DOMString::from(s),
+ Cow::Borrowed(s) => DOMString::from(s),
+ }
+ }
+}
+
impl From<DOMString> for Atom {
fn from(contents: DOMString) -> Atom {
Atom::from(contents.0)
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index 7404e96b95d..e2c6e540a3d 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -276,7 +276,7 @@ impl<A: JSTraceable, B: JSTraceable, C: JSTraceable> JSTraceable for (A, B, C) {
}
}
-no_jsmanaged_fields!(bool, f32, f64, String, Url, AtomicBool, AtomicUsize, UrlOrigin, Uuid);
+no_jsmanaged_fields!(bool, f32, f64, String, Url, AtomicBool, AtomicUsize, UrlOrigin, Uuid, char);
no_jsmanaged_fields!(usize, u8, u16, u32, u64);
no_jsmanaged_fields!(isize, i8, i16, i32, i64);
no_jsmanaged_fields!(Sender<T>);
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 2160a3a4556..43a4473689e 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -1044,6 +1044,7 @@ impl Document {
/// The entry point for all key processing for web content
pub fn dispatch_key_event(&self,
+ ch: Option<char>,
key: Key,
state: KeyState,
modifiers: KeyModifiers,
@@ -1070,7 +1071,7 @@ impl Document {
}
.to_owned());
- let props = KeyboardEvent::key_properties(key, modifiers);
+ let props = KeyboardEvent::key_properties(ch, key, modifiers);
let keyevent = KeyboardEvent::new(&self.window,
ev_type,
@@ -1078,8 +1079,9 @@ impl Document {
true,
Some(&self.window),
0,
+ ch,
Some(key),
- DOMString::from(props.key_string),
+ DOMString::from(props.key_string.clone()),
DOMString::from(props.code),
props.location,
is_repeating,
@@ -1103,6 +1105,7 @@ impl Document {
true,
Some(&self.window),
0,
+ ch,
Some(key),
DOMString::from(props.key_string),
DOMString::from(props.code),
@@ -1122,7 +1125,7 @@ impl Document {
}
if !prevented {
- constellation.send(ConstellationMsg::SendKeyEvent(key, state, modifiers)).unwrap();
+ constellation.send(ConstellationMsg::SendKeyEvent(ch, key, state, modifiers)).unwrap();
}
// This behavior is unspecced
diff --git a/components/script/dom/keyboardevent.rs b/components/script/dom/keyboardevent.rs
index 4cfa1a61011..71b00767a8e 100644
--- a/components/script/dom/keyboardevent.rs
+++ b/components/script/dom/keyboardevent.rs
@@ -17,6 +17,7 @@ use dom::uievent::UIEvent;
use dom::window::Window;
use msg::constellation_msg;
use msg::constellation_msg::{Key, KeyModifiers};
+use std::borrow::Cow;
use std::cell::Cell;
no_jsmanaged_fields!(Key);
@@ -36,6 +37,7 @@ pub struct KeyboardEvent {
is_composing: Cell<bool>,
char_code: Cell<Option<u32>>,
key_code: Cell<u32>,
+ printable: Cell<Option<char>>,
}
impl KeyboardEvent {
@@ -54,6 +56,7 @@ impl KeyboardEvent {
is_composing: Cell::new(false),
char_code: Cell::new(None),
key_code: Cell::new(0),
+ printable: Cell::new(None),
}
}
@@ -69,6 +72,7 @@ impl KeyboardEvent {
cancelable: bool,
view: Option<&Window>,
_detail: i32,
+ ch: Option<char>,
key: Option<Key>,
key_string: DOMString,
code: DOMString,
@@ -91,6 +95,7 @@ impl KeyboardEvent {
ev.shift.set(shiftKey);
ev.meta.set(metaKey);
ev.char_code.set(char_code);
+ ev.printable.set(ch);
ev.key_code.set(key_code);
ev.is_composing.set(isComposing);
ev
@@ -103,7 +108,9 @@ impl KeyboardEvent {
init.parent.parent.parent.bubbles,
init.parent.parent.parent.cancelable,
init.parent.parent.view.r(),
- init.parent.parent.detail, key_from_string(&init.key, init.location),
+ init.parent.parent.detail,
+ None,
+ key_from_string(&init.key, init.location),
init.key.clone(), init.code.clone(), init.location,
init.repeat, init.isComposing, init.parent.ctrlKey,
init.parent.altKey, init.parent.shiftKey, init.parent.metaKey,
@@ -111,13 +118,13 @@ impl KeyboardEvent {
Ok(event)
}
- pub fn key_properties(key: Key, mods: KeyModifiers)
+ pub fn key_properties(ch: Option<char>, key: Key, mods: KeyModifiers)
-> KeyEventProperties {
KeyEventProperties {
- key_string: key_value(key, mods),
+ key_string: key_value(ch, key, mods),
code: code_value(key),
location: key_location(key),
- char_code: key_charcode(key, mods),
+ char_code: ch.map(|ch| ch as u32),
key_code: key_keycode(key),
}
}
@@ -125,6 +132,10 @@ impl KeyboardEvent {
impl KeyboardEvent {
+ pub fn printable(&self) -> Option<char> {
+ self.printable.get()
+ }
+
pub fn get_key(&self) -> Option<Key> {
self.key.get().clone()
}
@@ -147,11 +158,14 @@ impl KeyboardEvent {
}
}
-
// https://w3c.github.io/uievents-key/#key-value-tables
-pub fn key_value(key: Key, mods: KeyModifiers) -> &'static str {
+pub fn key_value(ch: Option<char>, key: Key, mods: KeyModifiers) -> Cow<'static, str> {
+ if let Some(ch) = ch {
+ return Cow::from(format!("{}", ch));
+ }
+
let shift = mods.contains(constellation_msg::SHIFT);
- match key {
+ Cow::from(match key {
Key::Space => " ",
Key::Apostrophe if shift => "\"",
Key::Apostrophe => "'",
@@ -321,7 +335,7 @@ pub fn key_value(key: Key, mods: KeyModifiers) -> &'static str {
Key::Menu => "ContextMenu",
Key::NavigateForward => "BrowserForward",
Key::NavigateBackward => "BrowserBack",
- }
+ })
}
fn key_from_string(key_string: &str, location: u32) -> Option<Key> {
@@ -647,16 +661,6 @@ fn key_location(key: Key) -> u32 {
}
}
-// https://w3c.github.io/uievents/#dom-keyboardevent-charcode
-fn key_charcode(key: Key, mods: KeyModifiers) -> Option<u32> {
- let key_string = key_value(key, mods);
- if key_string.len() == 1 {
- Some(key_string.chars().next().unwrap() as u32)
- } else {
- None
- }
-}
-
// https://w3c.github.io/uievents/#legacy-key-models
fn key_keycode(key: Key) -> u32 {
match key {
@@ -739,7 +743,7 @@ fn key_keycode(key: Key) -> u32 {
#[derive(HeapSizeOf)]
pub struct KeyEventProperties {
- pub key_string: &'static str,
+ pub key_string: Cow<'static, str>,
pub code: &'static str,
pub location: u32,
pub char_code: Option<u32>,
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 2367ecc0fd9..05689baac39 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -1937,12 +1937,12 @@ impl ScriptThread {
document.r().handle_touchpad_pressure_event(self.js_runtime.rt(), point, pressure, phase);
}
- KeyEvent(key, state, modifiers) => {
+ KeyEvent(ch, key, state, modifiers) => {
let document = match self.root_browsing_context().find(pipeline_id) {
Some(browsing_context) => browsing_context.active_document(),
None => return warn!("Message sent to closed pipeline {}.", pipeline_id),
};
- document.dispatch_key_event(key, state, modifiers, &self.constellation_chan);
+ document.dispatch_key_event(ch, key, state, modifiers, &self.constellation_chan);
}
}
}
diff --git a/components/script/textinput.rs b/components/script/textinput.rs
index a56bd983f34..871af9637c0 100644
--- a/components/script/textinput.rs
+++ b/components/script/textinput.rs
@@ -6,7 +6,7 @@
use clipboard_provider::ClipboardProvider;
use dom::bindings::str::DOMString;
-use dom::keyboardevent::{KeyboardEvent, key_value};
+use dom::keyboardevent::KeyboardEvent;
use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER};
use msg::constellation_msg::{Key, KeyModifiers};
use std::borrow::ToOwned;
@@ -120,24 +120,6 @@ fn is_control_key(mods: KeyModifiers) -> bool {
mods.contains(CONTROL) && !mods.contains(SUPER | ALT)
}
-fn is_printable_key(key: Key) -> bool {
- match key {
- Key::Space | Key::Apostrophe | Key::Comma | Key::Minus |
- Key::Period | Key::Slash | Key::GraveAccent | Key::Num0 |
- Key::Num1 | Key::Num2 | Key::Num3 | Key::Num4 | Key::Num5 |
- Key::Num6 | Key::Num7 | Key::Num8 | Key::Num9 | Key::Semicolon |
- Key::Equal | 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::LeftBracket | Key::Backslash |
- Key::RightBracket | 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::KpEqual => true,
- _ => false,
- }
-}
-
/// The length in bytes of the first n characters in a UTF-8 string.
///
/// If the string has fewer than n characters, returns the length of the whole string.
@@ -486,80 +468,80 @@ impl<T: ClipboardProvider> TextInput<T> {
/// Process a given `KeyboardEvent` and return an action for the caller to execute.
pub fn handle_keydown(&mut self, event: &KeyboardEvent) -> KeyReaction {
if let Some(key) = event.get_key() {
- self.handle_keydown_aux(key, event.get_key_modifiers())
+ self.handle_keydown_aux(event.printable(), key, event.get_key_modifiers())
} else {
KeyReaction::Nothing
}
}
- pub fn handle_keydown_aux(&mut self, key: Key, mods: KeyModifiers) -> KeyReaction {
+
+ pub fn handle_keydown_aux(&mut self,
+ printable: Option<char>,
+ key: Key,
+ mods: KeyModifiers) -> KeyReaction {
let maybe_select = if mods.contains(SHIFT) { Selection::Selected } else { Selection::NotSelected };
- match key {
- Key::A if is_control_key(mods) => {
+ match (printable, key) {
+ (Some('a'), _) if is_control_key(mods) => {
self.select_all();
KeyReaction::RedrawSelection
},
- Key::C if is_control_key(mods) => {
+ (Some('c'), _) if is_control_key(mods) => {
if let Some(text) = self.get_selection_text() {
self.clipboard_provider.set_clipboard_contents(text);
}
KeyReaction::DispatchInput
},
- Key::V if is_control_key(mods) => {
+ (Some('v'), _) if is_control_key(mods) => {
let contents = self.clipboard_provider.clipboard_contents();
self.insert_string(contents);
KeyReaction::DispatchInput
},
- _ if is_printable_key(key) => {
- self.insert_string(key_value(key, mods));
- KeyReaction::DispatchInput
- }
- Key::Space => {
- self.insert_char(' ');
+ (Some(c), _) => {
+ self.insert_char(c);
KeyReaction::DispatchInput
}
- Key::Delete => {
+ (None, Key::Delete) => {
self.delete_char(Direction::Forward);
KeyReaction::DispatchInput
}
- Key::Backspace => {
+ (None, Key::Backspace) => {
self.delete_char(Direction::Backward);
KeyReaction::DispatchInput
}
- Key::Left => {
+ (None, Key::Left) => {
self.adjust_horizontal_by_one(Direction::Backward, maybe_select);
KeyReaction::RedrawSelection
}
- Key::Right => {
+ (None, Key::Right) => {
self.adjust_horizontal_by_one(Direction::Forward, maybe_select);
KeyReaction::RedrawSelection
}
- Key::Up => {
+ (None, Key::Up) => {
self.adjust_vertical(-1, maybe_select);
KeyReaction::RedrawSelection
}
- Key::Down => {
+ (None, Key::Down) => {
self.adjust_vertical(1, maybe_select);
KeyReaction::RedrawSelection
}
- Key::Enter | Key::KpEnter => self.handle_return(),
- Key::Home => {
+ (None, Key::Enter) | (None, Key::KpEnter) => self.handle_return(),
+ (None, Key::Home) => {
self.edit_point.index = 0;
KeyReaction::RedrawSelection
}
- Key::End => {
+ (None, Key::End) => {
self.edit_point.index = self.current_line_length();
self.assert_ok_selection();
KeyReaction::RedrawSelection
}
- Key::PageUp => {
+ (None, Key::PageUp) => {
self.adjust_vertical(-28, maybe_select);
KeyReaction::RedrawSelection
}
- Key::PageDown => {
+ (None, Key::PageDown) => {
self.adjust_vertical(28, maybe_select);
KeyReaction::RedrawSelection
}
- Key::Tab => KeyReaction::TriggerDefaultAction,
+ (None, Key::Tab) => KeyReaction::TriggerDefaultAction,
_ => KeyReaction::Nothing,
}
}
diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs
index bd82a498d46..5c6064a3d3e 100644
--- a/components/script_traits/lib.rs
+++ b/components/script_traits/lib.rs
@@ -282,7 +282,7 @@ pub enum CompositorEvent {
/// Touchpad pressure event
TouchpadPressureEvent(Point2D<f32>, f32, TouchpadPressurePhase),
/// A key was pressed.
- KeyEvent(Key, KeyState, KeyModifiers),
+ KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
}
/// Touchpad pressure phase for TouchpadPressureEvent.
@@ -586,7 +586,7 @@ pub enum ConstellationMsg {
/// Query the constellation to see if the current compositor output is stable
IsReadyToSaveImage(HashMap<PipelineId, Epoch>),
/// Inform the constellation of a key event.
- KeyEvent(Key, KeyState, KeyModifiers),
+ KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
/// Request to load a page.
LoadUrl(PipelineId, LoadData),
/// Request to navigate a frame.
diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs
index 7fc871eb4cc..0ac5aeae4b4 100644
--- a/components/script_traits/script_msg.rs
+++ b/components/script_traits/script_msg.rs
@@ -103,7 +103,7 @@ pub enum ScriptMsg {
/// https://html.spec.whatwg.org/multipage/#document.title
SetTitle(PipelineId, Option<String>),
/// Send a key event
- SendKeyEvent(Key, KeyState, KeyModifiers),
+ SendKeyEvent(Option<char>, Key, KeyState, KeyModifiers),
/// Get Window Informations size and position
GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
/// Move the window to a point
diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock
index 997fc8ab250..030f19a5038 100644
--- a/components/servo/Cargo.lock
+++ b/components/servo/Cargo.lock
@@ -146,7 +146,7 @@ dependencies = [
[[package]]
name = "bincode"
-version = "0.5.7"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1061,7 +1061,7 @@ name = "ipc-channel"
version = "0.2.3"
source = "git+https://github.com/servo/ipc-channel#48137d69955f5460da586c552de275ecdc3f4efe"
dependencies = [
- "bincode 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bincode 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock
index 4907cc20629..7071b45ddcf 100644
--- a/ports/cef/Cargo.lock
+++ b/ports/cef/Cargo.lock
@@ -120,7 +120,7 @@ dependencies = [
[[package]]
name = "bincode"
-version = "0.5.7"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -970,7 +970,7 @@ name = "ipc-channel"
version = "0.2.3"
source = "git+https://github.com/servo/ipc-channel#48137d69955f5460da586c552de275ecdc3f4efe"
dependencies = [
- "bincode 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bincode 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/ports/cef/browser_host.rs b/ports/cef/browser_host.rs
index bbf776ee839..fce7c6c5735 100644
--- a/ports/cef/browser_host.rs
+++ b/ports/cef/browser_host.rs
@@ -17,6 +17,7 @@ use libc::{c_double, c_int};
use msg::constellation_msg::{self, KeyModifiers, KeyState};
use script_traits::{MouseButton, TouchEventType};
use std::cell::{Cell, RefCell};
+use std::char;
pub struct ServoCefBrowserHost {
/// A reference to the browser.
@@ -424,7 +425,8 @@ full_cef_class_impl! {
if (*event).modifiers & EVENTFLAG_ALT_DOWN as u32 != 0 {
key_modifiers = key_modifiers | constellation_msg::ALT;
}
- this.downcast().send_window_event(WindowEvent::KeyEvent(key, key_state, key_modifiers))
+ let ch = char::from_u32((*event).character as u32);
+ this.downcast().send_window_event(WindowEvent::KeyEvent(ch, key, key_state, key_modifiers))
}}
fn send_mouse_click_event(&this,
diff --git a/ports/cef/window.rs b/ports/cef/window.rs
index 1d4ee0a3281..e5c2cd5f4db 100644
--- a/ports/cef/window.rs
+++ b/ports/cef/window.rs
@@ -479,7 +479,7 @@ impl WindowMethods for Window {
}
}
- fn handle_key(&self, _: Key, _: KeyModifiers) {
+ fn handle_key(&self, _: Option<char>, _: Key, _: KeyModifiers) {
// TODO(negge)
}
diff --git a/ports/geckolib/Cargo.lock b/ports/geckolib/Cargo.lock
index 27b841fb790..38213b2f352 100644
--- a/ports/geckolib/Cargo.lock
+++ b/ports/geckolib/Cargo.lock
@@ -72,7 +72,7 @@ dependencies = [
[[package]]
name = "bincode"
-version = "0.5.7"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -254,7 +254,7 @@ name = "ipc-channel"
version = "0.2.4"
source = "git+https://github.com/servo/ipc-channel#8411eeabf3a712006ad1b47637b2d8fe71177f85"
dependencies = [
- "bincode 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bincode 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/ports/glutin/window.rs b/ports/glutin/window.rs
index a6efae6aab4..00bd7ceff0a 100644
--- a/ports/glutin/window.rs
+++ b/ports/glutin/window.rs
@@ -14,10 +14,10 @@ use euclid::{Size2D, Point2D};
#[cfg(target_os = "windows")] use gdi32;
use gleam::gl;
use glutin;
-use glutin::TouchPhase;
#[cfg(target_os = "macos")]
use glutin::os::macos::{ActivationPolicy, WindowBuilderExt};
use glutin::{Api, ElementState, Event, GlRequest, MouseButton, VirtualKeyCode, MouseScrollDelta};
+use glutin::{ScanCode, TouchPhase};
use layers::geometry::DevicePixel;
use layers::platform::surface::NativeDisplay;
use msg::constellation_msg::{KeyState, NONE, CONTROL, SHIFT, ALT, SUPER};
@@ -99,6 +99,12 @@ pub struct Window {
mouse_pos: Cell<Point2D<i32>>,
key_modifiers: Cell<KeyModifiers>,
current_url: RefCell<Option<Url>>,
+
+ /// The contents of the last ReceivedCharacter event for use in a subsequent KeyEvent.
+ pending_key_event_char: Cell<Option<char>>,
+ /// The list of keys that have been pressed but not yet released, to allow providing
+ /// the equivalent ReceivedCharacter data as was received for the press event.
+ pressed_key_map: RefCell<Vec<(ScanCode, char)>>,
}
#[cfg(not(target_os = "windows"))]
@@ -175,6 +181,9 @@ impl Window {
mouse_pos: Cell::new(Point2D::new(0, 0)),
key_modifiers: Cell::new(KeyModifiers::empty()),
current_url: RefCell::new(None),
+
+ pending_key_event_char: Cell::new(None),
+ pressed_key_map: RefCell::new(vec![]),
};
gl::clear_color(0.6, 0.6, 0.6, 1.0);
@@ -232,7 +241,13 @@ impl Window {
fn handle_window_event(&self, event: glutin::Event) -> bool {
match event {
- Event::KeyboardInput(element_state, _scan_code, Some(virtual_key_code)) => {
+ Event::ReceivedCharacter(ch) => {
+ assert!(self.pending_key_event_char.get().is_none());
+ if !ch.is_control() {
+ self.pending_key_event_char.set(Some(ch));
+ }
+ }
+ Event::KeyboardInput(element_state, scan_code, Some(virtual_key_code)) => {
match virtual_key_code {
VirtualKeyCode::LControl => self.toggle_modifier(LEFT_CONTROL),
VirtualKeyCode::RControl => self.toggle_modifier(RIGHT_CONTROL),
@@ -245,13 +260,39 @@ impl Window {
_ => {}
}
+ let ch = match element_state {
+ ElementState::Pressed => {
+ // Retrieve any previosly stored ReceivedCharacter value.
+ // Store the association between the scan code and the actual
+ // character value, if there is one.
+ let ch = self.pending_key_event_char
+ .get()
+ .and_then(|ch| filter_nonprintable(ch, virtual_key_code));
+ self.pending_key_event_char.set(None);
+ if let Some(ch) = ch {
+ self.pressed_key_map.borrow_mut().push((scan_code, ch));
+ }
+ ch
+ }
+
+ ElementState::Released => {
+ // Retrieve the associated character value for this release key,
+ // if one was previously stored.
+ let idx = self.pressed_key_map
+ .borrow()
+ .iter()
+ .position(|&(code, _)| code == scan_code);
+ idx.map(|idx| self.pressed_key_map.borrow_mut().swap_remove(idx).1)
+ }
+ };
+
if let Ok(key) = Window::glutin_key_to_script_key(virtual_key_code) {
let state = match element_state {
ElementState::Pressed => KeyState::Pressed,
ElementState::Released => KeyState::Released,
};
let modifiers = Window::glutin_mods_to_script_mods(self.key_modifiers.get());
- self.event_queue.borrow_mut().push(WindowEvent::KeyEvent(key, state, modifiers));
+ self.event_queue.borrow_mut().push(WindowEvent::KeyEvent(ch, key, state, modifiers));
}
}
Event::KeyboardInput(_, _, None) => {
@@ -803,48 +844,47 @@ impl WindowMethods for Window {
}
/// Helper function to handle keyboard events.
- fn handle_key(&self, key: Key, mods: constellation_msg::KeyModifiers) {
- match (mods, key) {
- (_, Key::Equal) => {
+ fn handle_key(&self, ch: Option<char>, key: Key, mods: constellation_msg::KeyModifiers) {
+ match (mods, ch, key) {
+ (_, Some('+'), _) => {
if mods & !SHIFT == CMD_OR_CONTROL {
self.event_queue.borrow_mut().push(WindowEvent::Zoom(1.1));
} else if mods & !SHIFT == CMD_OR_CONTROL | ALT {
self.event_queue.borrow_mut().push(WindowEvent::PinchZoom(1.1));
}
}
- (CMD_OR_CONTROL, Key::Minus) => {
+ (CMD_OR_CONTROL, Some('-'), _) => {
self.event_queue.borrow_mut().push(WindowEvent::Zoom(1.0 / 1.1));
}
- (_, Key::Minus) if mods == CMD_OR_CONTROL | ALT => {
+ (_, Some('-'), _) if mods == CMD_OR_CONTROL | ALT => {
self.event_queue.borrow_mut().push(WindowEvent::PinchZoom(1.0 / 1.1));
}
- (CMD_OR_CONTROL, Key::Num0) |
- (CMD_OR_CONTROL, Key::Kp0) => {
+ (CMD_OR_CONTROL, Some('0'), _) => {
self.event_queue.borrow_mut().push(WindowEvent::ResetZoom);
}
- (NONE, Key::NavigateForward) => {
+ (NONE, None, Key::NavigateForward) => {
self.event_queue.borrow_mut().push(WindowEvent::Navigation(WindowNavigateMsg::Forward));
}
- (NONE, Key::NavigateBackward) => {
+ (NONE, None, Key::NavigateBackward) => {
self.event_queue.borrow_mut().push(WindowEvent::Navigation(WindowNavigateMsg::Back));
}
- (NONE, Key::Escape) => {
+ (NONE, None, Key::Escape) => {
if let Some(true) = PREFS.get("shell.builtin-key-shortcuts.enabled").as_boolean() {
self.event_queue.borrow_mut().push(WindowEvent::Quit);
}
}
- (CMD_OR_ALT, Key::Right) => {
+ (CMD_OR_ALT, None, Key::Right) => {
self.event_queue.borrow_mut().push(WindowEvent::Navigation(WindowNavigateMsg::Forward));
}
- (CMD_OR_ALT, Key::Left) => {
+ (CMD_OR_ALT, None, Key::Left) => {
self.event_queue.borrow_mut().push(WindowEvent::Navigation(WindowNavigateMsg::Back));
}
- (NONE, Key::PageDown) |
- (NONE, Key::Space) => {
+ (NONE, None, Key::PageDown) |
+ (NONE, Some(' '), _) => {
self.scroll_window(0.0,
-self.framebuffer_size()
.as_f32()
@@ -852,8 +892,8 @@ impl WindowMethods for Window {
.height + 2.0 * LINE_HEIGHT,
TouchEventType::Move);
}
- (NONE, Key::PageUp) |
- (SHIFT, Key::Space) => {
+ (NONE, None, Key::PageUp) |
+ (SHIFT, Some(' '), _) => {
self.scroll_window(0.0,
self.framebuffer_size()
.as_f32()
@@ -861,19 +901,19 @@ impl WindowMethods for Window {
.height - 2.0 * LINE_HEIGHT,
TouchEventType::Move);
}
- (NONE, Key::Up) => {
+ (NONE, None, Key::Up) => {
self.scroll_window(0.0, 3.0 * LINE_HEIGHT, TouchEventType::Move);
}
- (NONE, Key::Down) => {
+ (NONE, None, Key::Down) => {
self.scroll_window(0.0, -3.0 * LINE_HEIGHT, TouchEventType::Move);
}
- (NONE, Key::Left) => {
+ (NONE, None, Key::Left) => {
self.scroll_window(LINE_HEIGHT, 0.0, TouchEventType::Move);
}
- (NONE, Key::Right) => {
+ (NONE, None, Key::Right) => {
self.scroll_window(-LINE_HEIGHT, 0.0, TouchEventType::Move);
}
- (CMD_OR_CONTROL, Key::R) => {
+ (CMD_OR_CONTROL, Some('r'), _) => {
if let Some(true) = PREFS.get("shell.builtin-key-shortcuts.enabled").as_boolean() {
self.event_queue.borrow_mut().push(WindowEvent::Reload);
}
@@ -932,6 +972,77 @@ fn glutin_pressure_stage_to_touchpad_pressure_phase(stage: i64) -> TouchpadPress
}
}
+fn filter_nonprintable(ch: char, key_code: VirtualKeyCode) -> Option<char> {
+ use glutin::VirtualKeyCode::*;
+ match key_code {
+ Escape |
+ F1 |
+ F2 |
+ F3 |
+ F4 |
+ F5 |
+ F6 |
+ F7 |
+ F8 |
+ F9 |
+ F10 |
+ F11 |
+ F12 |
+ F13 |
+ F14 |
+ F15 |
+ Snapshot |
+ Scroll |
+ Pause |
+ Insert |
+ Home |
+ Delete |
+ End |
+ PageDown |
+ PageUp |
+ Left |
+ Up |
+ Right |
+ Down |
+ Back |
+ LAlt |
+ LControl |
+ LMenu |
+ LShift |
+ LWin |
+ Mail |
+ MediaSelect |
+ MediaStop |
+ Mute |
+ MyComputer |
+ NavigateForward |
+ NavigateBackward |
+ NextTrack |
+ NoConvert |
+ PlayPause |
+ Power |
+ PrevTrack |
+ RAlt |
+ RControl |
+ RMenu |
+ RShift |
+ RWin |
+ Sleep |
+ Stop |
+ VolumeDown |
+ VolumeUp |
+ Wake |
+ WebBack |
+ WebFavorites |
+ WebForward |
+ WebHome |
+ WebRefresh |
+ WebSearch |
+ WebStop => None,
+ _ => Some(ch),
+ }
+}
+
// These functions aren't actually called. They are here as a link
// hack because Skia references them.
diff --git a/tests/unit/script/textinput.rs b/tests/unit/script/textinput.rs
index 4ee2c897bef..d5e9c1268d6 100644
--- a/tests/unit/script/textinput.rs
+++ b/tests/unit/script/textinput.rs
@@ -401,7 +401,7 @@ fn test_clipboard_paste() {
SelectionDirection::None);
assert_eq!(textinput.get_content(), "defg");
assert_eq!(textinput.edit_point.index, 0);
- textinput.handle_keydown_aux(Key::V, MODIFIERS);
+ textinput.handle_keydown_aux(Some('v'), Key::V, MODIFIERS);
assert_eq!(textinput.get_content(), "abcdefg");
}