mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Associate logical and physical keypresses together to support non-QWERTY keyboards.
This commit is contained in:
parent
87c7772527
commit
04ce86c08c
15 changed files with 137 additions and 77 deletions
|
@ -701,9 +701,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
self.composition_request = CompositionRequest::CompositeNow(reason)
|
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 {
|
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);
|
self.on_touchpad_pressure_event(cursor, pressure, stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowEvent::KeyEvent(key, state, modifiers) => {
|
WindowEvent::KeyEvent(ch, key, state, modifiers) => {
|
||||||
self.on_key_event(key, state, modifiers);
|
self.on_key_event(ch, key, state, modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowEvent::Quit => {
|
WindowEvent::Quit => {
|
||||||
|
@ -1880,8 +1880,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_key_event(&self, key: Key, state: KeyState, modifiers: KeyModifiers) {
|
fn on_key_event(&self, ch: Option<char>, key: Key, state: KeyState, modifiers: KeyModifiers) {
|
||||||
let msg = ConstellationMsg::KeyEvent(key, state, modifiers);
|
let msg = ConstellationMsg::KeyEvent(ch, key, state, modifiers);
|
||||||
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 key event to constellation failed ({}).", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,7 +151,7 @@ pub enum Msg {
|
||||||
/// Composite.
|
/// Composite.
|
||||||
Recomposite(CompositingReason),
|
Recomposite(CompositingReason),
|
||||||
/// Sends an unconsumed key event back to the compositor.
|
/// 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.
|
/// Script has handled a touch event, and either prevented or allowed default actions.
|
||||||
TouchEventProcessed(EventResult),
|
TouchEventProcessed(EventResult),
|
||||||
/// Changes the cursor.
|
/// Changes the cursor.
|
||||||
|
|
|
@ -76,7 +76,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(Key, KeyState, KeyModifiers),
|
KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
|
||||||
/// 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,
|
Reload,
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ pub trait WindowMethods {
|
||||||
fn set_cursor(&self, cursor: Cursor);
|
fn set_cursor(&self, cursor: Cursor);
|
||||||
|
|
||||||
/// Process a key event.
|
/// 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
|
/// Does this window support a clipboard
|
||||||
fn supports_clipboard(&self) -> bool;
|
fn supports_clipboard(&self) -> bool;
|
||||||
|
|
|
@ -574,9 +574,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
debug!("constellation got get-pipeline-title message");
|
debug!("constellation got get-pipeline-title message");
|
||||||
self.handle_get_pipeline_title_msg(pipeline_id);
|
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");
|
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
|
// Load a new page from a typed url
|
||||||
// If there is already a pending page (self.pending_frames), it will not be overridden;
|
// 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))
|
self.compositor_proxy.send(ToCompositorMsg::ChangePageTitle(pipeline_id, title))
|
||||||
}
|
}
|
||||||
|
|
||||||
FromScriptMsg::SendKeyEvent(key, key_state, key_modifiers) => {
|
FromScriptMsg::SendKeyEvent(key, key_state, key_modifiers, ch) => {
|
||||||
self.compositor_proxy.send(ToCompositorMsg::KeyEvent(key, key_state, key_modifiers))
|
self.compositor_proxy.send(ToCompositorMsg::KeyEvent(ch, key, key_state, key_modifiers))
|
||||||
}
|
}
|
||||||
|
|
||||||
FromScriptMsg::TouchEventProcessed(result) => {
|
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
|
// Send to the explicitly focused pipeline (if it exists), or the root
|
||||||
// frame's current pipeline. If neither exist, fall back to sending to
|
// frame's current pipeline. If neither exist, fall back to sending to
|
||||||
// the compositor below.
|
// the compositor below.
|
||||||
|
@ -1407,7 +1407,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
|
|
||||||
match pipeline_id {
|
match pipeline_id {
|
||||||
Some(pipeline_id) => {
|
Some(pipeline_id) => {
|
||||||
let event = CompositorEvent::KeyEvent(key, state, mods);
|
let event = CompositorEvent::KeyEvent(key, state, mods, ch);
|
||||||
let msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
|
let msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
|
||||||
let result = match self.pipelines.get(&pipeline_id) {
|
let result = match self.pipelines.get(&pipeline_id) {
|
||||||
Some(pipeline) => pipeline.script_chan.send(msg),
|
Some(pipeline) => pipeline.script_chan.send(msg),
|
||||||
|
@ -1418,7 +1418,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let event = ToCompositorMsg::KeyEvent(key, state, mods);
|
let event = ToCompositorMsg::KeyEvent(ch, key, state, mods);
|
||||||
self.compositor_proxy.clone_compositor_proxy().send(event);
|
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),
|
None => return warn!("Pipeline {:?} SendKeys after closure.", pipeline_id),
|
||||||
};
|
};
|
||||||
for (key, mods, state) in cmd {
|
for (key, mods, state) in cmd {
|
||||||
let event = CompositorEvent::KeyEvent(key, state, mods);
|
let event = CompositorEvent::KeyEvent(key, state, mods, None);
|
||||||
let control_msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
|
let control_msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
|
||||||
if let Err(e) = script_channel.send(control_msg) {
|
if let Err(e) = script_channel.send(control_msg) {
|
||||||
return self.handle_send_error(pipeline_id, e);
|
return self.handle_send_error(pipeline_id, e);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! The `ByteString` struct.
|
//! The `ByteString` struct.
|
||||||
|
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::{ToOwned, Cow};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::ops;
|
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 {
|
impl From<DOMString> for Atom {
|
||||||
fn from(contents: DOMString) -> Atom {
|
fn from(contents: DOMString) -> Atom {
|
||||||
Atom::from(contents.0)
|
Atom::from(contents.0)
|
||||||
|
|
|
@ -1044,6 +1044,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(&self,
|
pub fn dispatch_key_event(&self,
|
||||||
|
ch: Option<char>,
|
||||||
key: Key,
|
key: Key,
|
||||||
state: KeyState,
|
state: KeyState,
|
||||||
modifiers: KeyModifiers,
|
modifiers: KeyModifiers,
|
||||||
|
@ -1070,7 +1071,7 @@ impl Document {
|
||||||
}
|
}
|
||||||
.to_owned());
|
.to_owned());
|
||||||
|
|
||||||
let props = KeyboardEvent::key_properties(key, modifiers);
|
let props = KeyboardEvent::key_properties(ch, key, modifiers);
|
||||||
|
|
||||||
let keyevent = KeyboardEvent::new(&self.window,
|
let keyevent = KeyboardEvent::new(&self.window,
|
||||||
ev_type,
|
ev_type,
|
||||||
|
@ -1078,8 +1079,9 @@ impl Document {
|
||||||
true,
|
true,
|
||||||
Some(&self.window),
|
Some(&self.window),
|
||||||
0,
|
0,
|
||||||
|
ch,
|
||||||
Some(key),
|
Some(key),
|
||||||
DOMString::from(props.key_string),
|
DOMString::from(props.key_string.clone()),
|
||||||
DOMString::from(props.code),
|
DOMString::from(props.code),
|
||||||
props.location,
|
props.location,
|
||||||
is_repeating,
|
is_repeating,
|
||||||
|
@ -1103,6 +1105,7 @@ impl Document {
|
||||||
true,
|
true,
|
||||||
Some(&self.window),
|
Some(&self.window),
|
||||||
0,
|
0,
|
||||||
|
ch,
|
||||||
Some(key),
|
Some(key),
|
||||||
DOMString::from(props.key_string),
|
DOMString::from(props.key_string),
|
||||||
DOMString::from(props.code),
|
DOMString::from(props.code),
|
||||||
|
@ -1122,7 +1125,7 @@ impl Document {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !prevented {
|
if !prevented {
|
||||||
constellation.send(ConstellationMsg::SendKeyEvent(key, state, modifiers)).unwrap();
|
constellation.send(ConstellationMsg::SendKeyEvent(key, state, modifiers, ch)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This behavior is unspecced
|
// This behavior is unspecced
|
||||||
|
|
|
@ -17,6 +17,7 @@ use dom::uievent::UIEvent;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use msg::constellation_msg;
|
use msg::constellation_msg;
|
||||||
use msg::constellation_msg::{Key, KeyModifiers};
|
use msg::constellation_msg::{Key, KeyModifiers};
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
|
||||||
no_jsmanaged_fields!(Key);
|
no_jsmanaged_fields!(Key);
|
||||||
|
@ -69,6 +70,7 @@ impl KeyboardEvent {
|
||||||
cancelable: bool,
|
cancelable: bool,
|
||||||
view: Option<&Window>,
|
view: Option<&Window>,
|
||||||
_detail: i32,
|
_detail: i32,
|
||||||
|
ch: Option<char>,
|
||||||
key: Option<Key>,
|
key: Option<Key>,
|
||||||
key_string: DOMString,
|
key_string: DOMString,
|
||||||
code: DOMString,
|
code: DOMString,
|
||||||
|
@ -84,7 +86,7 @@ impl KeyboardEvent {
|
||||||
let ev = KeyboardEvent::new_uninitialized(window);
|
let ev = KeyboardEvent::new_uninitialized(window);
|
||||||
ev.InitKeyboardEvent(type_, canBubble, cancelable, view, key_string, location,
|
ev.InitKeyboardEvent(type_, canBubble, cancelable, view, key_string, location,
|
||||||
DOMString::new(), repeat, DOMString::new());
|
DOMString::new(), repeat, DOMString::new());
|
||||||
ev.key.set(key);
|
ev.key.set(logical_key(ch, key, location));
|
||||||
*ev.code.borrow_mut() = code;
|
*ev.code.borrow_mut() = code;
|
||||||
ev.ctrl.set(ctrlKey);
|
ev.ctrl.set(ctrlKey);
|
||||||
ev.alt.set(altKey);
|
ev.alt.set(altKey);
|
||||||
|
@ -103,7 +105,9 @@ impl KeyboardEvent {
|
||||||
init.parent.parent.parent.bubbles,
|
init.parent.parent.parent.bubbles,
|
||||||
init.parent.parent.parent.cancelable,
|
init.parent.parent.parent.cancelable,
|
||||||
init.parent.parent.view.r(),
|
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.key.clone(), init.code.clone(), init.location,
|
||||||
init.repeat, init.isComposing, init.parent.ctrlKey,
|
init.repeat, init.isComposing, init.parent.ctrlKey,
|
||||||
init.parent.altKey, init.parent.shiftKey, init.parent.metaKey,
|
init.parent.altKey, init.parent.shiftKey, init.parent.metaKey,
|
||||||
|
@ -111,13 +115,13 @@ impl KeyboardEvent {
|
||||||
Ok(event)
|
Ok(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn key_properties(key: Key, mods: KeyModifiers)
|
pub fn key_properties(ch: Option<char>, key: Key, mods: KeyModifiers)
|
||||||
-> KeyEventProperties {
|
-> KeyEventProperties {
|
||||||
KeyEventProperties {
|
KeyEventProperties {
|
||||||
key_string: key_value(key, mods),
|
key_string: key_value(ch, key, mods),
|
||||||
code: code_value(key),
|
code: code_value(key),
|
||||||
location: key_location(key),
|
location: key_location(key),
|
||||||
char_code: key_charcode(key, mods),
|
char_code: ch.map(|ch| ch as u32),
|
||||||
key_code: key_keycode(key),
|
key_code: key_keycode(key),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,11 +151,26 @@ impl KeyboardEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn logical_key(ch: Option<char>, key: Option<Key>, location: u32) -> Option<Key> {
|
||||||
|
if let Some(ch) = ch {
|
||||||
|
let key = key_from_string(&format!("{}", ch), location);
|
||||||
|
if key.is_some() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// https://w3c.github.io/uievents-key/#key-value-tables
|
// 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);
|
let shift = mods.contains(constellation_msg::SHIFT);
|
||||||
match key {
|
Cow::from(match key {
|
||||||
Key::Space => " ",
|
Key::Space => " ",
|
||||||
Key::Apostrophe if shift => "\"",
|
Key::Apostrophe if shift => "\"",
|
||||||
Key::Apostrophe => "'",
|
Key::Apostrophe => "'",
|
||||||
|
@ -321,7 +340,7 @@ pub fn key_value(key: Key, mods: KeyModifiers) -> &'static str {
|
||||||
Key::Menu => "ContextMenu",
|
Key::Menu => "ContextMenu",
|
||||||
Key::NavigateForward => "BrowserForward",
|
Key::NavigateForward => "BrowserForward",
|
||||||
Key::NavigateBackward => "BrowserBack",
|
Key::NavigateBackward => "BrowserBack",
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key_from_string(key_string: &str, location: u32) -> Option<Key> {
|
fn key_from_string(key_string: &str, location: u32) -> Option<Key> {
|
||||||
|
@ -647,16 +666,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
|
// https://w3c.github.io/uievents/#legacy-key-models
|
||||||
fn key_keycode(key: Key) -> u32 {
|
fn key_keycode(key: Key) -> u32 {
|
||||||
match key {
|
match key {
|
||||||
|
@ -739,7 +748,7 @@ fn key_keycode(key: Key) -> u32 {
|
||||||
|
|
||||||
#[derive(HeapSizeOf)]
|
#[derive(HeapSizeOf)]
|
||||||
pub struct KeyEventProperties {
|
pub struct KeyEventProperties {
|
||||||
pub key_string: &'static str,
|
pub key_string: Cow<'static, str>,
|
||||||
pub code: &'static str,
|
pub code: &'static str,
|
||||||
pub location: u32,
|
pub location: u32,
|
||||||
pub char_code: Option<u32>,
|
pub char_code: Option<u32>,
|
||||||
|
|
|
@ -1937,12 +1937,12 @@ impl ScriptThread {
|
||||||
document.r().handle_touchpad_pressure_event(self.js_runtime.rt(), point, pressure, phase);
|
document.r().handle_touchpad_pressure_event(self.js_runtime.rt(), point, pressure, phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent(key, state, modifiers) => {
|
KeyEvent(key, state, modifiers, ch) => {
|
||||||
let document = match self.root_browsing_context().find(pipeline_id) {
|
let document = match self.root_browsing_context().find(pipeline_id) {
|
||||||
Some(browsing_context) => browsing_context.active_document(),
|
Some(browsing_context) => browsing_context.active_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(key, state, modifiers, &self.constellation_chan);
|
document.dispatch_key_event(ch, key, state, modifiers, &self.constellation_chan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use dom::bindings::str::DOMString;
|
||||||
use dom::keyboardevent::{KeyboardEvent, key_value};
|
use dom::keyboardevent::{KeyboardEvent, key_value};
|
||||||
use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER};
|
use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER};
|
||||||
use msg::constellation_msg::{Key, KeyModifiers};
|
use msg::constellation_msg::{Key, KeyModifiers};
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::{ToOwned, Borrow};
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
@ -510,7 +510,7 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||||
KeyReaction::DispatchInput
|
KeyReaction::DispatchInput
|
||||||
},
|
},
|
||||||
_ if is_printable_key(key) => {
|
_ if is_printable_key(key) => {
|
||||||
self.insert_string(key_value(key, mods));
|
self.insert_string::<&str>(key_value(None, key, mods).borrow());
|
||||||
KeyReaction::DispatchInput
|
KeyReaction::DispatchInput
|
||||||
}
|
}
|
||||||
Key::Space => {
|
Key::Space => {
|
||||||
|
|
|
@ -282,7 +282,7 @@ pub enum CompositorEvent {
|
||||||
/// Touchpad pressure event
|
/// Touchpad pressure event
|
||||||
TouchpadPressureEvent(Point2D<f32>, f32, TouchpadPressurePhase),
|
TouchpadPressureEvent(Point2D<f32>, f32, TouchpadPressurePhase),
|
||||||
/// A key was pressed.
|
/// A key was pressed.
|
||||||
KeyEvent(Key, KeyState, KeyModifiers),
|
KeyEvent(Key, KeyState, KeyModifiers, Option<char>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Touchpad pressure phase for TouchpadPressureEvent.
|
/// Touchpad pressure phase for TouchpadPressureEvent.
|
||||||
|
@ -586,7 +586,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(Key, KeyState, KeyModifiers),
|
KeyEvent(Option<char>, Key, KeyState, KeyModifiers),
|
||||||
/// Request to load a page.
|
/// Request to load a page.
|
||||||
LoadUrl(PipelineId, LoadData),
|
LoadUrl(PipelineId, LoadData),
|
||||||
/// Request to navigate a frame.
|
/// Request to navigate a frame.
|
||||||
|
|
|
@ -103,7 +103,7 @@ pub enum ScriptMsg {
|
||||||
/// https://html.spec.whatwg.org/multipage/#document.title
|
/// https://html.spec.whatwg.org/multipage/#document.title
|
||||||
SetTitle(PipelineId, Option<String>),
|
SetTitle(PipelineId, Option<String>),
|
||||||
/// Send a key event
|
/// Send a key event
|
||||||
SendKeyEvent(Key, KeyState, KeyModifiers),
|
SendKeyEvent(Key, KeyState, KeyModifiers, Option<char>),
|
||||||
/// Get Window Informations size and position
|
/// Get Window Informations size and position
|
||||||
GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
|
GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
|
||||||
/// Move the window to a point
|
/// Move the window to a point
|
||||||
|
|
4
components/servo/Cargo.lock
generated
4
components/servo/Cargo.lock
generated
|
@ -146,7 +146,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "bincode"
|
||||||
version = "0.5.7"
|
version = "0.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1061,7 +1061,7 @@ name = "ipc-channel"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
source = "git+https://github.com/servo/ipc-channel#48137d69955f5460da586c552de275ecdc3f4efe"
|
source = "git+https://github.com/servo/ipc-channel#48137d69955f5460da586c552de275ecdc3f4efe"
|
||||||
dependencies = [
|
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)",
|
"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)",
|
"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)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
4
ports/cef/Cargo.lock
generated
4
ports/cef/Cargo.lock
generated
|
@ -120,7 +120,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "bincode"
|
||||||
version = "0.5.7"
|
version = "0.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -970,7 +970,7 @@ name = "ipc-channel"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
source = "git+https://github.com/servo/ipc-channel#48137d69955f5460da586c552de275ecdc3f4efe"
|
source = "git+https://github.com/servo/ipc-channel#48137d69955f5460da586c552de275ecdc3f4efe"
|
||||||
dependencies = [
|
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)",
|
"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)",
|
"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)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
4
ports/geckolib/Cargo.lock
generated
4
ports/geckolib/Cargo.lock
generated
|
@ -72,7 +72,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "bincode"
|
||||||
version = "0.5.7"
|
version = "0.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -254,7 +254,7 @@ name = "ipc-channel"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
source = "git+https://github.com/servo/ipc-channel#8411eeabf3a712006ad1b47637b2d8fe71177f85"
|
source = "git+https://github.com/servo/ipc-channel#8411eeabf3a712006ad1b47637b2d8fe71177f85"
|
||||||
dependencies = [
|
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)",
|
"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)",
|
"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)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -14,10 +14,10 @@ use euclid::{Size2D, Point2D};
|
||||||
#[cfg(target_os = "windows")] use gdi32;
|
#[cfg(target_os = "windows")] use gdi32;
|
||||||
use gleam::gl;
|
use gleam::gl;
|
||||||
use glutin;
|
use glutin;
|
||||||
use glutin::TouchPhase;
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use glutin::os::macos::{ActivationPolicy, WindowBuilderExt};
|
use glutin::os::macos::{ActivationPolicy, WindowBuilderExt};
|
||||||
use glutin::{Api, ElementState, Event, GlRequest, MouseButton, VirtualKeyCode, MouseScrollDelta};
|
use glutin::{Api, ElementState, Event, GlRequest, MouseButton, VirtualKeyCode, MouseScrollDelta};
|
||||||
|
use glutin::{ScanCode, TouchPhase};
|
||||||
use layers::geometry::DevicePixel;
|
use layers::geometry::DevicePixel;
|
||||||
use layers::platform::surface::NativeDisplay;
|
use layers::platform::surface::NativeDisplay;
|
||||||
use msg::constellation_msg::{KeyState, NONE, CONTROL, SHIFT, ALT, SUPER};
|
use msg::constellation_msg::{KeyState, NONE, CONTROL, SHIFT, ALT, SUPER};
|
||||||
|
@ -99,6 +99,12 @@ pub struct Window {
|
||||||
mouse_pos: Cell<Point2D<i32>>,
|
mouse_pos: Cell<Point2D<i32>>,
|
||||||
key_modifiers: Cell<KeyModifiers>,
|
key_modifiers: Cell<KeyModifiers>,
|
||||||
current_url: RefCell<Option<Url>>,
|
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"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
@ -175,6 +181,9 @@ impl Window {
|
||||||
mouse_pos: Cell::new(Point2D::new(0, 0)),
|
mouse_pos: Cell::new(Point2D::new(0, 0)),
|
||||||
key_modifiers: Cell::new(KeyModifiers::empty()),
|
key_modifiers: Cell::new(KeyModifiers::empty()),
|
||||||
current_url: RefCell::new(None),
|
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);
|
gl::clear_color(0.6, 0.6, 0.6, 1.0);
|
||||||
|
@ -232,7 +241,14 @@ impl Window {
|
||||||
|
|
||||||
fn handle_window_event(&self, event: glutin::Event) -> bool {
|
fn handle_window_event(&self, event: glutin::Event) -> bool {
|
||||||
match event {
|
match event {
|
||||||
Event::KeyboardInput(element_state, _scan_code, Some(virtual_key_code)) => {
|
Event::ReceivedCharacter(ch) => {
|
||||||
|
// Glutin ends up providing non-printable characters like escape and backspace,
|
||||||
|
// which is no good for trying to figure out the logical key that was pressed.
|
||||||
|
if !ch.is_control() && ch.len_utf8() == 1 {
|
||||||
|
self.pending_key_event_char.set(Some(ch));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::KeyboardInput(element_state, scan_code, Some(virtual_key_code)) => {
|
||||||
match virtual_key_code {
|
match virtual_key_code {
|
||||||
VirtualKeyCode::LControl => self.toggle_modifier(LEFT_CONTROL),
|
VirtualKeyCode::LControl => self.toggle_modifier(LEFT_CONTROL),
|
||||||
VirtualKeyCode::RControl => self.toggle_modifier(RIGHT_CONTROL),
|
VirtualKeyCode::RControl => self.toggle_modifier(RIGHT_CONTROL),
|
||||||
|
@ -245,13 +261,37 @@ 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();
|
||||||
|
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) {
|
if let Ok(key) = Window::glutin_key_to_script_key(virtual_key_code) {
|
||||||
let state = match element_state {
|
let state = match element_state {
|
||||||
ElementState::Pressed => KeyState::Pressed,
|
ElementState::Pressed => KeyState::Pressed,
|
||||||
ElementState::Released => KeyState::Released,
|
ElementState::Released => KeyState::Released,
|
||||||
};
|
};
|
||||||
let modifiers = Window::glutin_mods_to_script_mods(self.key_modifiers.get());
|
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) => {
|
Event::KeyboardInput(_, _, None) => {
|
||||||
|
@ -794,48 +834,47 @@ impl WindowMethods for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to handle keyboard events.
|
/// Helper function to handle keyboard events.
|
||||||
fn handle_key(&self, key: Key, mods: constellation_msg::KeyModifiers) {
|
fn handle_key(&self, ch: Option<char>, key: Key, mods: constellation_msg::KeyModifiers) {
|
||||||
match (mods, key) {
|
match (mods, ch, key) {
|
||||||
(_, Key::Equal) => {
|
(_, Some('+'), _) => {
|
||||||
if mods & !SHIFT == CMD_OR_CONTROL {
|
if mods & !SHIFT == CMD_OR_CONTROL {
|
||||||
self.event_queue.borrow_mut().push(WindowEvent::Zoom(1.1));
|
self.event_queue.borrow_mut().push(WindowEvent::Zoom(1.1));
|
||||||
} else if mods & !SHIFT == CMD_OR_CONTROL | ALT {
|
} else if mods & !SHIFT == CMD_OR_CONTROL | ALT {
|
||||||
self.event_queue.borrow_mut().push(WindowEvent::PinchZoom(1.1));
|
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));
|
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));
|
self.event_queue.borrow_mut().push(WindowEvent::PinchZoom(1.0 / 1.1));
|
||||||
}
|
}
|
||||||
(CMD_OR_CONTROL, Key::Num0) |
|
(CMD_OR_CONTROL, Some('0'), _) => {
|
||||||
(CMD_OR_CONTROL, Key::Kp0) => {
|
|
||||||
self.event_queue.borrow_mut().push(WindowEvent::ResetZoom);
|
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));
|
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));
|
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() {
|
if let Some(true) = PREFS.get("shell.builtin-key-shortcuts.enabled").as_boolean() {
|
||||||
self.event_queue.borrow_mut().push(WindowEvent::Quit);
|
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));
|
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));
|
self.event_queue.borrow_mut().push(WindowEvent::Navigation(WindowNavigateMsg::Back));
|
||||||
}
|
}
|
||||||
|
|
||||||
(NONE, Key::PageDown) |
|
(NONE, None, Key::PageDown) |
|
||||||
(NONE, Key::Space) => {
|
(NONE, Some(' '), _) => {
|
||||||
self.scroll_window(0.0,
|
self.scroll_window(0.0,
|
||||||
-self.framebuffer_size()
|
-self.framebuffer_size()
|
||||||
.as_f32()
|
.as_f32()
|
||||||
|
@ -843,8 +882,8 @@ impl WindowMethods for Window {
|
||||||
.height + 2.0 * LINE_HEIGHT,
|
.height + 2.0 * LINE_HEIGHT,
|
||||||
TouchEventType::Move);
|
TouchEventType::Move);
|
||||||
}
|
}
|
||||||
(NONE, Key::PageUp) |
|
(NONE, None, Key::PageUp) |
|
||||||
(SHIFT, Key::Space) => {
|
(SHIFT, Some(' '), _) => {
|
||||||
self.scroll_window(0.0,
|
self.scroll_window(0.0,
|
||||||
self.framebuffer_size()
|
self.framebuffer_size()
|
||||||
.as_f32()
|
.as_f32()
|
||||||
|
@ -852,19 +891,19 @@ impl WindowMethods for Window {
|
||||||
.height - 2.0 * LINE_HEIGHT,
|
.height - 2.0 * LINE_HEIGHT,
|
||||||
TouchEventType::Move);
|
TouchEventType::Move);
|
||||||
}
|
}
|
||||||
(NONE, Key::Up) => {
|
(NONE, None, Key::Up) => {
|
||||||
self.scroll_window(0.0, 3.0 * LINE_HEIGHT, TouchEventType::Move);
|
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);
|
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);
|
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);
|
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() {
|
if let Some(true) = PREFS.get("shell.builtin-key-shortcuts.enabled").as_boolean() {
|
||||||
self.event_queue.borrow_mut().push(WindowEvent::Reload);
|
self.event_queue.borrow_mut().push(WindowEvent::Reload);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue