aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/script_task.rs
diff options
context:
space:
mode:
authorbors-servo <metajack+bors@gmail.com>2014-11-13 10:57:33 -0700
committerbors-servo <metajack+bors@gmail.com>2014-11-13 10:57:33 -0700
commit2ffa845cf463b14b19322d477a77ffd20efa89a9 (patch)
tree64428ac6615df95fabb298f0aeb274fc10f947c7 /components/script/script_task.rs
parentc5e1b0d32e17fad29799023c85e2e73ac89c3af7 (diff)
parentc23edf6f5a020f24008c84957c1a290241632c6d (diff)
downloadservo-2ffa845cf463b14b19322d477a77ffd20efa89a9.tar.gz
servo-2ffa845cf463b14b19322d477a77ffd20efa89a9.zip
auto merge of #3585 : jdm/servo/input, r=gw
This attempts to implement a bunch of the DOM Level 3 Events spec by implementing the KeyboardEvent interface, the document focus context, and dispatching keyup/keydown/keypress events appropriately. There's also some support for multiline text input that's untested.
Diffstat (limited to 'components/script/script_task.rs')
-rw-r--r--components/script/script_task.rs75
1 files changed, 72 insertions, 3 deletions
diff --git a/components/script/script_task.rs b/components/script/script_task.rs
index c6f4b636d50..087e3fdf043 100644
--- a/components/script/script_task.rs
+++ b/components/script/script_task.rs
@@ -9,7 +9,9 @@ use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyStateValues};
use dom::bindings::codegen::Bindings::DOMRectBinding::DOMRectMethods;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
+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::{EventTargetCast, NodeCast, EventCast, ElementCast};
use dom::bindings::conversions;
use dom::bindings::conversions::{FromJSValConvertible, Empty};
@@ -23,6 +25,7 @@ use dom::element::{HTMLSelectElementTypeId, HTMLTextAreaElementTypeId, HTMLOptio
use dom::event::{Event, Bubbles, DoesNotBubble, Cancelable, NotCancelable};
use dom::uievent::UIEvent;
use dom::eventtarget::{EventTarget, EventTargetHelpers};
+use dom::keyboardevent::KeyboardEvent;
use dom::node;
use dom::node::{ElementNodeTypeId, Node, NodeHelpers};
use dom::window::{Window, WindowHelpers};
@@ -42,11 +45,13 @@ use script_traits::{CompositorEvent, ResizeEvent, ReflowEvent, ClickEvent, Mouse
use script_traits::{MouseMoveEvent, MouseUpEvent, ConstellationControlMsg, ScriptTaskFactory};
use script_traits::{ResizeMsg, AttachLayoutMsg, LoadMsg, ViewportMsg, SendEventMsg};
use script_traits::{ResizeInactiveMsg, ExitPipelineMsg, NewLayoutInfo, OpaqueScriptLayoutChannel};
-use script_traits::{ScriptControlChan, ReflowCompleteMsg, UntrustedNodeAddress};
+use script_traits::{ScriptControlChan, ReflowCompleteMsg, UntrustedNodeAddress, KeyEvent};
use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading};
use servo_msg::compositor_msg::{ScriptListener};
use servo_msg::constellation_msg::{ConstellationChan, LoadCompleteMsg, LoadUrlMsg, NavigationDirection};
-use servo_msg::constellation_msg::{LoadData, PipelineId, Failure, FailureMsg, WindowSizeData};
+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::{Released};
use servo_msg::constellation_msg;
use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask;
@@ -907,7 +912,67 @@ impl ScriptTask {
MouseMoveEvent(point) => {
self.handle_mouse_move_event(pipeline_id, point);
}
+
+ KeyEvent(key, state, modifiers) => {
+ self.dispatch_key_event(key, state, modifiers, pipeline_id);
+ }
+ }
+ }
+
+ /// 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.Document().root();
+ let focused = doc.get_focused_element().root();
+ let body = doc.GetBody().root();
+
+ let target: JSRef<EventTarget> = match (&focused, &body) {
+ (&Some(ref focused), _) => EventTargetCast::from_ref(**focused),
+ (&None, &Some(ref body)) => EventTargetCast::from_ref(**body),
+ (&None, &None) => EventTargetCast::from_ref(*window),
+ };
+
+ 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 == Repeated;
+ let ev_type = match state {
+ Pressed | Repeated => "keydown",
+ Released => "keyup",
+ }.to_string();
+
+ let props = KeyboardEvent::key_properties(key, modifiers);
+
+ let keyevent = KeyboardEvent::new(*window, ev_type, true, true, Some(*window), 0,
+ props.key.to_string(), props.code.to_string(),
+ props.location, is_repeating, is_composing,
+ ctrl, alt, shift, meta,
+ None, props.key_code).root();
+ let event = EventCast::from_ref(*keyevent);
+ let _ = target.DispatchEvent(event);
+
+ // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keys-cancelable-keys
+ if state != Released && props.is_printable() && !event.DefaultPrevented() {
+ // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#keypress-event-order
+ let event = KeyboardEvent::new(*window, "keypress".to_string(), true, true, Some(*window),
+ 0, props.key.to_string(), props.code.to_string(),
+ props.location, is_repeating, is_composing,
+ ctrl, alt, shift, meta,
+ props.char_code, 0).root();
+ let _ = target.DispatchEvent(EventCast::from_ref(*event));
+
+ // TODO: if keypress event is canceled, prevent firing input events
}
+
+ window.flush_layout();
}
/// The entry point for content to notify that a new load has been requested
@@ -1011,6 +1076,9 @@ impl ScriptTask {
match *page.frame() {
Some(ref frame) => {
let window = frame.window.root();
+ let doc = window.Document().root();
+ doc.begin_focus_transaction();
+
let event =
Event::new(&global::Window(*window),
"click".to_string(),
@@ -1018,6 +1086,7 @@ impl ScriptTask {
let eventtarget: JSRef<EventTarget> = EventTargetCast::from_ref(node);
let _ = eventtarget.dispatch_event_with_target(None, *event);
+ doc.commit_focus_transaction();
window.flush_layout();
}
None => {}
@@ -1093,7 +1162,7 @@ impl ScriptTask {
}
None => {}
- }
+ }
}
}