mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
Dispatch keydown, keyup, and keypress events at appropriate times.
This commit is contained in:
parent
e999843183
commit
329ba56fca
8 changed files with 124 additions and 19 deletions
|
@ -43,7 +43,7 @@ use servo_msg::compositor_msg::{Blank, Epoch, FinishedLoading, IdleRenderState,
|
||||||
use servo_msg::compositor_msg::{ReadyState, RenderingRenderState, RenderState, Scrollable};
|
use servo_msg::compositor_msg::{ReadyState, RenderingRenderState, RenderState, Scrollable};
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, LoadUrlMsg};
|
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, LoadUrlMsg};
|
||||||
use servo_msg::constellation_msg::{NavigateMsg, LoadData, PipelineId, ResizedWindowMsg};
|
use servo_msg::constellation_msg::{NavigateMsg, LoadData, PipelineId, ResizedWindowMsg};
|
||||||
use servo_msg::constellation_msg::{WindowSizeData, KeyState, Key};
|
use servo_msg::constellation_msg::{WindowSizeData, KeyState, Key, KeyModifiers};
|
||||||
use servo_msg::constellation_msg;
|
use servo_msg::constellation_msg;
|
||||||
use servo_util::geometry::{PagePx, ScreenPx, ViewportPx};
|
use servo_util::geometry::{PagePx, ScreenPx, ViewportPx};
|
||||||
use servo_util::memory::MemoryProfilerChan;
|
use servo_util::memory::MemoryProfilerChan;
|
||||||
|
@ -707,8 +707,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
self.on_navigation_window_event(direction);
|
self.on_navigation_window_event(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent(key, state) => {
|
KeyEvent(key, state, modifiers) => {
|
||||||
self.on_key_event(key, state);
|
self.on_key_event(key, state, modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
FinishedWindowEvent => {
|
FinishedWindowEvent => {
|
||||||
|
@ -882,9 +882,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
chan.send(NavigateMsg(direction))
|
chan.send(NavigateMsg(direction))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_key_event(&self, key: Key, state: KeyState) {
|
fn on_key_event(&self, key: Key, state: KeyState, modifiers: KeyModifiers) {
|
||||||
let ConstellationChan(ref chan) = self.constellation_chan;
|
let ConstellationChan(ref chan) = self.constellation_chan;
|
||||||
chan.send(constellation_msg::KeyEvent(key, state))
|
chan.send(constellation_msg::KeyEvent(key, state, modifiers))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_buffer_requests_to_pipeline_requests_map(&self,
|
fn convert_buffer_requests_to_pipeline_requests_map(&self,
|
||||||
|
|
|
@ -22,7 +22,7 @@ use servo_msg::constellation_msg::{IFrameSandboxState, IFrameUnsandboxed, InitLo
|
||||||
use servo_msg::constellation_msg::{LoadCompleteMsg, LoadUrlMsg, LoadData, Msg, NavigateMsg};
|
use servo_msg::constellation_msg::{LoadCompleteMsg, LoadUrlMsg, LoadData, Msg, NavigateMsg};
|
||||||
use servo_msg::constellation_msg::{NavigationType, PipelineId, RendererReadyMsg, ResizedWindowMsg};
|
use servo_msg::constellation_msg::{NavigationType, PipelineId, RendererReadyMsg, ResizedWindowMsg};
|
||||||
use servo_msg::constellation_msg::{ScriptLoadedURLInIFrameMsg, SubpageId, WindowSizeData};
|
use servo_msg::constellation_msg::{ScriptLoadedURLInIFrameMsg, SubpageId, WindowSizeData};
|
||||||
use servo_msg::constellation_msg::{KeyEvent, Key, KeyState};
|
use servo_msg::constellation_msg::{KeyEvent, Key, KeyState, KeyModifiers};
|
||||||
use servo_msg::constellation_msg;
|
use servo_msg::constellation_msg;
|
||||||
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
|
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
|
||||||
use servo_net::resource_task::ResourceTask;
|
use servo_net::resource_task::ResourceTask;
|
||||||
|
@ -452,9 +452,9 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
debug!("constellation got window resize message");
|
debug!("constellation got window resize message");
|
||||||
self.handle_resized_window_msg(new_size);
|
self.handle_resized_window_msg(new_size);
|
||||||
}
|
}
|
||||||
KeyEvent(key, state) => {
|
KeyEvent(key, state, modifiers) => {
|
||||||
debug!("constellation got key event message");
|
debug!("constellation got key event message");
|
||||||
self.handle_key_msg(key, state);
|
self.handle_key_msg(key, state, modifiers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -767,10 +767,10 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
.any(|current_frame| current_frame.contains(pipeline_id))
|
.any(|current_frame| current_frame.contains(pipeline_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_key_msg(&self, key: Key, state: KeyState) {
|
fn handle_key_msg(&self, key: Key, state: KeyState, mods: KeyModifiers) {
|
||||||
self.current_frame().as_ref().map(|frame| {
|
self.current_frame().as_ref().map(|frame| {
|
||||||
let ScriptControlChan(ref chan) = frame.pipeline.script_chan;
|
let ScriptControlChan(ref chan) = frame.pipeline.script_chan;
|
||||||
chan.send(SendEventMsg(frame.pipeline.id, script_traits::KeyEvent(key, state)));
|
chan.send(SendEventMsg(frame.pipeline.id, script_traits::KeyEvent(key, state, mods)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use geom::scale_factor::ScaleFactor;
|
||||||
use geom::size::TypedSize2D;
|
use geom::size::TypedSize2D;
|
||||||
use layers::geometry::DevicePixel;
|
use layers::geometry::DevicePixel;
|
||||||
use layers::platform::surface::NativeGraphicsMetadata;
|
use layers::platform::surface::NativeGraphicsMetadata;
|
||||||
use servo_msg::constellation_msg::{Key, KeyState};
|
use servo_msg::constellation_msg::{Key, KeyState, KeyModifiers};
|
||||||
use servo_msg::compositor_msg::{ReadyState, RenderState};
|
use servo_msg::compositor_msg::{ReadyState, RenderState};
|
||||||
use servo_util::geometry::ScreenPx;
|
use servo_util::geometry::ScreenPx;
|
||||||
use std::fmt::{FormatError, Formatter, Show};
|
use std::fmt::{FormatError, Formatter, Show};
|
||||||
|
@ -60,7 +60,7 @@ pub enum WindowEvent {
|
||||||
/// Sent when the user quits the application
|
/// Sent when the user quits the application
|
||||||
QuitWindowEvent,
|
QuitWindowEvent,
|
||||||
/// Sent when a key input state changes
|
/// Sent when a key input state changes
|
||||||
KeyEvent(Key, KeyState),
|
KeyEvent(Key, KeyState, KeyModifiers),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Show for WindowEvent {
|
impl Show for WindowEvent {
|
||||||
|
|
|
@ -50,6 +50,7 @@ pub struct WindowSizeData {
|
||||||
pub device_pixel_ratio: ScaleFactor<ViewportPx, DevicePixel, f32>,
|
pub device_pixel_ratio: ScaleFactor<ViewportPx, DevicePixel, f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deriving(PartialEq)]
|
||||||
pub enum KeyState {
|
pub enum KeyState {
|
||||||
Pressed,
|
Pressed,
|
||||||
Released,
|
Released,
|
||||||
|
@ -181,6 +182,15 @@ pub enum Key {
|
||||||
KeyMenu,
|
KeyMenu,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
flags KeyModifiers: u8 {
|
||||||
|
const Shift = 0x01,
|
||||||
|
const Control = 0x02,
|
||||||
|
const Alt = 0x04,
|
||||||
|
const Super = 0x08,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Messages from the compositor and script to the constellation.
|
/// Messages from the compositor and script to the constellation.
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
ExitMsg,
|
ExitMsg,
|
||||||
|
@ -193,7 +203,7 @@ pub enum Msg {
|
||||||
NavigateMsg(NavigationDirection),
|
NavigateMsg(NavigationDirection),
|
||||||
RendererReadyMsg(PipelineId),
|
RendererReadyMsg(PipelineId),
|
||||||
ResizedWindowMsg(WindowSizeData),
|
ResizedWindowMsg(WindowSizeData),
|
||||||
KeyEvent(Key, KeyState),
|
KeyEvent(Key, KeyState, KeyModifiers),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Similar to net::resource_task::LoadData
|
/// Similar to net::resource_task::LoadData
|
||||||
|
|
|
@ -14,6 +14,7 @@ use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
||||||
use dom::event::{Event, KeyboardEventTypeId};
|
use dom::event::{Event, KeyboardEventTypeId};
|
||||||
use dom::uievent::UIEvent;
|
use dom::uievent::UIEvent;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
|
use servo_msg::constellation_msg;
|
||||||
use servo_util::str::DOMString;
|
use servo_util::str::DOMString;
|
||||||
use std::cell::{RefCell, Cell};
|
use std::cell::{RefCell, Cell};
|
||||||
|
|
||||||
|
@ -109,6 +110,32 @@ impl KeyboardEvent {
|
||||||
None, 0);
|
None, 0);
|
||||||
Ok(event)
|
Ok(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn key_properties(key: constellation_msg::Key) -> KeyEventProperties {
|
||||||
|
match key {
|
||||||
|
_ => KeyEventProperties {
|
||||||
|
key: "".to_string(),
|
||||||
|
code: "".to_string(),
|
||||||
|
location: 0,
|
||||||
|
char_code: None,
|
||||||
|
key_code: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct KeyEventProperties {
|
||||||
|
pub key: DOMString,
|
||||||
|
pub code: DOMString,
|
||||||
|
pub location: u32,
|
||||||
|
pub char_code: Option<u32>,
|
||||||
|
pub key_code: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyEventProperties {
|
||||||
|
pub fn is_printable(&self) -> bool {
|
||||||
|
self.char_code.is_some()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> KeyboardEventMethods for JSRef<'a, KeyboardEvent> {
|
impl<'a> KeyboardEventMethods for JSRef<'a, KeyboardEvent> {
|
||||||
|
|
|
@ -10,6 +10,7 @@ use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, Documen
|
||||||
use dom::bindings::codegen::Bindings::DOMRectBinding::DOMRectMethods;
|
use dom::bindings::codegen::Bindings::DOMRectBinding::DOMRectMethods;
|
||||||
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
|
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
|
||||||
use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods;
|
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::codegen::InheritTypes::{EventTargetCast, NodeCast, EventCast, ElementCast};
|
||||||
use dom::bindings::conversions;
|
use dom::bindings::conversions;
|
||||||
use dom::bindings::conversions::{FromJSValConvertible, Empty};
|
use dom::bindings::conversions::{FromJSValConvertible, Empty};
|
||||||
|
@ -23,6 +24,7 @@ use dom::element::{HTMLSelectElementTypeId, HTMLTextAreaElementTypeId, HTMLOptio
|
||||||
use dom::event::{Event, Bubbles, DoesNotBubble, Cancelable, NotCancelable};
|
use dom::event::{Event, Bubbles, DoesNotBubble, Cancelable, NotCancelable};
|
||||||
use dom::uievent::UIEvent;
|
use dom::uievent::UIEvent;
|
||||||
use dom::eventtarget::{EventTarget, EventTargetHelpers};
|
use dom::eventtarget::{EventTarget, EventTargetHelpers};
|
||||||
|
use dom::keyboardevent::KeyboardEvent;
|
||||||
use dom::node;
|
use dom::node;
|
||||||
use dom::node::{ElementNodeTypeId, Node, NodeHelpers};
|
use dom::node::{ElementNodeTypeId, Node, NodeHelpers};
|
||||||
use dom::window::{Window, WindowHelpers};
|
use dom::window::{Window, WindowHelpers};
|
||||||
|
@ -46,7 +48,9 @@ use script_traits::{ScriptControlChan, ReflowCompleteMsg, UntrustedNodeAddress,
|
||||||
use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading};
|
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};
|
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_msg::constellation_msg;
|
||||||
use servo_net::image_cache_task::ImageCacheTask;
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
use servo_net::resource_task::ResourceTask;
|
use servo_net::resource_task::ResourceTask;
|
||||||
|
@ -908,12 +912,58 @@ impl ScriptTask {
|
||||||
self.handle_mouse_move_event(pipeline_id, point);
|
self.handle_mouse_move_event(pipeline_id, point);
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent(key, state) => {
|
KeyEvent(key, state, modifiers) => {
|
||||||
println!("key {} is {}", key as int, state as int);
|
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) {
|
||||||
|
println!("key {} is {}", key as int, state as int);
|
||||||
|
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 body = doc.GetBody().root();
|
||||||
|
|
||||||
|
let target: JSRef<EventTarget> = match body {
|
||||||
|
Some(body) => EventTargetCast::from_ref(*body),
|
||||||
|
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);
|
||||||
|
|
||||||
|
let event = KeyboardEvent::new(*window, ev_type, true, true, Some(*window), 0,
|
||||||
|
props.key.clone(), props.code.clone(), props.location,
|
||||||
|
is_repeating, is_composing, ctrl, alt, shift, meta,
|
||||||
|
props.char_code, props.key_code).root();
|
||||||
|
let _ = target.DispatchEvent(EventCast::from_ref(*event));
|
||||||
|
|
||||||
|
if state != Released && props.is_printable() {
|
||||||
|
let event = KeyboardEvent::new(*window, "keypress".to_string(), true, true, Some(*window),
|
||||||
|
0, props.key.clone(), props.code.clone(), props.location,
|
||||||
|
is_repeating, is_composing, ctrl, alt, shift, meta,
|
||||||
|
props.char_code, props.key_code).root();
|
||||||
|
let _ = target.DispatchEvent(EventCast::from_ref(*event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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) {
|
||||||
|
|
|
@ -25,7 +25,7 @@ extern crate serialize;
|
||||||
use devtools_traits::DevtoolsControlChan;
|
use devtools_traits::DevtoolsControlChan;
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, Failure, WindowSizeData};
|
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, Failure, WindowSizeData};
|
||||||
use servo_msg::constellation_msg::{LoadData, SubpageId, Key, KeyState};
|
use servo_msg::constellation_msg::{LoadData, SubpageId, Key, KeyState, KeyModifiers};
|
||||||
use servo_msg::compositor_msg::ScriptListener;
|
use servo_msg::compositor_msg::ScriptListener;
|
||||||
use servo_net::image_cache_task::ImageCacheTask;
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
use servo_net::resource_task::ResourceTask;
|
use servo_net::resource_task::ResourceTask;
|
||||||
|
@ -75,7 +75,7 @@ pub enum CompositorEvent {
|
||||||
MouseDownEvent(uint, Point2D<f32>),
|
MouseDownEvent(uint, Point2D<f32>),
|
||||||
MouseUpEvent(uint, Point2D<f32>),
|
MouseUpEvent(uint, Point2D<f32>),
|
||||||
MouseMoveEvent(Point2D<f32>),
|
MouseMoveEvent(Point2D<f32>),
|
||||||
KeyEvent(Key, KeyState),
|
KeyEvent(Key, KeyState, KeyModifiers),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An opaque wrapper around script<->layout channels to avoid leaking message types into
|
/// An opaque wrapper around script<->layout channels to avoid leaking message types into
|
||||||
|
|
|
@ -216,7 +216,8 @@ impl Window {
|
||||||
glfw::Release => constellation_msg::Released,
|
glfw::Release => constellation_msg::Released,
|
||||||
glfw::Repeat => constellation_msg::Repeated,
|
glfw::Repeat => constellation_msg::Repeated,
|
||||||
};
|
};
|
||||||
self.event_queue.borrow_mut().push(KeyEvent(key, state));
|
let modifiers = glfw_mods_to_script_mods(mods);
|
||||||
|
self.event_queue.borrow_mut().push(KeyEvent(key, state, modifiers));
|
||||||
},
|
},
|
||||||
glfw::FramebufferSizeEvent(width, height) => {
|
glfw::FramebufferSizeEvent(width, height) => {
|
||||||
self.event_queue.borrow_mut().push(
|
self.event_queue.borrow_mut().push(
|
||||||
|
@ -436,6 +437,23 @@ extern "C" fn on_framebuffer_size(_glfw_window: *mut glfw::ffi::GLFWwindow,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn glfw_mods_to_script_mods(mods: glfw::Modifiers) -> constellation_msg::KeyModifiers {
|
||||||
|
let mut result = constellation_msg::KeyModifiers::from_bits(0).unwrap();
|
||||||
|
if mods.contains(glfw::Shift) {
|
||||||
|
result.insert(constellation_msg::Shift);
|
||||||
|
}
|
||||||
|
if mods.contains(glfw::Alt) {
|
||||||
|
result.insert(constellation_msg::Alt);
|
||||||
|
}
|
||||||
|
if mods.contains(glfw::Control) {
|
||||||
|
result.insert(constellation_msg::Control);
|
||||||
|
}
|
||||||
|
if mods.contains(glfw::Super) {
|
||||||
|
result.insert(constellation_msg::Super);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
fn glfw_key_to_script_key(key: glfw::Key) -> constellation_msg::Key {
|
fn glfw_key_to_script_key(key: glfw::Key) -> constellation_msg::Key {
|
||||||
match key {
|
match key {
|
||||||
glfw::KeySpace => constellation_msg::KeySpace,
|
glfw::KeySpace => constellation_msg::KeySpace,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue