aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/textinput.rs
diff options
context:
space:
mode:
authorPyfisch <pyfisch@gmail.com>2018-10-06 17:35:45 +0200
committerPyfisch <pyfisch@gmail.com>2018-10-07 22:39:00 +0200
commit0ccaa7e1a9e9bf9472d869576019b9cda350ad87 (patch)
tree812a25be7dcad507d183b25d683a9ebaec3d493c /components/script/textinput.rs
parent76ddbe4d7afd48b83b23f3fd0cff47b214a0a290 (diff)
downloadservo-0ccaa7e1a9e9bf9472d869576019b9cda350ad87.tar.gz
servo-0ccaa7e1a9e9bf9472d869576019b9cda350ad87.zip
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
Diffstat (limited to 'components/script/textinput.rs')
-rw-r--r--components/script/textinput.rs174
1 files changed, 76 insertions, 98 deletions
diff --git a/components/script/textinput.rs b/components/script/textinput.rs
index 7f462ba43fb..dfa469c1a08 100644
--- a/components/script/textinput.rs
+++ b/components/script/textinput.rs
@@ -7,7 +7,7 @@
use clipboard_provider::ClipboardProvider;
use dom::bindings::str::DOMString;
use dom::keyboardevent::KeyboardEvent;
-use msg::constellation_msg::{Key, KeyModifiers};
+use keyboard_types::{Key, KeyState, Modifiers, ShortcutMatcher};
use std::borrow::ToOwned;
use std::cmp::{max, min};
use std::default::Default;
@@ -130,17 +130,11 @@ pub enum Direction {
Backward,
}
-/// Was the keyboard event accompanied by the standard control modifier,
-/// i.e. cmd on Mac OS or ctrl on other platforms.
+// Some shortcuts use Cmd on Mac and Control on other systems.
#[cfg(target_os = "macos")]
-fn is_control_key(mods: KeyModifiers) -> bool {
- mods.contains(KeyModifiers::SUPER) && !mods.contains(KeyModifiers::CONTROL | KeyModifiers::ALT)
-}
-
+pub const CMD_OR_CONTROL: Modifiers = Modifiers::META;
#[cfg(not(target_os = "macos"))]
-fn is_control_key(mods: KeyModifiers) -> bool {
- mods.contains(KeyModifiers::CONTROL) && !mods.contains(KeyModifiers::SUPER | KeyModifiers::ALT)
-}
+pub const CMD_OR_CONTROL: Modifiers = Modifiers::CONTROL;
/// 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.
pub fn handle_keydown(&mut self, event: &KeyboardEvent) -> KeyReaction {
- if let Some(key) = event.get_key() {
- self.handle_keydown_aux(event.printable(), key, event.get_key_modifiers())
- } else {
- KeyReaction::Nothing
- }
+ let key = event.key();
+ let mods = event.modifiers();
+ self.handle_keydown_aux(key, mods, cfg!(target_os = "macos"))
}
+ // This function exists for easy unit testing.
+ // To test Mac OS shortcuts on other systems a flag is passed.
pub fn handle_keydown_aux(
&mut self,
- printable: Option<char>,
key: Key,
- mods: KeyModifiers,
+ mut mods: Modifiers,
+ macos: bool,
) -> KeyReaction {
- let maybe_select = if mods.contains(KeyModifiers::SHIFT) {
+ let maybe_select = if mods.contains(Modifiers::SHIFT) {
Selection::Selected
} else {
Selection::NotSelected
};
-
- match (printable, key) {
- (_, Key::B) if mods.contains(KeyModifiers::CONTROL | KeyModifiers::ALT) => {
+ mods.remove(Modifiers::SHIFT);
+ ShortcutMatcher::new(KeyState::Down, key.clone(), mods)
+ .shortcut(Modifiers::CONTROL | Modifiers::ALT, 'B', || {
self.adjust_horizontal_by_word(Direction::Backward, maybe_select);
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);
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);
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);
KeyReaction::RedrawSelection
- },
- #[cfg(target_os = "macos")]
- (None, Key::A) if mods == KeyModifiers::CONTROL =>
- {
+ })
+ .optional_shortcut(macos, Modifiers::CONTROL, 'A', || {
self.adjust_horizontal_to_line_end(Direction::Backward, maybe_select);
KeyReaction::RedrawSelection
- }
- #[cfg(target_os = "macos")]
- (None, Key::E) if mods == KeyModifiers::CONTROL =>
- {
+ })
+ .optional_shortcut(macos, Modifiers::CONTROL, 'E', || {
self.adjust_horizontal_to_line_end(Direction::Forward, maybe_select);
KeyReaction::RedrawSelection
- }
- (_, Key::A) if is_control_key(mods) => {
+ })
+ .shortcut(CMD_OR_CONTROL, 'A', || {
self.select_all();
KeyReaction::RedrawSelection
- },
- (_, Key::C) if is_control_key(mods) => {
+ })
+ .shortcut(CMD_OR_CONTROL, 'C', || {
if let Some(text) = self.get_selection_text() {
self.clipboard_provider.set_clipboard_contents(text);
}
KeyReaction::DispatchInput
- },
- (_, Key::V) if is_control_key(mods) => {
+ })
+ .shortcut(CMD_OR_CONTROL, 'V', || {
let contents = self.clipboard_provider.clipboard_contents();
self.insert_string(contents);
KeyReaction::DispatchInput
- },
- (Some(c), _) => {
- self.insert_char(c);
- KeyReaction::DispatchInput
- },
- (None, Key::Delete) => {
+ })
+ .shortcut(Modifiers::empty(), Key::Delete, || {
self.delete_char(Direction::Forward);
KeyReaction::DispatchInput
- },
- (None, Key::Backspace) => {
+ })
+ .shortcut(Modifiers::empty(), Key::Backspace, || {
self.delete_char(Direction::Backward);
KeyReaction::DispatchInput
- },
- #[cfg(target_os = "macos")]
- (None, Key::Left) if mods.contains(KeyModifiers::SUPER) =>
- {
+ })
+ .optional_shortcut(macos, Modifiers::META, Key::ArrowLeft, || {
self.adjust_horizontal_to_line_end(Direction::Backward, maybe_select);
KeyReaction::RedrawSelection
- }
- #[cfg(target_os = "macos")]
- (None, Key::Right) if mods.contains(KeyModifiers::SUPER) =>
- {
+ })
+ .optional_shortcut(macos, Modifiers::META, Key::ArrowRight, || {
self.adjust_horizontal_to_line_end(Direction::Forward, maybe_select);
KeyReaction::RedrawSelection
- }
- #[cfg(target_os = "macos")]
- (None, Key::Up) if mods.contains(KeyModifiers::SUPER) =>
- {
+ })
+ .optional_shortcut(macos, Modifiers::META, Key::ArrowUp, || {
self.adjust_horizontal_to_limit(Direction::Backward, maybe_select);
KeyReaction::RedrawSelection
- }
- #[cfg(target_os = "macos")]
- (None, Key::Down) if mods.contains(KeyModifiers::SUPER) =>
- {
+ })
+ .optional_shortcut(macos, Modifiers::META, Key::ArrowDown, || {
self.adjust_horizontal_to_limit(Direction::Forward, maybe_select);
KeyReaction::RedrawSelection
- }
- (None, Key::Left) if mods.contains(KeyModifiers::ALT) => {
+ })
+ .shortcut(Modifiers::ALT, Key::ArrowLeft, || {
self.adjust_horizontal_by_word(Direction::Backward, maybe_select);
KeyReaction::RedrawSelection
- },
- (None, Key::Right) if mods.contains(KeyModifiers::ALT) => {
+ })
+ .shortcut(Modifiers::ALT, Key::ArrowRight, || {
self.adjust_horizontal_by_word(Direction::Forward, maybe_select);
KeyReaction::RedrawSelection
- },
- (None, Key::Left) => {
+ })
+ .shortcut(Modifiers::empty(), Key::ArrowLeft, || {
self.adjust_horizontal_by_one(Direction::Backward, maybe_select);
KeyReaction::RedrawSelection
- },
- (None, Key::Right) => {
+ })
+ .shortcut(Modifiers::empty(), Key::ArrowRight, || {
self.adjust_horizontal_by_one(Direction::Forward, maybe_select);
KeyReaction::RedrawSelection
- },
- (None, Key::Up) => {
+ })
+ .shortcut(Modifiers::empty(), Key::ArrowUp, || {
self.adjust_vertical(-1, maybe_select);
KeyReaction::RedrawSelection
- },
- (None, Key::Down) => {
+ })
+ .shortcut(Modifiers::empty(), Key::ArrowDown, || {
self.adjust_vertical(1, maybe_select);
KeyReaction::RedrawSelection
- },
- (None, Key::Enter) | (None, Key::KpEnter) => self.handle_return(),
- (None, Key::Home) => {
- #[cfg(not(target_os = "macos"))]
- {
- self.edit_point.index = 0;
- }
+ })
+ .shortcut(Modifiers::empty(), Key::Enter, || self.handle_return())
+ .optional_shortcut(macos, Modifiers::empty(), Key::Home, || {
+ self.edit_point.index = 0;
KeyReaction::RedrawSelection
- },
- (None, Key::End) => {
- #[cfg(not(target_os = "macos"))]
- {
- self.edit_point.index = self.current_line_length();
- self.assert_ok_selection();
- }
+ })
+ .optional_shortcut(macos, Modifiers::empty(), Key::End, || {
+ self.edit_point.index = self.current_line_length();
+ self.assert_ok_selection();
KeyReaction::RedrawSelection
- },
- (None, Key::PageUp) => {
+ })
+ .shortcut(Modifiers::empty(), Key::PageUp, || {
self.adjust_vertical(-28, maybe_select);
KeyReaction::RedrawSelection
- },
- (None, Key::PageDown) => {
+ })
+ .shortcut(Modifiers::empty(), Key::PageDown, || {
self.adjust_vertical(28, maybe_select);
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.