mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Auto merge of #11950 - jdm:keylayout2, r=emilio
Support non-QWERTY keyboards Using the ReceivedCharacter event from glutin, we can obtain the actual key characters that the user is pressing and releasing. This gets passed to the script thread along with the physical key data, since KeyboardEvent needs both pieces of information, where they get merged into a single logical key that gets processed by clients like TextInput without any special changes. Tested by switching my macbook keyboard to dvorak and looking at the output of keypress/keyup/keydown event listeners, as well as playing with tests/html/textarea.html. Non-content keybindings like reload work as expected, too - the remapped keybinding triggers the reload action. --- - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #4144 - [X] These changes do not require tests because I can't think of a way to test remapped keyboard input Fixes #11991. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/11950) <!-- Reviewable:end -->
This commit is contained in:
commit
68fb9ebc41
19 changed files with 233 additions and 122 deletions
|
@ -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)
|
||||
|
|
|
@ -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>);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue