Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support non-QWERTY keyboards, take 2 #11955

Closed
wants to merge 2 commits into from
Closed
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Next

Associate logical and physical keypresses together to support non-QWE…

…RTY keyboards.
  • Loading branch information
jdm authored and nox committed Jun 30, 2016
commit da776d918842d5da19b65693f8e1861f028cca37
@@ -691,9 +691,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);
}
}

@@ -1330,8 +1330,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 => {
@@ -1840,8 +1840,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);
}
@@ -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.
@@ -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;
@@ -48,6 +48,7 @@ use script_traits::{IFrameLoadInfo, IFrameSandboxState, TimerEventRequest};
use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
use script_traits::{MozBrowserEvent, MozBrowserErrorType};
use std::borrow::ToOwned;
use std::char;
use std::collections::HashMap;
use std::io::Error as IOError;
use std::marker::PhantomData;
@@ -575,9 +576,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;
@@ -804,8 +805,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(key, key_state, key_modifiers, ch) => {
self.compositor_proxy.send(ToCompositorMsg::KeyEvent(ch, key, key_state, key_modifiers))
}

FromScriptMsg::TouchEventProcessed(result) => {
@@ -1397,7 +1398,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.
@@ -1408,7 +1409,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(key, state, mods, ch);
let msg = ConstellationControlMsg::SendEvent(pipeline_id, event);
let result = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => pipeline.script_chan.send(msg),
@@ -1419,7 +1420,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);
}
}
@@ -1630,7 +1631,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(key, state, mods, None);
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);
@@ -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)
@@ -1047,6 +1047,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,
@@ -1073,16 +1074,17 @@ 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,
true,
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,
@@ -1106,6 +1108,7 @@ impl Document {
true,
Some(&self.window),
0,
ch,
Some(key),
DOMString::from(props.key_string),
DOMString::from(props.code),
@@ -1125,7 +1128,7 @@ impl Document {
}

if !prevented {
constellation.send(ConstellationMsg::SendKeyEvent(key, state, modifiers)).unwrap();
constellation.send(ConstellationMsg::SendKeyEvent(key, state, modifiers, ch)).unwrap();
}

// This behavior is unspecced
@@ -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);
@@ -69,6 +70,7 @@ impl KeyboardEvent {
cancelable: bool,
view: Option<&Window>,
_detail: i32,
ch: Option<char>,
key: Option<Key>,
key_string: DOMString,
code: DOMString,
@@ -84,7 +86,7 @@ impl KeyboardEvent {
let ev = KeyboardEvent::new_uninitialized(window);
ev.InitKeyboardEvent(type_, canBubble, cancelable, view, key_string, location,
DOMString::new(), repeat, DOMString::new());
ev.key.set(key);
ev.key.set(logical_key(ch, key, location));
*ev.code.borrow_mut() = code;
ev.ctrl.set(ctrlKey);
ev.alt.set(altKey);
@@ -103,21 +105,23 @@ 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,
None, 0);
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),
}
}
@@ -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
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 +340,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 +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
fn key_keycode(key: Key) -> u32 {
match key {
@@ -739,7 +748,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>,
@@ -1937,12 +1937,12 @@ impl ScriptThread {
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) {
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);
}
}
}
@@ -9,7 +9,7 @@ use dom::bindings::str::DOMString;
use dom::keyboardevent::{KeyboardEvent, key_value};
use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER};
use msg::constellation_msg::{Key, KeyModifiers};
use std::borrow::ToOwned;
use std::borrow::{ToOwned, Borrow};
use std::cmp::{max, min};
use std::default::Default;
use std::ops::Range;
@@ -510,7 +510,7 @@ impl<T: ClipboardProvider> TextInput<T> {
KeyReaction::DispatchInput
},
_ if is_printable_key(key) => {
self.insert_string(key_value(key, mods));
self.insert_string::<&str>(key_value(None, key, mods).borrow());
KeyReaction::DispatchInput
}
Key::Space => {
@@ -275,7 +275,7 @@ pub enum CompositorEvent {
/// Touchpad pressure event
TouchpadPressureEvent(Point2D<f32>, f32, TouchpadPressurePhase),
/// A key was pressed.
KeyEvent(Key, KeyState, KeyModifiers),
KeyEvent(Key, KeyState, KeyModifiers, Option<char>),
}

/// Touchpad pressure phase for TouchpadPressureEvent.
@@ -544,7 +544,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.
@@ -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(Key, KeyState, KeyModifiers, Option<char>),
/// Get Window Informations size and position
GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
/// Move the window to a point

Some generated files are not rendered by default. Learn more.

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.