mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Add single-line text input with no visible cursor.
This commit is contained in:
parent
84bc17e7ad
commit
80764f65e3
8 changed files with 776 additions and 63 deletions
|
@ -58,6 +58,7 @@ pub enum KeyState {
|
||||||
}
|
}
|
||||||
|
|
||||||
//N.B. Straight up copied from glfw-rs
|
//N.B. Straight up copied from glfw-rs
|
||||||
|
#[deriving(Show)]
|
||||||
pub enum Key {
|
pub enum Key {
|
||||||
KeySpace,
|
KeySpace,
|
||||||
KeyApostrophe,
|
KeyApostrophe,
|
||||||
|
@ -184,10 +185,10 @@ pub enum Key {
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
flags KeyModifiers: u8 {
|
flags KeyModifiers: u8 {
|
||||||
const Shift = 0x01,
|
const SHIFT = 0x01,
|
||||||
const Control = 0x02,
|
const CONTROL = 0x02,
|
||||||
const Alt = 0x04,
|
const ALT = 0x04,
|
||||||
const Super = 0x08,
|
const SUPER = 0x08,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ use dom::document::{Document, DocumentHelpers, LayoutDocumentHelpers};
|
||||||
use dom::domtokenlist::DOMTokenList;
|
use dom::domtokenlist::DOMTokenList;
|
||||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||||
use dom::htmlcollection::HTMLCollection;
|
use dom::htmlcollection::HTMLCollection;
|
||||||
use dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
|
use dom::htmlinputelement::{HTMLInputElement, RawLayoutHTMLInputElementHelpers};
|
||||||
use dom::htmlserializer::serialize;
|
use dom::htmlserializer::serialize;
|
||||||
use dom::htmltablecellelement::{HTMLTableCellElement, HTMLTableCellElementHelpers};
|
use dom::htmltablecellelement::{HTMLTableCellElement, HTMLTableCellElementHelpers};
|
||||||
use dom::node::{ElementNodeTypeId, Node, NodeHelpers, NodeIterator, document_from_node};
|
use dom::node::{ElementNodeTypeId, Node, NodeHelpers, NodeIterator, document_from_node};
|
||||||
|
@ -231,17 +231,24 @@ pub trait RawLayoutElementHelpers {
|
||||||
-> Option<i32>;
|
-> Option<i32>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[allow(unrooted_must_root)]
|
||||||
|
unsafe fn get_attr_for_layout<'a>(elem: &'a Element, namespace: &Namespace, name: &Atom) -> Option<&'a JS<Attr>> {
|
||||||
|
// cast to point to T in RefCell<T> directly
|
||||||
|
let attrs: *const Vec<JS<Attr>> = mem::transmute(&elem.attrs);
|
||||||
|
(*attrs).iter().find(|attr: & &JS<Attr>| {
|
||||||
|
let attr = attr.unsafe_get();
|
||||||
|
*name == (*attr).local_name_atom_forever() &&
|
||||||
|
(*attr).namespace() == namespace
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
impl RawLayoutElementHelpers for Element {
|
impl RawLayoutElementHelpers for Element {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
unsafe fn get_attr_val_for_layout<'a>(&'a self, namespace: &Namespace, name: &Atom)
|
unsafe fn get_attr_val_for_layout<'a>(&'a self, namespace: &Namespace, name: &Atom)
|
||||||
-> Option<&'a str> {
|
-> Option<&'a str> {
|
||||||
let attrs = self.attrs.borrow_for_layout();
|
get_attr_for_layout(self, namespace, name).map(|attr| {
|
||||||
(*attrs).iter().find(|attr: & &JS<Attr>| {
|
|
||||||
let attr = attr.unsafe_get();
|
|
||||||
*name == (*attr).local_name_atom_forever() &&
|
|
||||||
(*attr).namespace() == namespace
|
|
||||||
}).map(|attr| {
|
|
||||||
let attr = attr.unsafe_get();
|
let attr = attr.unsafe_get();
|
||||||
(*attr).value_ref_forever()
|
(*attr).value_ref_forever()
|
||||||
})
|
})
|
||||||
|
@ -337,6 +344,7 @@ impl RawLayoutElementHelpers for Element {
|
||||||
|
|
||||||
pub trait LayoutElementHelpers {
|
pub trait LayoutElementHelpers {
|
||||||
unsafe fn html_element_in_html_document_for_layout(&self) -> bool;
|
unsafe fn html_element_in_html_document_for_layout(&self) -> bool;
|
||||||
|
unsafe fn has_attr_for_layout(&self, namespace: &Namespace, name: &Atom) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutElementHelpers for JS<Element> {
|
impl LayoutElementHelpers for JS<Element> {
|
||||||
|
@ -349,6 +357,10 @@ impl LayoutElementHelpers for JS<Element> {
|
||||||
let node: JS<Node> = self.transmute_copy();
|
let node: JS<Node> = self.transmute_copy();
|
||||||
node.owner_doc_for_layout().is_html_document_for_layout()
|
node.owner_doc_for_layout().is_html_document_for_layout()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn has_attr_for_layout(&self, namespace: &Namespace, name: &Atom) -> bool {
|
||||||
|
get_attr_for_layout(&*self.unsafe_get(), namespace, name).is_some()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ElementHelpers<'a> {
|
pub trait ElementHelpers<'a> {
|
||||||
|
|
|
@ -13,16 +13,20 @@ use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementM
|
||||||
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
|
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
|
||||||
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, HTMLFormElementCast, HTMLInputElementCast, NodeCast};
|
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, HTMLFormElementCast, HTMLInputElementCast, NodeCast};
|
||||||
use dom::bindings::codegen::InheritTypes::{HTMLInputElementDerived, HTMLFieldSetElementDerived};
|
use dom::bindings::codegen::InheritTypes::{HTMLInputElementDerived, HTMLFieldSetElementDerived};
|
||||||
|
use dom::bindings::codegen::InheritTypes::KeyboardEventCast;
|
||||||
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, ResultRootable};
|
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, ResultRootable};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::document::{Document, DocumentHelpers};
|
use dom::document::{Document, DocumentHelpers};
|
||||||
use dom::element::{AttributeHandlers, Element, HTMLInputElementTypeId};
|
use dom::element::{AttributeHandlers, Element, HTMLInputElementTypeId, LayoutElementHelpers};
|
||||||
|
use dom::element::RawLayoutElementHelpers;
|
||||||
use dom::event::Event;
|
use dom::event::Event;
|
||||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
|
use dom::keyboardevent::KeyboardEvent;
|
||||||
use dom::htmlformelement::{InputElement, FormOwner, HTMLFormElement, HTMLFormElementHelpers, NotFromFormSubmitMethod};
|
use dom::htmlformelement::{InputElement, FormOwner, HTMLFormElement, HTMLFormElementHelpers, NotFromFormSubmitMethod};
|
||||||
use dom::node::{DisabledStateHelpers, Node, NodeHelpers, ElementNodeTypeId, document_from_node, window_from_node};
|
use dom::node::{DisabledStateHelpers, Node, NodeHelpers, ElementNodeTypeId, document_from_node, window_from_node};
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
|
use textinput::{TextInput, TriggerDefaultAction, DispatchInput, Nothing};
|
||||||
|
|
||||||
use servo_util::str::DOMString;
|
use servo_util::str::DOMString;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
|
@ -51,9 +55,8 @@ pub struct HTMLInputElement {
|
||||||
htmlelement: HTMLElement,
|
htmlelement: HTMLElement,
|
||||||
input_type: Cell<InputType>,
|
input_type: Cell<InputType>,
|
||||||
checked: Cell<bool>,
|
checked: Cell<bool>,
|
||||||
uncommitted_value: DOMRefCell<Option<String>>,
|
|
||||||
value: DOMRefCell<Option<String>>,
|
|
||||||
size: Cell<u32>,
|
size: Cell<u32>,
|
||||||
|
textinput: DOMRefCell<TextInput>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLInputElementDerived for EventTarget {
|
impl HTMLInputElementDerived for EventTarget {
|
||||||
|
@ -70,9 +73,8 @@ impl HTMLInputElement {
|
||||||
htmlelement: HTMLElement::new_inherited(HTMLInputElementTypeId, localName, prefix, document),
|
htmlelement: HTMLElement::new_inherited(HTMLInputElementTypeId, localName, prefix, document),
|
||||||
input_type: Cell::new(InputText),
|
input_type: Cell::new(InputText),
|
||||||
checked: Cell::new(false),
|
checked: Cell::new(false),
|
||||||
uncommitted_value: DOMRefCell::new(None),
|
|
||||||
value: DOMRefCell::new(None),
|
|
||||||
size: Cell::new(DEFAULT_INPUT_SIZE),
|
size: Cell::new(DEFAULT_INPUT_SIZE),
|
||||||
|
textinput: DOMRefCell::new(TextInput::new(false, "".to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,40 +86,55 @@ impl HTMLInputElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait LayoutHTMLInputElementHelpers {
|
pub trait LayoutHTMLInputElementHelpers {
|
||||||
unsafe fn get_value_for_layout(&self) -> String;
|
unsafe fn get_value_for_layout(self) -> String;
|
||||||
|
unsafe fn get_size_for_layout(self) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RawLayoutHTMLInputElementHelpers {
|
||||||
unsafe fn get_size_for_layout(&self) -> u32;
|
unsafe fn get_size_for_layout(&self) -> u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutHTMLInputElementHelpers for HTMLInputElement {
|
impl LayoutHTMLInputElementHelpers for JS<HTMLInputElement> {
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
unsafe fn get_value_for_layout(&self) -> String {
|
unsafe fn get_value_for_layout(self) -> String {
|
||||||
match self.input_type.get() {
|
unsafe fn get_raw_textinput_value(input: JS<HTMLInputElement>) -> Option<String> {
|
||||||
|
let elem: JS<Element> = input.transmute_copy();
|
||||||
|
if !elem.has_attr_for_layout(&ns!(""), &atom!("value")) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some((*input.unsafe_get()).textinput.borrow_for_layout().get_content())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_raw_attr_value(input: JS<HTMLInputElement>) -> Option<String> {
|
||||||
|
let elem: JS<Element> = input.transmute_copy();
|
||||||
|
(*elem.unsafe_get()).get_attr_val_for_layout(&ns!(""), &atom!("value"))
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
match (*self.unsafe_get()).input_type.get() {
|
||||||
InputCheckbox | InputRadio => "".to_string(),
|
InputCheckbox | InputRadio => "".to_string(),
|
||||||
InputFile | InputImage => "".to_string(),
|
InputFile | InputImage => "".to_string(),
|
||||||
InputButton(ref default) => self.value.borrow_for_layout().clone()
|
InputButton(ref default) => get_raw_attr_value(self)
|
||||||
.or_else(|| default.map(|v| v.to_string()))
|
.or_else(|| default.map(|v| v.to_string()))
|
||||||
.unwrap_or_else(|| "".to_string()),
|
.unwrap_or_else(|| "".to_string()),
|
||||||
InputPassword => {
|
InputPassword => {
|
||||||
let raw = self.value.borrow_for_layout().clone().unwrap_or_else(|| "".to_string());
|
let raw = get_raw_textinput_value(self).unwrap_or_else(|| "".to_string());
|
||||||
String::from_char(raw.len(), '*')
|
String::from_char(raw.len(), '●')
|
||||||
}
|
}
|
||||||
_ => self.value.borrow_for_layout().clone().unwrap_or_else(|| "".to_string()),
|
_ => get_raw_textinput_value(self).unwrap_or_else(|| "".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unrooted_must_root)]
|
#[allow(unrooted_must_root)]
|
||||||
unsafe fn get_size_for_layout(&self) -> u32 {
|
unsafe fn get_size_for_layout(self) -> u32 {
|
||||||
self.size.get()
|
(*self.unsafe_get()).get_size_for_layout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutHTMLInputElementHelpers for JS<HTMLInputElement> {
|
impl RawLayoutHTMLInputElementHelpers for HTMLInputElement {
|
||||||
unsafe fn get_value_for_layout(&self) -> String {
|
#[allow(unrooted_must_root)]
|
||||||
(*self.unsafe_get()).get_value_for_layout()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn get_size_for_layout(&self) -> u32 {
|
unsafe fn get_size_for_layout(&self) -> u32 {
|
||||||
(*self.unsafe_get()).get_size_for_layout()
|
self.size.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +173,7 @@ impl<'a> HTMLInputElementMethods for JSRef<'a, HTMLInputElement> {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/forms.html#dom-input-value
|
// https://html.spec.whatwg.org/multipage/forms.html#dom-input-value
|
||||||
fn Value(self) -> DOMString {
|
fn Value(self) -> DOMString {
|
||||||
self.value.borrow().clone().unwrap_or("".to_string())
|
self.textinput.borrow().get_content()
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/forms.html#dom-input-value
|
// https://html.spec.whatwg.org/multipage/forms.html#dom-input-value
|
||||||
|
@ -309,7 +326,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLInputElement> {
|
||||||
self.force_relayout();
|
self.force_relayout();
|
||||||
}
|
}
|
||||||
&atom!("value") => {
|
&atom!("value") => {
|
||||||
*self.value.borrow_mut() = Some(attr.value().as_slice().to_string());
|
self.textinput.borrow_mut().set_content(attr.value().as_slice().to_string());
|
||||||
self.force_relayout();
|
self.force_relayout();
|
||||||
}
|
}
|
||||||
&atom!("name") => {
|
&atom!("name") => {
|
||||||
|
@ -353,7 +370,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLInputElement> {
|
||||||
self.force_relayout();
|
self.force_relayout();
|
||||||
}
|
}
|
||||||
&atom!("value") => {
|
&atom!("value") => {
|
||||||
*self.value.borrow_mut() = None;
|
self.textinput.borrow_mut().set_content("".to_string());
|
||||||
self.force_relayout();
|
self.force_relayout();
|
||||||
}
|
}
|
||||||
&atom!("name") => {
|
&atom!("name") => {
|
||||||
|
@ -418,6 +435,18 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLInputElement> {
|
||||||
|
|
||||||
let doc = document_from_node(*self).root();
|
let doc = document_from_node(*self).root();
|
||||||
doc.request_focus(ElementCast::from_ref(*self));
|
doc.request_focus(ElementCast::from_ref(*self));
|
||||||
|
} else if "keydown" == event.Type().as_slice() && !event.DefaultPrevented() &&
|
||||||
|
(self.input_type.get() == InputText|| self.input_type.get() == InputPassword) {
|
||||||
|
let keyevent: Option<JSRef<KeyboardEvent>> = KeyboardEventCast::to_ref(event);
|
||||||
|
keyevent.map(|event| {
|
||||||
|
match self.textinput.borrow_mut().handle_keydown(event) {
|
||||||
|
TriggerDefaultAction => (),
|
||||||
|
DispatchInput => {
|
||||||
|
self.force_relayout();
|
||||||
|
}
|
||||||
|
Nothing => (),
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::bindings::codegen::Bindings::KeyboardEventBinding;
|
use dom::bindings::codegen::Bindings::KeyboardEventBinding;
|
||||||
use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
|
use dom::bindings::codegen::Bindings::KeyboardEventBinding::{KeyboardEventMethods, KeyboardEventConstants};
|
||||||
use dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods;
|
use dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods;
|
||||||
use dom::bindings::codegen::InheritTypes::{UIEventCast, KeyboardEventDerived};
|
use dom::bindings::codegen::InheritTypes::{UIEventCast, KeyboardEventDerived};
|
||||||
use dom::bindings::error::Fallible;
|
use dom::bindings::error::Fallible;
|
||||||
|
@ -111,22 +111,431 @@ impl KeyboardEvent {
|
||||||
Ok(event)
|
Ok(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn key_properties(key: constellation_msg::Key) -> KeyEventProperties {
|
pub fn key_properties(key: constellation_msg::Key, mods: constellation_msg::KeyModifiers)
|
||||||
match key {
|
-> KeyEventProperties {
|
||||||
_ => KeyEventProperties {
|
KeyEventProperties {
|
||||||
key: "".to_string(),
|
key: key_value(key, mods),
|
||||||
code: "".to_string(),
|
code: code_value(key),
|
||||||
location: 0,
|
location: key_location(key),
|
||||||
char_code: None,
|
char_code: key_char_code(key, mods),
|
||||||
key_code: 0,
|
key_code: key_key_code(key),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3Events-key.html
|
||||||
|
fn key_value(key: constellation_msg::Key, mods: constellation_msg::KeyModifiers) -> &'static str {
|
||||||
|
let shift = mods.contains(constellation_msg::SHIFT);
|
||||||
|
match key {
|
||||||
|
constellation_msg::KeySpace => " ",
|
||||||
|
constellation_msg::KeyApostrophe if shift => "\"",
|
||||||
|
constellation_msg::KeyApostrophe => "'",
|
||||||
|
constellation_msg::KeyComma if shift => "<",
|
||||||
|
constellation_msg::KeyComma => ",",
|
||||||
|
constellation_msg::KeyMinus if shift => "_",
|
||||||
|
constellation_msg::KeyMinus => "-",
|
||||||
|
constellation_msg::KeyPeriod if shift => ">",
|
||||||
|
constellation_msg::KeyPeriod => ".",
|
||||||
|
constellation_msg::KeySlash if shift => "?",
|
||||||
|
constellation_msg::KeySlash => "/",
|
||||||
|
constellation_msg::Key0 if shift => ")",
|
||||||
|
constellation_msg::Key0 => "0",
|
||||||
|
constellation_msg::Key1 if shift => "!",
|
||||||
|
constellation_msg::Key1 => "1",
|
||||||
|
constellation_msg::Key2 if shift => "@",
|
||||||
|
constellation_msg::Key2 => "2",
|
||||||
|
constellation_msg::Key3 if shift => "#",
|
||||||
|
constellation_msg::Key3 => "3",
|
||||||
|
constellation_msg::Key4 if shift => "$",
|
||||||
|
constellation_msg::Key4 => "4",
|
||||||
|
constellation_msg::Key5 if shift => "%",
|
||||||
|
constellation_msg::Key5 => "5",
|
||||||
|
constellation_msg::Key6 if shift => "^",
|
||||||
|
constellation_msg::Key6 => "6",
|
||||||
|
constellation_msg::Key7 if shift => "&",
|
||||||
|
constellation_msg::Key7 => "7",
|
||||||
|
constellation_msg::Key8 if shift => "*",
|
||||||
|
constellation_msg::Key8 => "8",
|
||||||
|
constellation_msg::Key9 if shift => "(",
|
||||||
|
constellation_msg::Key9 => "9",
|
||||||
|
constellation_msg::KeySemicolon if shift => ":",
|
||||||
|
constellation_msg::KeySemicolon => ";",
|
||||||
|
constellation_msg::KeyEqual if shift => "+",
|
||||||
|
constellation_msg::KeyEqual => "=",
|
||||||
|
constellation_msg::KeyA if shift => "A",
|
||||||
|
constellation_msg::KeyA => "a",
|
||||||
|
constellation_msg::KeyB if shift => "B",
|
||||||
|
constellation_msg::KeyB => "b",
|
||||||
|
constellation_msg::KeyC if shift => "C",
|
||||||
|
constellation_msg::KeyC => "c",
|
||||||
|
constellation_msg::KeyD if shift => "D",
|
||||||
|
constellation_msg::KeyD => "d",
|
||||||
|
constellation_msg::KeyE if shift => "E",
|
||||||
|
constellation_msg::KeyE => "e",
|
||||||
|
constellation_msg::KeyF if shift => "F",
|
||||||
|
constellation_msg::KeyF => "f",
|
||||||
|
constellation_msg::KeyG if shift => "G",
|
||||||
|
constellation_msg::KeyG => "g",
|
||||||
|
constellation_msg::KeyH if shift => "H",
|
||||||
|
constellation_msg::KeyH => "h",
|
||||||
|
constellation_msg::KeyI if shift => "I",
|
||||||
|
constellation_msg::KeyI => "i",
|
||||||
|
constellation_msg::KeyJ if shift => "J",
|
||||||
|
constellation_msg::KeyJ => "j",
|
||||||
|
constellation_msg::KeyK if shift => "K",
|
||||||
|
constellation_msg::KeyK => "k",
|
||||||
|
constellation_msg::KeyL if shift => "L",
|
||||||
|
constellation_msg::KeyL => "l",
|
||||||
|
constellation_msg::KeyM if shift => "M",
|
||||||
|
constellation_msg::KeyM => "m",
|
||||||
|
constellation_msg::KeyN if shift => "N",
|
||||||
|
constellation_msg::KeyN => "n",
|
||||||
|
constellation_msg::KeyO if shift => "O",
|
||||||
|
constellation_msg::KeyO => "o",
|
||||||
|
constellation_msg::KeyP if shift => "P",
|
||||||
|
constellation_msg::KeyP => "p",
|
||||||
|
constellation_msg::KeyQ if shift => "Q",
|
||||||
|
constellation_msg::KeyQ => "q",
|
||||||
|
constellation_msg::KeyR if shift => "R",
|
||||||
|
constellation_msg::KeyR => "r",
|
||||||
|
constellation_msg::KeyS if shift => "S",
|
||||||
|
constellation_msg::KeyS => "s",
|
||||||
|
constellation_msg::KeyT if shift => "T",
|
||||||
|
constellation_msg::KeyT => "t",
|
||||||
|
constellation_msg::KeyU if shift => "U",
|
||||||
|
constellation_msg::KeyU => "u",
|
||||||
|
constellation_msg::KeyV if shift => "V",
|
||||||
|
constellation_msg::KeyV => "v",
|
||||||
|
constellation_msg::KeyW if shift => "W",
|
||||||
|
constellation_msg::KeyW => "w",
|
||||||
|
constellation_msg::KeyX if shift => "X",
|
||||||
|
constellation_msg::KeyX => "x",
|
||||||
|
constellation_msg::KeyY if shift => "Y",
|
||||||
|
constellation_msg::KeyY => "y",
|
||||||
|
constellation_msg::KeyZ if shift => "Z",
|
||||||
|
constellation_msg::KeyZ => "z",
|
||||||
|
constellation_msg::KeyLeftBracket if shift => "{",
|
||||||
|
constellation_msg::KeyLeftBracket => "{",
|
||||||
|
constellation_msg::KeyBackslash if shift => "|",
|
||||||
|
constellation_msg::KeyBackslash => "\\",
|
||||||
|
constellation_msg::KeyRightBracket if shift => "}",
|
||||||
|
constellation_msg::KeyRightBracket => "]",
|
||||||
|
constellation_msg::KeyGraveAccent => "Dead",
|
||||||
|
constellation_msg::KeyWorld1 => "Unidentified",
|
||||||
|
constellation_msg::KeyWorld2 => "Unidentified",
|
||||||
|
constellation_msg::KeyEscape => "Escape",
|
||||||
|
constellation_msg::KeyEnter => "Enter",
|
||||||
|
constellation_msg::KeyTab => "Tab",
|
||||||
|
constellation_msg::KeyBackspace => "Backspace",
|
||||||
|
constellation_msg::KeyInsert => "Insert",
|
||||||
|
constellation_msg::KeyDelete => "Delete",
|
||||||
|
constellation_msg::KeyRight => "ArrowRight",
|
||||||
|
constellation_msg::KeyLeft => "ArrowLeft",
|
||||||
|
constellation_msg::KeyDown => "ArrowDown",
|
||||||
|
constellation_msg::KeyUp => "ArrowUp",
|
||||||
|
constellation_msg::KeyPageUp => "PageUp",
|
||||||
|
constellation_msg::KeyPageDown => "PageDown",
|
||||||
|
constellation_msg::KeyHome => "Home",
|
||||||
|
constellation_msg::KeyEnd => "End",
|
||||||
|
constellation_msg::KeyCapsLock => "CapsLock",
|
||||||
|
constellation_msg::KeyScrollLock => "ScrollLock",
|
||||||
|
constellation_msg::KeyNumLock => "NumLock",
|
||||||
|
constellation_msg::KeyPrintScreen => "PrintScreen",
|
||||||
|
constellation_msg::KeyPause => "Pause",
|
||||||
|
constellation_msg::KeyF1 => "F1",
|
||||||
|
constellation_msg::KeyF2 => "F2",
|
||||||
|
constellation_msg::KeyF3 => "F3",
|
||||||
|
constellation_msg::KeyF4 => "F4",
|
||||||
|
constellation_msg::KeyF5 => "F5",
|
||||||
|
constellation_msg::KeyF6 => "F6",
|
||||||
|
constellation_msg::KeyF7 => "F7",
|
||||||
|
constellation_msg::KeyF8 => "F8",
|
||||||
|
constellation_msg::KeyF9 => "F9",
|
||||||
|
constellation_msg::KeyF10 => "F10",
|
||||||
|
constellation_msg::KeyF11 => "F11",
|
||||||
|
constellation_msg::KeyF12 => "F12",
|
||||||
|
constellation_msg::KeyF13 => "F13",
|
||||||
|
constellation_msg::KeyF14 => "F14",
|
||||||
|
constellation_msg::KeyF15 => "F15",
|
||||||
|
constellation_msg::KeyF16 => "F16",
|
||||||
|
constellation_msg::KeyF17 => "F17",
|
||||||
|
constellation_msg::KeyF18 => "F18",
|
||||||
|
constellation_msg::KeyF19 => "F19",
|
||||||
|
constellation_msg::KeyF20 => "F20",
|
||||||
|
constellation_msg::KeyF21 => "F21",
|
||||||
|
constellation_msg::KeyF22 => "F22",
|
||||||
|
constellation_msg::KeyF23 => "F23",
|
||||||
|
constellation_msg::KeyF24 => "F24",
|
||||||
|
constellation_msg::KeyF25 => "F25",
|
||||||
|
constellation_msg::KeyKp0 => "0",
|
||||||
|
constellation_msg::KeyKp1 => "1",
|
||||||
|
constellation_msg::KeyKp2 => "2",
|
||||||
|
constellation_msg::KeyKp3 => "3",
|
||||||
|
constellation_msg::KeyKp4 => "4",
|
||||||
|
constellation_msg::KeyKp5 => "5",
|
||||||
|
constellation_msg::KeyKp6 => "6",
|
||||||
|
constellation_msg::KeyKp7 => "7",
|
||||||
|
constellation_msg::KeyKp8 => "8",
|
||||||
|
constellation_msg::KeyKp9 => "9",
|
||||||
|
constellation_msg::KeyKpDecimal => ".",
|
||||||
|
constellation_msg::KeyKpDivide => "/",
|
||||||
|
constellation_msg::KeyKpMultiply => "*",
|
||||||
|
constellation_msg::KeyKpSubtract => "-",
|
||||||
|
constellation_msg::KeyKpAdd => "+",
|
||||||
|
constellation_msg::KeyKpEnter => "Enter",
|
||||||
|
constellation_msg::KeyKpEqual => "=",
|
||||||
|
constellation_msg::KeyLeftShift => "Shift",
|
||||||
|
constellation_msg::KeyLeftControl => "Control",
|
||||||
|
constellation_msg::KeyLeftAlt => "Alt",
|
||||||
|
constellation_msg::KeyLeftSuper => "Super",
|
||||||
|
constellation_msg::KeyRightShift => "Shift",
|
||||||
|
constellation_msg::KeyRightControl => "Control",
|
||||||
|
constellation_msg::KeyRightAlt => "Alt",
|
||||||
|
constellation_msg::KeyRightSuper => "Super",
|
||||||
|
constellation_msg::KeyMenu => "ContextMenu",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3Events-code.html
|
||||||
|
fn code_value(key: constellation_msg::Key) -> &'static str {
|
||||||
|
match key {
|
||||||
|
constellation_msg::KeySpace => "Space",
|
||||||
|
constellation_msg::KeyApostrophe => "Quote",
|
||||||
|
constellation_msg::KeyComma => "Comma",
|
||||||
|
constellation_msg::KeyMinus => "Minus",
|
||||||
|
constellation_msg::KeyPeriod => "Period",
|
||||||
|
constellation_msg::KeySlash => "Slash",
|
||||||
|
constellation_msg::Key0 => "Digit0",
|
||||||
|
constellation_msg::Key1 => "Digit1",
|
||||||
|
constellation_msg::Key2 => "Digit2",
|
||||||
|
constellation_msg::Key3 => "Digit3",
|
||||||
|
constellation_msg::Key4 => "Digit4",
|
||||||
|
constellation_msg::Key5 => "Digit5",
|
||||||
|
constellation_msg::Key6 => "Digit6",
|
||||||
|
constellation_msg::Key7 => "Digit7",
|
||||||
|
constellation_msg::Key8 => "Digit8",
|
||||||
|
constellation_msg::Key9 => "Digit9",
|
||||||
|
constellation_msg::KeySemicolon => "Semicolon",
|
||||||
|
constellation_msg::KeyEqual => "Equals",
|
||||||
|
constellation_msg::KeyA => "KeyA",
|
||||||
|
constellation_msg::KeyB => "KeyB",
|
||||||
|
constellation_msg::KeyC => "KeyC",
|
||||||
|
constellation_msg::KeyD => "KeyD",
|
||||||
|
constellation_msg::KeyE => "KeyE",
|
||||||
|
constellation_msg::KeyF => "KeyF",
|
||||||
|
constellation_msg::KeyG => "KeyG",
|
||||||
|
constellation_msg::KeyH => "KeyH",
|
||||||
|
constellation_msg::KeyI => "KeyI",
|
||||||
|
constellation_msg::KeyJ => "KeyJ",
|
||||||
|
constellation_msg::KeyK => "KeyK",
|
||||||
|
constellation_msg::KeyL => "KeyL",
|
||||||
|
constellation_msg::KeyM => "KeyM",
|
||||||
|
constellation_msg::KeyN => "KeyN",
|
||||||
|
constellation_msg::KeyO => "KeyO",
|
||||||
|
constellation_msg::KeyP => "KeyP",
|
||||||
|
constellation_msg::KeyQ => "KeyQ",
|
||||||
|
constellation_msg::KeyR => "KeyR",
|
||||||
|
constellation_msg::KeyS => "KeyS",
|
||||||
|
constellation_msg::KeyT => "KeyT",
|
||||||
|
constellation_msg::KeyU => "KeyU",
|
||||||
|
constellation_msg::KeyV => "KeyV",
|
||||||
|
constellation_msg::KeyW => "KeyW",
|
||||||
|
constellation_msg::KeyX => "KeyX",
|
||||||
|
constellation_msg::KeyY => "KeyY",
|
||||||
|
constellation_msg::KeyZ => "KeyZ",
|
||||||
|
constellation_msg::KeyLeftBracket => "BracketLeft",
|
||||||
|
constellation_msg::KeyBackslash => "Backslash",
|
||||||
|
constellation_msg::KeyRightBracket => "BracketRight",
|
||||||
|
|
||||||
|
constellation_msg::KeyGraveAccent |
|
||||||
|
constellation_msg::KeyWorld1 |
|
||||||
|
constellation_msg::KeyWorld2 => panic!("unknown char code for {}", key),
|
||||||
|
|
||||||
|
constellation_msg::KeyEscape => "Escape",
|
||||||
|
constellation_msg::KeyEnter => "Enter",
|
||||||
|
constellation_msg::KeyTab => "Tab",
|
||||||
|
constellation_msg::KeyBackspace => "Backspace",
|
||||||
|
constellation_msg::KeyInsert => "Insert",
|
||||||
|
constellation_msg::KeyDelete => "Delete",
|
||||||
|
constellation_msg::KeyRight => "ArrowRight",
|
||||||
|
constellation_msg::KeyLeft => "ArrowLeft",
|
||||||
|
constellation_msg::KeyDown => "ArrowDown",
|
||||||
|
constellation_msg::KeyUp => "ArrowUp",
|
||||||
|
constellation_msg::KeyPageUp => "PageUp",
|
||||||
|
constellation_msg::KeyPageDown => "PageDown",
|
||||||
|
constellation_msg::KeyHome => "Home",
|
||||||
|
constellation_msg::KeyEnd => "End",
|
||||||
|
constellation_msg::KeyCapsLock => "CapsLock",
|
||||||
|
constellation_msg::KeyScrollLock => "ScrollLock",
|
||||||
|
constellation_msg::KeyNumLock => "NumLock",
|
||||||
|
constellation_msg::KeyPrintScreen => "PrintScreen",
|
||||||
|
constellation_msg::KeyPause => "Pause",
|
||||||
|
constellation_msg::KeyF1 => "F1",
|
||||||
|
constellation_msg::KeyF2 => "F2",
|
||||||
|
constellation_msg::KeyF3 => "F3",
|
||||||
|
constellation_msg::KeyF4 => "F4",
|
||||||
|
constellation_msg::KeyF5 => "F5",
|
||||||
|
constellation_msg::KeyF6 => "F6",
|
||||||
|
constellation_msg::KeyF7 => "F7",
|
||||||
|
constellation_msg::KeyF8 => "F8",
|
||||||
|
constellation_msg::KeyF9 => "F9",
|
||||||
|
constellation_msg::KeyF10 => "F10",
|
||||||
|
constellation_msg::KeyF11 => "F11",
|
||||||
|
constellation_msg::KeyF12 => "F12",
|
||||||
|
constellation_msg::KeyF13 => "F13",
|
||||||
|
constellation_msg::KeyF14 => "F14",
|
||||||
|
constellation_msg::KeyF15 => "F15",
|
||||||
|
constellation_msg::KeyF16 => "F16",
|
||||||
|
constellation_msg::KeyF17 => "F17",
|
||||||
|
constellation_msg::KeyF18 => "F18",
|
||||||
|
constellation_msg::KeyF19 => "F19",
|
||||||
|
constellation_msg::KeyF20 => "F20",
|
||||||
|
constellation_msg::KeyF21 => "F21",
|
||||||
|
constellation_msg::KeyF22 => "F22",
|
||||||
|
constellation_msg::KeyF23 => "F23",
|
||||||
|
constellation_msg::KeyF24 => "F24",
|
||||||
|
constellation_msg::KeyF25 => "F25",
|
||||||
|
constellation_msg::KeyKp0 => "Numpad0",
|
||||||
|
constellation_msg::KeyKp1 => "Numpad1",
|
||||||
|
constellation_msg::KeyKp2 => "Numpad2",
|
||||||
|
constellation_msg::KeyKp3 => "Numpad3",
|
||||||
|
constellation_msg::KeyKp4 => "Numpad4",
|
||||||
|
constellation_msg::KeyKp5 => "Numpad5",
|
||||||
|
constellation_msg::KeyKp6 => "Numpad6",
|
||||||
|
constellation_msg::KeyKp7 => "Numpad7",
|
||||||
|
constellation_msg::KeyKp8 => "Numpad8",
|
||||||
|
constellation_msg::KeyKp9 => "Numpad9",
|
||||||
|
constellation_msg::KeyKpDecimal => "NumpadDecimal",
|
||||||
|
constellation_msg::KeyKpDivide => "NumpadDivide",
|
||||||
|
constellation_msg::KeyKpMultiply => "NumpadMultiply",
|
||||||
|
constellation_msg::KeyKpSubtract => "NumpadSubtract",
|
||||||
|
constellation_msg::KeyKpAdd => "NumpadAdd",
|
||||||
|
constellation_msg::KeyKpEnter => "NumpadEnter",
|
||||||
|
constellation_msg::KeyKpEqual => "NumpadEquals",
|
||||||
|
constellation_msg::KeyLeftShift | constellation_msg::KeyRightShift => "Shift",
|
||||||
|
constellation_msg::KeyLeftControl | constellation_msg::KeyRightControl => "Control",
|
||||||
|
constellation_msg::KeyLeftAlt | constellation_msg::KeyRightAlt => "Alt",
|
||||||
|
constellation_msg::KeyLeftSuper | constellation_msg::KeyRightSuper => "Super",
|
||||||
|
constellation_msg::KeyMenu => "Menu",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_location(key: constellation_msg::Key) -> u32 {
|
||||||
|
match key {
|
||||||
|
constellation_msg::KeyKp0 | constellation_msg::KeyKp1 | constellation_msg::KeyKp2 |
|
||||||
|
constellation_msg::KeyKp3 | constellation_msg::KeyKp4 | constellation_msg::KeyKp5 |
|
||||||
|
constellation_msg::KeyKp6 | constellation_msg::KeyKp7 | constellation_msg::KeyKp8 |
|
||||||
|
constellation_msg::KeyKp9 | constellation_msg::KeyKpDecimal |
|
||||||
|
constellation_msg::KeyKpDivide | constellation_msg::KeyKpMultiply |
|
||||||
|
constellation_msg::KeyKpSubtract | constellation_msg::KeyKpAdd |
|
||||||
|
constellation_msg::KeyKpEnter | constellation_msg::KeyKpEqual =>
|
||||||
|
KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD,
|
||||||
|
|
||||||
|
constellation_msg::KeyLeftShift | constellation_msg::KeyLeftAlt |
|
||||||
|
constellation_msg::KeyLeftControl | constellation_msg::KeyLeftSuper =>
|
||||||
|
KeyboardEventConstants::DOM_KEY_LOCATION_LEFT,
|
||||||
|
|
||||||
|
constellation_msg::KeyRightShift | constellation_msg::KeyRightAlt |
|
||||||
|
constellation_msg::KeyRightControl | constellation_msg::KeyRightSuper =>
|
||||||
|
KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT,
|
||||||
|
|
||||||
|
_ => KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#widl-KeyboardEvent-charCode
|
||||||
|
fn key_char_code(key: constellation_msg::Key, mods: constellation_msg::KeyModifiers) -> Option<u32> {
|
||||||
|
let key = key_value(key, mods);
|
||||||
|
if key.len() == 1 {
|
||||||
|
Some(key.char_at(0) as u32)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#legacy-key-models
|
||||||
|
fn key_key_code(key: constellation_msg::Key) -> u32 {
|
||||||
|
match key {
|
||||||
|
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#legacy-key-models
|
||||||
|
constellation_msg::KeyBackspace => 8,
|
||||||
|
constellation_msg::KeyTab => 9,
|
||||||
|
constellation_msg::KeyEnter => 13,
|
||||||
|
constellation_msg::KeyLeftShift | constellation_msg::KeyRightShift => 16,
|
||||||
|
constellation_msg::KeyLeftControl | constellation_msg::KeyRightControl => 17,
|
||||||
|
constellation_msg::KeyLeftAlt | constellation_msg::KeyRightAlt => 18,
|
||||||
|
constellation_msg::KeyCapsLock => 20,
|
||||||
|
constellation_msg::KeyEscape => 27,
|
||||||
|
constellation_msg::KeySpace => 32,
|
||||||
|
constellation_msg::KeyPageUp => 33,
|
||||||
|
constellation_msg::KeyPageDown => 34,
|
||||||
|
constellation_msg::KeyEnd => 35,
|
||||||
|
constellation_msg::KeyHome => 36,
|
||||||
|
constellation_msg::KeyLeft => 37,
|
||||||
|
constellation_msg::KeyUp => 38,
|
||||||
|
constellation_msg::KeyRight => 39,
|
||||||
|
constellation_msg::KeyDown => 40,
|
||||||
|
constellation_msg::KeyDelete => 46,
|
||||||
|
|
||||||
|
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#optionally-fixed-virtual-key-codes
|
||||||
|
constellation_msg::KeySemicolon => 186,
|
||||||
|
constellation_msg::KeyEqual => 187,
|
||||||
|
constellation_msg::KeyComma => 188,
|
||||||
|
constellation_msg::KeyMinus => 189,
|
||||||
|
constellation_msg::KeyPeriod => 190,
|
||||||
|
constellation_msg::KeySlash => 191,
|
||||||
|
constellation_msg::KeyLeftBracket => 219,
|
||||||
|
constellation_msg::KeyBackslash => 220,
|
||||||
|
constellation_msg::KeyRightBracket => 221,
|
||||||
|
constellation_msg::KeyApostrophe => 222,
|
||||||
|
|
||||||
|
//§ B.2.1.3
|
||||||
|
constellation_msg::Key0 |
|
||||||
|
constellation_msg::Key1 |
|
||||||
|
constellation_msg::Key2 |
|
||||||
|
constellation_msg::Key3 |
|
||||||
|
constellation_msg::Key4 |
|
||||||
|
constellation_msg::Key5 |
|
||||||
|
constellation_msg::Key6 |
|
||||||
|
constellation_msg::Key7 |
|
||||||
|
constellation_msg::Key8 |
|
||||||
|
constellation_msg::Key9 => key as u32 - constellation_msg::Key0 as u32 + '0' as u32,
|
||||||
|
|
||||||
|
//§ B.2.1.4
|
||||||
|
constellation_msg::KeyA |
|
||||||
|
constellation_msg::KeyB |
|
||||||
|
constellation_msg::KeyC |
|
||||||
|
constellation_msg::KeyD |
|
||||||
|
constellation_msg::KeyE |
|
||||||
|
constellation_msg::KeyF |
|
||||||
|
constellation_msg::KeyG |
|
||||||
|
constellation_msg::KeyH |
|
||||||
|
constellation_msg::KeyI |
|
||||||
|
constellation_msg::KeyJ |
|
||||||
|
constellation_msg::KeyK |
|
||||||
|
constellation_msg::KeyL |
|
||||||
|
constellation_msg::KeyM |
|
||||||
|
constellation_msg::KeyN |
|
||||||
|
constellation_msg::KeyO |
|
||||||
|
constellation_msg::KeyP |
|
||||||
|
constellation_msg::KeyQ |
|
||||||
|
constellation_msg::KeyR |
|
||||||
|
constellation_msg::KeyS |
|
||||||
|
constellation_msg::KeyT |
|
||||||
|
constellation_msg::KeyU |
|
||||||
|
constellation_msg::KeyV |
|
||||||
|
constellation_msg::KeyW |
|
||||||
|
constellation_msg::KeyX |
|
||||||
|
constellation_msg::KeyY |
|
||||||
|
constellation_msg::KeyZ => key as u32 - constellation_msg::KeyA as u32 + 'A' as u32,
|
||||||
|
|
||||||
|
//§ B.2.1.8
|
||||||
|
_ => 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct KeyEventProperties {
|
pub struct KeyEventProperties {
|
||||||
pub key: DOMString,
|
pub key: &'static str,
|
||||||
pub code: DOMString,
|
pub code: &'static str,
|
||||||
pub location: u32,
|
pub location: u32,
|
||||||
pub char_code: Option<u32>,
|
pub char_code: Option<u32>,
|
||||||
pub key_code: u32,
|
pub key_code: u32,
|
||||||
|
|
|
@ -221,3 +221,4 @@ pub mod layout_interface;
|
||||||
pub mod page;
|
pub mod page;
|
||||||
pub mod script_task;
|
pub mod script_task;
|
||||||
mod timers;
|
mod timers;
|
||||||
|
pub mod textinput;
|
||||||
|
|
|
@ -49,7 +49,7 @@ use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading};
|
||||||
use servo_msg::compositor_msg::{ScriptListener};
|
use servo_msg::compositor_msg::{ScriptListener};
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, LoadCompleteMsg, LoadUrlMsg, NavigationDirection};
|
use servo_msg::constellation_msg::{ConstellationChan, LoadCompleteMsg, LoadUrlMsg, NavigationDirection};
|
||||||
use servo_msg::constellation_msg::{LoadData, PipelineId, Failure, FailureMsg, WindowSizeData, Key, KeyState};
|
use servo_msg::constellation_msg::{LoadData, PipelineId, Failure, FailureMsg, WindowSizeData, Key, KeyState};
|
||||||
use servo_msg::constellation_msg::{KeyModifiers, Super, Shift, Control, Alt, Repeated, Pressed};
|
use servo_msg::constellation_msg::{KeyModifiers, SUPER, SHIFT, CONTROL, ALT, Repeated, Pressed};
|
||||||
use servo_msg::constellation_msg::{Released};
|
use servo_msg::constellation_msg::{Released};
|
||||||
use servo_msg::constellation_msg;
|
use servo_msg::constellation_msg;
|
||||||
use servo_net::image_cache_task::ImageCacheTask;
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
|
@ -923,7 +923,6 @@ impl ScriptTask {
|
||||||
state: KeyState,
|
state: KeyState,
|
||||||
modifiers: KeyModifiers,
|
modifiers: KeyModifiers,
|
||||||
pipeline_id: PipelineId) {
|
pipeline_id: PipelineId) {
|
||||||
println!("key {} is {}", key as int, state as int);
|
|
||||||
let page = get_page(&*self.page.borrow(), pipeline_id);
|
let page = get_page(&*self.page.borrow(), pipeline_id);
|
||||||
let frame = page.frame();
|
let frame = page.frame();
|
||||||
let window = frame.as_ref().unwrap().window.root();
|
let window = frame.as_ref().unwrap().window.root();
|
||||||
|
@ -937,10 +936,10 @@ impl ScriptTask {
|
||||||
(&None, &None) => EventTargetCast::from_ref(*window),
|
(&None, &None) => EventTargetCast::from_ref(*window),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ctrl = modifiers.contains(Control);
|
let ctrl = modifiers.contains(CONTROL);
|
||||||
let alt = modifiers.contains(Alt);
|
let alt = modifiers.contains(ALT);
|
||||||
let shift = modifiers.contains(Shift);
|
let shift = modifiers.contains(SHIFT);
|
||||||
let meta = modifiers.contains(Super);
|
let meta = modifiers.contains(SUPER);
|
||||||
|
|
||||||
let is_composing = false;
|
let is_composing = false;
|
||||||
let is_repeating = state == Repeated;
|
let is_repeating = state == Repeated;
|
||||||
|
@ -949,21 +948,24 @@ impl ScriptTask {
|
||||||
Released => "keyup",
|
Released => "keyup",
|
||||||
}.to_string();
|
}.to_string();
|
||||||
|
|
||||||
let props = KeyboardEvent::key_properties(key);
|
let props = KeyboardEvent::key_properties(key, modifiers);
|
||||||
|
|
||||||
let event = KeyboardEvent::new(*window, ev_type, true, true, Some(*window), 0,
|
let event = KeyboardEvent::new(*window, ev_type, true, true, Some(*window), 0,
|
||||||
props.key.clone(), props.code.clone(), props.location,
|
props.key.to_string(), props.code.to_string(), props.location,
|
||||||
is_repeating, is_composing, ctrl, alt, shift, meta,
|
is_repeating, is_composing, ctrl, alt, shift, meta,
|
||||||
props.char_code, props.key_code).root();
|
None, props.key_code).root();
|
||||||
let _ = target.DispatchEvent(EventCast::from_ref(*event));
|
let _ = target.DispatchEvent(EventCast::from_ref(*event));
|
||||||
|
|
||||||
if state != Released && props.is_printable() {
|
if state != Released && props.is_printable() {
|
||||||
let event = KeyboardEvent::new(*window, "keypress".to_string(), true, true, Some(*window),
|
let event = KeyboardEvent::new(*window, "keypress".to_string(), true, true, Some(*window),
|
||||||
0, props.key.clone(), props.code.clone(), props.location,
|
0, props.key.to_string(), props.code.to_string(),
|
||||||
is_repeating, is_composing, ctrl, alt, shift, meta,
|
props.location, is_repeating, is_composing,
|
||||||
props.char_code, props.key_code).root();
|
ctrl, alt, shift, meta,
|
||||||
|
props.char_code, 0).root();
|
||||||
let _ = target.DispatchEvent(EventCast::from_ref(*event));
|
let _ = target.DispatchEvent(EventCast::from_ref(*event));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.flush_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The entry point for content to notify that a new load has been requested
|
/// The entry point for content to notify that a new load has been requested
|
||||||
|
|
259
components/script/textinput.rs
Normal file
259
components/script/textinput.rs
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! Common handling of keyboard input and state management for text input controls
|
||||||
|
|
||||||
|
use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
|
||||||
|
use dom::bindings::js::JSRef;
|
||||||
|
use dom::keyboardevent::KeyboardEvent;
|
||||||
|
use servo_util::str::DOMString;
|
||||||
|
|
||||||
|
use std::cmp::{min, max};
|
||||||
|
use std::default::Default;
|
||||||
|
|
||||||
|
#[jstraceable]
|
||||||
|
struct TextPoint {
|
||||||
|
line: uint,
|
||||||
|
index: uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[jstraceable]
|
||||||
|
pub struct TextInput {
|
||||||
|
/// Current text input content, split across lines without trailing '\n'
|
||||||
|
lines: Vec<DOMString>,
|
||||||
|
/// Current cursor input point
|
||||||
|
edit_point: TextPoint,
|
||||||
|
/// Selection range, beginning and end point that can span multiple lines.
|
||||||
|
_selection: Option<(TextPoint, TextPoint)>,
|
||||||
|
/// Is this ia multiline input?
|
||||||
|
multiline: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum KeyReaction {
|
||||||
|
TriggerDefaultAction,
|
||||||
|
DispatchInput,
|
||||||
|
Nothing,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TextPoint {
|
||||||
|
fn default() -> TextPoint {
|
||||||
|
TextPoint {
|
||||||
|
line: 0,
|
||||||
|
index: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextInput {
|
||||||
|
pub fn new(multiline: bool, initial: DOMString) -> TextInput {
|
||||||
|
let mut i = TextInput {
|
||||||
|
lines: vec!(),
|
||||||
|
edit_point: Default::default(),
|
||||||
|
_selection: None,
|
||||||
|
multiline: multiline,
|
||||||
|
};
|
||||||
|
i.set_content(initial);
|
||||||
|
i
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_current_line(&self) -> &DOMString {
|
||||||
|
&self.lines[self.edit_point.line]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_char(&mut self, ch: char) {
|
||||||
|
//TODO: handle replacing selection with character
|
||||||
|
let new_line = {
|
||||||
|
let prefix = self.get_current_line().as_slice().slice_chars(0, self.edit_point.index);
|
||||||
|
let suffix = self.get_current_line().as_slice().slice_chars(self.edit_point.index,
|
||||||
|
self.current_line_length());
|
||||||
|
let mut new_line = prefix.to_string();
|
||||||
|
new_line.push(ch);
|
||||||
|
new_line.push_str(suffix.as_slice());
|
||||||
|
new_line
|
||||||
|
};
|
||||||
|
|
||||||
|
self.lines[self.edit_point.line] = new_line;
|
||||||
|
self.edit_point.index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete_char(&mut self, forward: bool) {
|
||||||
|
//TODO: handle deleting selection
|
||||||
|
let prefix_end = if forward {
|
||||||
|
self.edit_point.index
|
||||||
|
} else {
|
||||||
|
//TODO: handle backspacing from position 0 of current line
|
||||||
|
if self.multiline {
|
||||||
|
assert!(self.edit_point.index > 0);
|
||||||
|
} else if self.edit_point.index == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.edit_point.index - 1
|
||||||
|
};
|
||||||
|
let suffix_start = if forward {
|
||||||
|
let is_eol = self.edit_point.index == self.current_line_length() - 1;
|
||||||
|
if self.multiline {
|
||||||
|
//TODO: handle deleting from end position of current line
|
||||||
|
assert!(!is_eol);
|
||||||
|
} else if is_eol {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.edit_point.index + 1
|
||||||
|
} else {
|
||||||
|
self.edit_point.index
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_line = {
|
||||||
|
let prefix = self.get_current_line().as_slice().slice_chars(0, prefix_end);
|
||||||
|
let suffix = self.get_current_line().as_slice().slice_chars(suffix_start,
|
||||||
|
self.current_line_length());
|
||||||
|
let mut new_line = prefix.to_string();
|
||||||
|
new_line.push_str(suffix);
|
||||||
|
new_line
|
||||||
|
};
|
||||||
|
|
||||||
|
self.lines[self.edit_point.line] = new_line;
|
||||||
|
|
||||||
|
if !forward {
|
||||||
|
self.adjust_horizontal(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_line_length(&self) -> uint {
|
||||||
|
self.lines[self.edit_point.line].len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adjust_vertical(&mut self, adjust: int) {
|
||||||
|
if !self.multiline {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if adjust < 0 && self.edit_point.line as int + adjust < 0 {
|
||||||
|
self.edit_point.index = 0;
|
||||||
|
self.edit_point.line = 0;
|
||||||
|
return;
|
||||||
|
} else if adjust > 0 && self.edit_point.line >= min(0, self.lines.len() - adjust as uint) {
|
||||||
|
self.edit_point.index = self.current_line_length();
|
||||||
|
self.edit_point.line = self.lines.len() - 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.edit_point.line = (self.edit_point.line as int + adjust) as uint;
|
||||||
|
self.edit_point.index = min(self.current_line_length(), self.edit_point.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adjust_horizontal(&mut self, adjust: int) {
|
||||||
|
if adjust < 0 {
|
||||||
|
if self.multiline {
|
||||||
|
let remaining = self.edit_point.index;
|
||||||
|
if adjust.abs() as uint > remaining {
|
||||||
|
self.edit_point.index = 0;
|
||||||
|
self.adjust_vertical(-1);
|
||||||
|
self.edit_point.index = self.current_line_length();
|
||||||
|
self.adjust_horizontal(adjust + remaining as int);
|
||||||
|
} else {
|
||||||
|
self.edit_point.index = (self.edit_point.index as int + adjust) as uint;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.edit_point.index = max(0, self.edit_point.index as int + adjust) as uint;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if self.multiline {
|
||||||
|
let remaining = self.current_line_length() - self.edit_point.index;
|
||||||
|
if adjust as uint > remaining {
|
||||||
|
self.edit_point.index = 0;
|
||||||
|
self.adjust_vertical(1);
|
||||||
|
self.adjust_horizontal(adjust - remaining as int);
|
||||||
|
} else {
|
||||||
|
self.edit_point.index += adjust as uint;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.edit_point.index = min(self.current_line_length(),
|
||||||
|
self.edit_point.index + adjust as uint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_return(&mut self) -> KeyReaction {
|
||||||
|
if !self.multiline {
|
||||||
|
return TriggerDefaultAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: support replacing selection with newline
|
||||||
|
let prefix = self.get_current_line().as_slice().slice_chars(0, self.edit_point.index).to_string();
|
||||||
|
let suffix = self.get_current_line().as_slice().slice_chars(self.edit_point.index,
|
||||||
|
self.current_line_length()).to_string();
|
||||||
|
self.lines[self.edit_point.line] = prefix;
|
||||||
|
self.lines.insert(self.edit_point.line + 1, suffix);
|
||||||
|
return DispatchInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_keydown(&mut self, event: JSRef<KeyboardEvent>) -> KeyReaction {
|
||||||
|
match event.Key().as_slice() {
|
||||||
|
c if c.len() == 1 => {
|
||||||
|
self.insert_char(c.char_at(0));
|
||||||
|
return DispatchInput;
|
||||||
|
}
|
||||||
|
"Space" => {
|
||||||
|
self.insert_char(' ');
|
||||||
|
DispatchInput
|
||||||
|
}
|
||||||
|
"Delete" => {
|
||||||
|
self.delete_char(true);
|
||||||
|
DispatchInput
|
||||||
|
}
|
||||||
|
"Backspace" => {
|
||||||
|
self.delete_char(false);
|
||||||
|
DispatchInput
|
||||||
|
}
|
||||||
|
"ArrowLeft" => {
|
||||||
|
self.adjust_horizontal(-1);
|
||||||
|
Nothing
|
||||||
|
}
|
||||||
|
"ArrowRight" => {
|
||||||
|
self.adjust_horizontal(1);
|
||||||
|
Nothing
|
||||||
|
}
|
||||||
|
"ArrowUp" => {
|
||||||
|
self.adjust_vertical(-1);
|
||||||
|
Nothing
|
||||||
|
}
|
||||||
|
"ArrowDown" => {
|
||||||
|
self.adjust_vertical(1);
|
||||||
|
Nothing
|
||||||
|
}
|
||||||
|
"Enter" => self.handle_return(),
|
||||||
|
"Home" => {
|
||||||
|
self.edit_point.index = 0;
|
||||||
|
Nothing
|
||||||
|
}
|
||||||
|
"End" => {
|
||||||
|
self.edit_point.index = self.current_line_length();
|
||||||
|
Nothing
|
||||||
|
}
|
||||||
|
"Tab" => TriggerDefaultAction,
|
||||||
|
_ => Nothing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_content(&self) -> DOMString {
|
||||||
|
let mut content = "".to_string();
|
||||||
|
for (i, line) in self.lines.iter().enumerate() {
|
||||||
|
content.push_str(line.as_slice());
|
||||||
|
if i < self.lines.len() - 1 {
|
||||||
|
content.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_content(&mut self, content: DOMString) {
|
||||||
|
self.lines = if self.multiline {
|
||||||
|
content.as_slice().split('\n').map(|s| s.to_string()).collect()
|
||||||
|
} else {
|
||||||
|
vec!(content)
|
||||||
|
};
|
||||||
|
self.edit_point.line = min(self.edit_point.line, self.lines.len() - 1);
|
||||||
|
self.edit_point.index = min(self.edit_point.index, self.current_line_length() - 1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -440,16 +440,16 @@ extern "C" fn on_framebuffer_size(_glfw_window: *mut glfw::ffi::GLFWwindow,
|
||||||
fn glfw_mods_to_script_mods(mods: glfw::Modifiers) -> constellation_msg::KeyModifiers {
|
fn glfw_mods_to_script_mods(mods: glfw::Modifiers) -> constellation_msg::KeyModifiers {
|
||||||
let mut result = constellation_msg::KeyModifiers::from_bits(0).unwrap();
|
let mut result = constellation_msg::KeyModifiers::from_bits(0).unwrap();
|
||||||
if mods.contains(glfw::Shift) {
|
if mods.contains(glfw::Shift) {
|
||||||
result.insert(constellation_msg::Shift);
|
result.insert(constellation_msg::SHIFT);
|
||||||
}
|
}
|
||||||
if mods.contains(glfw::Alt) {
|
if mods.contains(glfw::Alt) {
|
||||||
result.insert(constellation_msg::Alt);
|
result.insert(constellation_msg::ALT);
|
||||||
}
|
}
|
||||||
if mods.contains(glfw::Control) {
|
if mods.contains(glfw::Control) {
|
||||||
result.insert(constellation_msg::Control);
|
result.insert(constellation_msg::CONTROL);
|
||||||
}
|
}
|
||||||
if mods.contains(glfw::Super) {
|
if mods.contains(glfw::Super) {
|
||||||
result.insert(constellation_msg::Super);
|
result.insert(constellation_msg::SUPER);
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue