mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Moved dispatch_key_event method from script_task.rs to document.rs, fixes #4982
This commit is contained in:
parent
c1645bd10c
commit
d79e422a8f
2 changed files with 92 additions and 90 deletions
|
@ -6,6 +6,7 @@ use dom::attr::{Attr, AttrHelpers, AttrValue};
|
||||||
use dom::bindings::cell::DOMRefCell;
|
use dom::bindings::cell::DOMRefCell;
|
||||||
use dom::bindings::codegen::Bindings::DocumentBinding;
|
use dom::bindings::codegen::Bindings::DocumentBinding;
|
||||||
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState};
|
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState};
|
||||||
|
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
||||||
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
|
||||||
use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods;
|
use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods;
|
||||||
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
||||||
|
@ -56,6 +57,10 @@ use dom::range::Range;
|
||||||
use dom::treewalker::TreeWalker;
|
use dom::treewalker::TreeWalker;
|
||||||
use dom::uievent::UIEvent;
|
use dom::uievent::UIEvent;
|
||||||
use dom::window::{Window, WindowHelpers};
|
use dom::window::{Window, WindowHelpers};
|
||||||
|
|
||||||
|
use msg::compositor_msg::ScriptListener;
|
||||||
|
use msg::constellation_msg::{Key, KeyState, KeyModifiers};
|
||||||
|
use msg::constellation_msg::{SUPER, ALT, SHIFT, CONTROL};
|
||||||
use net::resource_task::ControlMsg::{SetCookiesForUrl, GetCookiesForUrl};
|
use net::resource_task::ControlMsg::{SetCookiesForUrl, GetCookiesForUrl};
|
||||||
use net::cookie_storage::CookieSource::NonHTTP;
|
use net::cookie_storage::CookieSource::NonHTTP;
|
||||||
use script_task::Runnable;
|
use script_task::Runnable;
|
||||||
|
@ -199,6 +204,8 @@ pub trait DocumentHelpers<'a> {
|
||||||
fn send_title_to_compositor(self);
|
fn send_title_to_compositor(self);
|
||||||
fn dirty_all_nodes(self);
|
fn dirty_all_nodes(self);
|
||||||
fn handle_click_event(self, js_runtime: *mut JSRuntime, _button: uint, point: Point2D<f32>);
|
fn handle_click_event(self, js_runtime: *mut JSRuntime, _button: uint, point: Point2D<f32>);
|
||||||
|
fn dispatch_key_event(self, key: Key, state: KeyState,
|
||||||
|
modifiers: KeyModifiers, compositor: &mut Box<ScriptListener+'static>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
|
impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
|
||||||
|
@ -450,6 +457,84 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The entry point for all key processing for web content
|
||||||
|
fn dispatch_key_event(self, key: Key,
|
||||||
|
state: KeyState,
|
||||||
|
modifiers: KeyModifiers,
|
||||||
|
compositor: &mut Box<ScriptListener+'static>) {
|
||||||
|
let window = self.window.root();
|
||||||
|
let focused = self.get_focused_element().root();
|
||||||
|
let body = self.GetBody().root();
|
||||||
|
|
||||||
|
let target: JSRef<EventTarget> = match (&focused, &body) {
|
||||||
|
(&Some(ref focused), _) => EventTargetCast::from_ref(focused.r()),
|
||||||
|
(&None, &Some(ref body)) => EventTargetCast::from_ref(body.r()),
|
||||||
|
(&None, &None) => EventTargetCast::from_ref(window.r()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let ctrl = modifiers.contains(CONTROL);
|
||||||
|
let alt = modifiers.contains(ALT);
|
||||||
|
let shift = modifiers.contains(SHIFT);
|
||||||
|
let meta = modifiers.contains(SUPER);
|
||||||
|
|
||||||
|
let is_composing = false;
|
||||||
|
let is_repeating = state == KeyState::Repeated;
|
||||||
|
let ev_type = match state {
|
||||||
|
KeyState::Pressed | KeyState::Repeated => "keydown",
|
||||||
|
KeyState::Released => "keyup",
|
||||||
|
}.to_owned();
|
||||||
|
|
||||||
|
let props = KeyboardEvent::key_properties(key, modifiers);
|
||||||
|
|
||||||
|
let keyevent = KeyboardEvent::new(window.r(), ev_type, true, true,
|
||||||
|
Some(window.r()), 0,
|
||||||
|
props.key.to_owned(), props.code.to_owned(),
|
||||||
|
props.location, is_repeating, is_composing,
|
||||||
|
ctrl, alt, shift, meta,
|
||||||
|
None, props.key_code).root();
|
||||||
|
let event = EventCast::from_ref(keyevent.r());
|
||||||
|
let _ = target.DispatchEvent(event);
|
||||||
|
let mut prevented = event.DefaultPrevented();
|
||||||
|
|
||||||
|
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keys-cancelable-keys
|
||||||
|
if state != KeyState::Released && props.is_printable() && !prevented {
|
||||||
|
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keypress-event-order
|
||||||
|
let event = KeyboardEvent::new(window.r(), "keypress".to_owned(),
|
||||||
|
true, true, Some(window.r()),
|
||||||
|
0, props.key.to_owned(), props.code.to_owned(),
|
||||||
|
props.location, is_repeating, is_composing,
|
||||||
|
ctrl, alt, shift, meta,
|
||||||
|
props.char_code, 0).root();
|
||||||
|
let ev = EventCast::from_ref(event.r());
|
||||||
|
let _ = target.DispatchEvent(ev);
|
||||||
|
prevented = ev.DefaultPrevented();
|
||||||
|
// TODO: if keypress event is canceled, prevent firing input events
|
||||||
|
}
|
||||||
|
|
||||||
|
if !prevented {
|
||||||
|
compositor.send_key_event(key, state, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This behavior is unspecced
|
||||||
|
// We are supposed to dispatch synthetic click activation for Space and/or Return,
|
||||||
|
// however *when* we do it is up to us
|
||||||
|
// I'm dispatching it after the key event so the script has a chance to cancel it
|
||||||
|
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=27337
|
||||||
|
match key {
|
||||||
|
Key::Space if !prevented && state == KeyState::Released => {
|
||||||
|
let maybe_elem: Option<JSRef<Element>> = ElementCast::to_ref(target);
|
||||||
|
maybe_elem.map(|el| el.as_maybe_activatable().map(|a| a.synthetic_click_activation(ctrl, alt, shift, meta)));
|
||||||
|
}
|
||||||
|
Key::Enter if !prevented && state == KeyState::Released => {
|
||||||
|
let maybe_elem: Option<JSRef<Element>> = ElementCast::to_ref(target);
|
||||||
|
maybe_elem.map(|el| el.as_maybe_activatable().map(|a| a.implicit_submission(ctrl, alt, shift, meta)));
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
window.r().flush_layout(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
|
|
|
@ -9,9 +9,6 @@
|
||||||
|
|
||||||
use dom::bindings::cell::DOMRefCell;
|
use dom::bindings::cell::DOMRefCell;
|
||||||
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState};
|
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState};
|
||||||
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
|
||||||
use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods;
|
|
||||||
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
|
||||||
use dom::bindings::codegen::InheritTypes::{ElementCast, EventTargetCast, HTMLIFrameElementCast, NodeCast, EventCast};
|
use dom::bindings::codegen::InheritTypes::{ElementCast, EventTargetCast, HTMLIFrameElementCast, NodeCast, EventCast};
|
||||||
use dom::bindings::conversions::FromJSValConvertible;
|
use dom::bindings::conversions::FromJSValConvertible;
|
||||||
use dom::bindings::conversions::StringificationBehavior;
|
use dom::bindings::conversions::StringificationBehavior;
|
||||||
|
@ -22,11 +19,10 @@ use dom::bindings::structuredclone::StructuredCloneData;
|
||||||
use dom::bindings::trace::JSTraceable;
|
use dom::bindings::trace::JSTraceable;
|
||||||
use dom::bindings::utils::{wrap_for_same_compartment, pre_wrap};
|
use dom::bindings::utils::{wrap_for_same_compartment, pre_wrap};
|
||||||
use dom::document::{Document, IsHTMLDocument, DocumentHelpers, DocumentProgressHandler, DocumentProgressTask, DocumentSource};
|
use dom::document::{Document, IsHTMLDocument, DocumentHelpers, DocumentProgressHandler, DocumentProgressTask, DocumentSource};
|
||||||
use dom::element::{Element, ActivationElementHelpers, AttributeHandlers};
|
use dom::element::{Element, AttributeHandlers};
|
||||||
use dom::event::{Event, EventHelpers};
|
use dom::event::{Event, EventHelpers};
|
||||||
use dom::uievent::UIEvent;
|
use dom::uievent::UIEvent;
|
||||||
use dom::eventtarget::EventTarget;
|
use dom::eventtarget::EventTarget;
|
||||||
use dom::keyboardevent::KeyboardEvent;
|
|
||||||
use dom::mouseevent::MouseEvent;
|
use dom::mouseevent::MouseEvent;
|
||||||
use dom::node::{self, Node, NodeHelpers, NodeDamage};
|
use dom::node::{self, Node, NodeHelpers, NodeDamage};
|
||||||
use dom::window::{Window, WindowHelpers, ScriptHelpers};
|
use dom::window::{Window, WindowHelpers, ScriptHelpers};
|
||||||
|
@ -51,9 +47,7 @@ use msg::compositor_msg::ReadyState::{FinishedLoading, Loading, PerformingLayout
|
||||||
use msg::compositor_msg::{LayerId, ScriptListener};
|
use msg::compositor_msg::{LayerId, ScriptListener};
|
||||||
use msg::constellation_msg::{ConstellationChan};
|
use msg::constellation_msg::{ConstellationChan};
|
||||||
use msg::constellation_msg::{LoadData, PipelineId, SubpageId};
|
use msg::constellation_msg::{LoadData, PipelineId, SubpageId};
|
||||||
use msg::constellation_msg::{Failure, Msg, WindowSizeData, Key, KeyState};
|
use msg::constellation_msg::{Failure, Msg, WindowSizeData, PipelineExitType};
|
||||||
use msg::constellation_msg::{KeyModifiers, SUPER, SHIFT, CONTROL, ALT};
|
|
||||||
use msg::constellation_msg::{PipelineExitType};
|
|
||||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||||
use net::image_cache_task::ImageCacheTask;
|
use net::image_cache_task::ImageCacheTask;
|
||||||
use net::resource_task::{ResourceTask, ControlMsg};
|
use net::resource_task::{ResourceTask, ControlMsg};
|
||||||
|
@ -1009,92 +1003,15 @@ impl ScriptTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent(key, state, modifiers) => {
|
KeyEvent(key, state, modifiers) => {
|
||||||
self.dispatch_key_event(key, state, modifiers, pipeline_id);
|
let page = get_page(&*self.page.borrow(), pipeline_id);
|
||||||
|
let frame = page.frame();
|
||||||
|
let document = frame.as_ref().unwrap().document.root();
|
||||||
|
document.r().dispatch_key_event(
|
||||||
|
key, state, modifiers, &mut *self.compositor.borrow_mut());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The entry point for all key processing for web content
|
|
||||||
fn dispatch_key_event(&self, key: Key,
|
|
||||||
state: KeyState,
|
|
||||||
modifiers: KeyModifiers,
|
|
||||||
pipeline_id: PipelineId) {
|
|
||||||
let page = get_page(&*self.page.borrow(), pipeline_id);
|
|
||||||
let frame = page.frame();
|
|
||||||
let window = frame.as_ref().unwrap().window.root();
|
|
||||||
let doc = window.r().Document().root();
|
|
||||||
let focused = doc.r().get_focused_element().root();
|
|
||||||
let body = doc.r().GetBody().root();
|
|
||||||
|
|
||||||
let target: JSRef<EventTarget> = match (&focused, &body) {
|
|
||||||
(&Some(ref focused), _) => EventTargetCast::from_ref(focused.r()),
|
|
||||||
(&None, &Some(ref body)) => EventTargetCast::from_ref(body.r()),
|
|
||||||
(&None, &None) => EventTargetCast::from_ref(window.r()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let ctrl = modifiers.contains(CONTROL);
|
|
||||||
let alt = modifiers.contains(ALT);
|
|
||||||
let shift = modifiers.contains(SHIFT);
|
|
||||||
let meta = modifiers.contains(SUPER);
|
|
||||||
|
|
||||||
let is_composing = false;
|
|
||||||
let is_repeating = state == KeyState::Repeated;
|
|
||||||
let ev_type = match state {
|
|
||||||
KeyState::Pressed | KeyState::Repeated => "keydown",
|
|
||||||
KeyState::Released => "keyup",
|
|
||||||
}.to_owned();
|
|
||||||
|
|
||||||
let props = KeyboardEvent::key_properties(key, modifiers);
|
|
||||||
|
|
||||||
let keyevent = KeyboardEvent::new(window.r(), ev_type, true, true,
|
|
||||||
Some(window.r()), 0,
|
|
||||||
props.key.to_owned(), props.code.to_owned(),
|
|
||||||
props.location, is_repeating, is_composing,
|
|
||||||
ctrl, alt, shift, meta,
|
|
||||||
None, props.key_code).root();
|
|
||||||
let event = EventCast::from_ref(keyevent.r());
|
|
||||||
let _ = target.DispatchEvent(event);
|
|
||||||
let mut prevented = event.DefaultPrevented();
|
|
||||||
|
|
||||||
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keys-cancelable-keys
|
|
||||||
if state != KeyState::Released && props.is_printable() && !prevented {
|
|
||||||
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keypress-event-order
|
|
||||||
let event = KeyboardEvent::new(window.r(), "keypress".to_owned(),
|
|
||||||
true, true, Some(window.r()),
|
|
||||||
0, props.key.to_owned(), props.code.to_owned(),
|
|
||||||
props.location, is_repeating, is_composing,
|
|
||||||
ctrl, alt, shift, meta,
|
|
||||||
props.char_code, 0).root();
|
|
||||||
let ev = EventCast::from_ref(event.r());
|
|
||||||
let _ = target.DispatchEvent(ev);
|
|
||||||
prevented = ev.DefaultPrevented();
|
|
||||||
// TODO: if keypress event is canceled, prevent firing input events
|
|
||||||
}
|
|
||||||
|
|
||||||
if !prevented {
|
|
||||||
self.compositor.borrow_mut().send_key_event(key, state, modifiers);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This behavior is unspecced
|
|
||||||
// We are supposed to dispatch synthetic click activation for Space and/or Return,
|
|
||||||
// however *when* we do it is up to us
|
|
||||||
// I'm dispatching it after the key event so the script has a chance to cancel it
|
|
||||||
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=27337
|
|
||||||
match key {
|
|
||||||
Key::Space if !prevented && state == KeyState::Released => {
|
|
||||||
let maybe_elem: Option<JSRef<Element>> = ElementCast::to_ref(target);
|
|
||||||
maybe_elem.map(|el| el.as_maybe_activatable().map(|a| a.synthetic_click_activation(ctrl, alt, shift, meta)));
|
|
||||||
}
|
|
||||||
Key::Enter if !prevented && state == KeyState::Released => {
|
|
||||||
let maybe_elem: Option<JSRef<Element>> = ElementCast::to_ref(target);
|
|
||||||
maybe_elem.map(|el| el.as_maybe_activatable().map(|a| a.implicit_submission(ctrl, alt, shift, meta)));
|
|
||||||
}
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
|
|
||||||
window.r().flush_layout(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
||||||
/// for the given pipeline.
|
/// for the given pipeline.
|
||||||
fn trigger_load(&self, pipeline_id: PipelineId, load_data: LoadData) {
|
fn trigger_load(&self, pipeline_id: PipelineId, load_data: LoadData) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue