mirror of
https://github.com/servo/servo.git
synced 2025-06-26 18:14:34 +01:00
[WebDriver] Add synchronization for key action (#37403)
Implement action synchronization for key event. Previously only done for pointer https://github.com/servo/servo/pull/36932 and wheel https://github.com/servo/servo/pull/37260. --------- Signed-off-by: PotatoCP <kenzieradityatirtarahardja18@gmail.com>
This commit is contained in:
parent
f97cdb4d12
commit
cdc8b45965
16 changed files with 171 additions and 118 deletions
|
@ -130,9 +130,9 @@ use embedder_traits::user_content_manager::UserContentManager;
|
||||||
use embedder_traits::{
|
use embedder_traits::{
|
||||||
AnimationState, CompositorHitTestResult, Cursor, EmbedderMsg, EmbedderProxy,
|
AnimationState, CompositorHitTestResult, Cursor, EmbedderMsg, EmbedderProxy,
|
||||||
FocusSequenceNumber, ImeEvent, InputEvent, JSValue, JavaScriptEvaluationError,
|
FocusSequenceNumber, ImeEvent, InputEvent, JSValue, JavaScriptEvaluationError,
|
||||||
JavaScriptEvaluationId, MediaSessionActionType, MediaSessionEvent, MediaSessionPlaybackState,
|
JavaScriptEvaluationId, KeyboardEvent, MediaSessionActionType, MediaSessionEvent,
|
||||||
MouseButton, MouseButtonAction, MouseButtonEvent, Theme, ViewportDetails, WebDriverCommandMsg,
|
MediaSessionPlaybackState, MouseButton, MouseButtonAction, MouseButtonEvent, Theme,
|
||||||
WebDriverCommandResponse, WebDriverLoadStatus,
|
ViewportDetails, WebDriverCommandMsg, WebDriverCommandResponse, WebDriverLoadStatus,
|
||||||
};
|
};
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
use euclid::default::Size2D as UntypedSize2D;
|
use euclid::default::Size2D as UntypedSize2D;
|
||||||
|
@ -141,7 +141,7 @@ use ipc_channel::Error as IpcError;
|
||||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||||
use ipc_channel::router::ROUTER;
|
use ipc_channel::router::ROUTER;
|
||||||
use keyboard_types::webdriver::Event as WebDriverInputEvent;
|
use keyboard_types::webdriver::Event as WebDriverInputEvent;
|
||||||
use keyboard_types::{Key, KeyState, KeyboardEvent, Modifiers};
|
use keyboard_types::{Key, KeyState, Modifiers};
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
use media::WindowGLContext;
|
use media::WindowGLContext;
|
||||||
use net_traits::pub_domains::reg_host;
|
use net_traits::pub_domains::reg_host;
|
||||||
|
@ -3034,13 +3034,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_active_keybord_modifiers(&mut self, event: &KeyboardEvent) {
|
fn update_active_keybord_modifiers(&mut self, event: &KeyboardEvent) {
|
||||||
self.active_keyboard_modifiers = event.modifiers;
|
self.active_keyboard_modifiers = event.event.modifiers;
|
||||||
|
|
||||||
// `KeyboardEvent::modifiers` contains the pre-existing modifiers before this key was
|
// `KeyboardEvent::modifiers` contains the pre-existing modifiers before this key was
|
||||||
// either pressed or released, but `active_keyboard_modifiers` should track the subsequent
|
// either pressed or released, but `active_keyboard_modifiers` should track the subsequent
|
||||||
// state. If this event will update that state, we need to ensure that we are tracking what
|
// state. If this event will update that state, we need to ensure that we are tracking what
|
||||||
// the event changes.
|
// the event changes.
|
||||||
let modified_modifier = match event.key {
|
let modified_modifier = match event.event.key {
|
||||||
Key::Alt => Modifiers::ALT,
|
Key::Alt => Modifiers::ALT,
|
||||||
Key::AltGraph => Modifiers::ALT_GRAPH,
|
Key::AltGraph => Modifiers::ALT_GRAPH,
|
||||||
Key::CapsLock => Modifiers::CAPS_LOCK,
|
Key::CapsLock => Modifiers::CAPS_LOCK,
|
||||||
|
@ -3059,7 +3059,7 @@ where
|
||||||
Key::Super => Modifiers::META,
|
Key::Super => Modifiers::META,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
match event.state {
|
match event.event.state {
|
||||||
KeyState::Down => self.active_keyboard_modifiers.insert(modified_modifier),
|
KeyState::Down => self.active_keyboard_modifiers.insert(modified_modifier),
|
||||||
KeyState::Up => self.active_keyboard_modifiers.remove(modified_modifier),
|
KeyState::Up => self.active_keyboard_modifiers.remove(modified_modifier),
|
||||||
}
|
}
|
||||||
|
@ -4840,7 +4840,7 @@ where
|
||||||
pressed_mouse_buttons: self.pressed_mouse_buttons,
|
pressed_mouse_buttons: self.pressed_mouse_buttons,
|
||||||
active_keyboard_modifiers: event.modifiers,
|
active_keyboard_modifiers: event.modifiers,
|
||||||
hit_test_result: None,
|
hit_test_result: None,
|
||||||
event: InputEvent::Keyboard(event),
|
event: InputEvent::Keyboard(KeyboardEvent::new(event)),
|
||||||
},
|
},
|
||||||
WebDriverInputEvent::Composition(event) => ConstellationInputEvent {
|
WebDriverInputEvent::Composition(event) => ConstellationInputEvent {
|
||||||
pressed_mouse_buttons: self.pressed_mouse_buttons,
|
pressed_mouse_buttons: self.pressed_mouse_buttons,
|
||||||
|
@ -4855,7 +4855,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
WebDriverCommandMsg::KeyboardAction(browsing_context_id, event) => {
|
WebDriverCommandMsg::KeyboardAction(
|
||||||
|
browsing_context_id,
|
||||||
|
key_event,
|
||||||
|
msg_id,
|
||||||
|
response_sender,
|
||||||
|
) => {
|
||||||
|
self.webdriver.input_command_response_sender = Some(response_sender);
|
||||||
|
|
||||||
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
|
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
|
||||||
Some(browsing_context) => browsing_context.pipeline_id,
|
Some(browsing_context) => browsing_context.pipeline_id,
|
||||||
None => {
|
None => {
|
||||||
|
@ -4866,13 +4873,15 @@ where
|
||||||
Some(pipeline) => pipeline.event_loop.clone(),
|
Some(pipeline) => pipeline.event_loop.clone(),
|
||||||
None => return warn!("{}: KeyboardAction after closure", pipeline_id),
|
None => return warn!("{}: KeyboardAction after closure", pipeline_id),
|
||||||
};
|
};
|
||||||
|
let event = InputEvent::Keyboard(KeyboardEvent::new(key_event.clone()))
|
||||||
|
.with_webdriver_message_id(msg_id);
|
||||||
let control_msg = ScriptThreadMessage::SendInputEvent(
|
let control_msg = ScriptThreadMessage::SendInputEvent(
|
||||||
pipeline_id,
|
pipeline_id,
|
||||||
ConstellationInputEvent {
|
ConstellationInputEvent {
|
||||||
pressed_mouse_buttons: self.pressed_mouse_buttons,
|
pressed_mouse_buttons: self.pressed_mouse_buttons,
|
||||||
active_keyboard_modifiers: event.modifiers,
|
active_keyboard_modifiers: key_event.modifiers,
|
||||||
hit_test_result: None,
|
hit_test_result: None,
|
||||||
event: InputEvent::Keyboard(event),
|
event,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if let Err(e) = event_loop.send(control_msg) {
|
if let Err(e) = event_loop.send(control_msg) {
|
||||||
|
|
|
@ -2365,7 +2365,7 @@ impl Document {
|
||||||
/// The entry point for all key processing for web content
|
/// The entry point for all key processing for web content
|
||||||
pub(crate) fn dispatch_key_event(
|
pub(crate) fn dispatch_key_event(
|
||||||
&self,
|
&self,
|
||||||
keyboard_event: ::keyboard_types::KeyboardEvent,
|
keyboard_event: ::embedder_traits::KeyboardEvent,
|
||||||
can_gc: CanGc,
|
can_gc: CanGc,
|
||||||
) {
|
) {
|
||||||
let focused = self.get_focused_element();
|
let focused = self.get_focused_element();
|
||||||
|
@ -2379,19 +2379,19 @@ impl Document {
|
||||||
|
|
||||||
let keyevent = KeyboardEvent::new(
|
let keyevent = KeyboardEvent::new(
|
||||||
&self.window,
|
&self.window,
|
||||||
DOMString::from(keyboard_event.state.to_string()),
|
DOMString::from(keyboard_event.event.state.to_string()),
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
Some(&self.window),
|
Some(&self.window),
|
||||||
0,
|
0,
|
||||||
keyboard_event.key.clone(),
|
keyboard_event.event.key.clone(),
|
||||||
DOMString::from(keyboard_event.code.to_string()),
|
DOMString::from(keyboard_event.event.code.to_string()),
|
||||||
keyboard_event.location as u32,
|
keyboard_event.event.location as u32,
|
||||||
keyboard_event.repeat,
|
keyboard_event.event.repeat,
|
||||||
keyboard_event.is_composing,
|
keyboard_event.event.is_composing,
|
||||||
keyboard_event.modifiers,
|
keyboard_event.event.modifiers,
|
||||||
0,
|
0,
|
||||||
keyboard_event.key.legacy_keycode(),
|
keyboard_event.event.key.legacy_keycode(),
|
||||||
can_gc,
|
can_gc,
|
||||||
);
|
);
|
||||||
let event = keyevent.upcast::<Event>();
|
let event = keyevent.upcast::<Event>();
|
||||||
|
@ -2402,9 +2402,9 @@ impl Document {
|
||||||
// it MUST prevent the respective beforeinput and input
|
// it MUST prevent the respective beforeinput and input
|
||||||
// (and keypress if supported) events from being generated
|
// (and keypress if supported) events from being generated
|
||||||
// TODO: keypress should be deprecated and superceded by beforeinput
|
// TODO: keypress should be deprecated and superceded by beforeinput
|
||||||
if keyboard_event.state == KeyState::Down &&
|
if keyboard_event.event.state == KeyState::Down &&
|
||||||
is_character_value_key(&(keyboard_event.key)) &&
|
is_character_value_key(&(keyboard_event.event.key)) &&
|
||||||
!keyboard_event.is_composing &&
|
!keyboard_event.event.is_composing &&
|
||||||
cancel_state != EventDefault::Prevented
|
cancel_state != EventDefault::Prevented
|
||||||
{
|
{
|
||||||
// https://w3c.github.io/uievents/#keypress-event-order
|
// https://w3c.github.io/uievents/#keypress-event-order
|
||||||
|
@ -2415,13 +2415,13 @@ impl Document {
|
||||||
true,
|
true,
|
||||||
Some(&self.window),
|
Some(&self.window),
|
||||||
0,
|
0,
|
||||||
keyboard_event.key.clone(),
|
keyboard_event.event.key.clone(),
|
||||||
DOMString::from(keyboard_event.code.to_string()),
|
DOMString::from(keyboard_event.event.code.to_string()),
|
||||||
keyboard_event.location as u32,
|
keyboard_event.event.location as u32,
|
||||||
keyboard_event.repeat,
|
keyboard_event.event.repeat,
|
||||||
keyboard_event.is_composing,
|
keyboard_event.event.is_composing,
|
||||||
keyboard_event.modifiers,
|
keyboard_event.event.modifiers,
|
||||||
keyboard_event.key.legacy_charcode(),
|
keyboard_event.event.key.legacy_charcode(),
|
||||||
0,
|
0,
|
||||||
can_gc,
|
can_gc,
|
||||||
);
|
);
|
||||||
|
@ -2439,8 +2439,8 @@ impl Document {
|
||||||
// however *when* we do it is up to us.
|
// however *when* we do it is up to us.
|
||||||
// Here, we're dispatching it after the key event so the script has a chance to cancel it
|
// Here, we're 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
|
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=27337
|
||||||
if (keyboard_event.key == Key::Enter || keyboard_event.code == Code::Space) &&
|
if (keyboard_event.event.key == Key::Enter || keyboard_event.event.code == Code::Space) &&
|
||||||
keyboard_event.state == KeyState::Up
|
keyboard_event.event.state == KeyState::Up
|
||||||
{
|
{
|
||||||
if let Some(elem) = target.downcast::<Element>() {
|
if let Some(elem) = target.downcast::<Element>() {
|
||||||
elem.upcast::<Node>()
|
elem.upcast::<Node>()
|
||||||
|
|
|
@ -85,7 +85,9 @@ use gleam::gl::RENDERER;
|
||||||
use ipc_channel::ipc::{self, IpcSender};
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
use ipc_channel::router::ROUTER;
|
use ipc_channel::router::ROUTER;
|
||||||
use javascript_evaluator::JavaScriptEvaluator;
|
use javascript_evaluator::JavaScriptEvaluator;
|
||||||
pub use keyboard_types::*;
|
pub use keyboard_types::{
|
||||||
|
Code, CompositionEvent, CompositionState, Key, KeyState, Location, Modifiers,
|
||||||
|
};
|
||||||
use layout::LayoutFactoryImpl;
|
use layout::LayoutFactoryImpl;
|
||||||
use log::{Log, Metadata, Record, debug, warn};
|
use log::{Log, Metadata, Record, debug, warn};
|
||||||
use media::{GlApi, NativeDisplay, WindowGLContext};
|
use media::{GlApi, NativeDisplay, WindowGLContext};
|
||||||
|
|
|
@ -8,12 +8,11 @@ use base::id::PipelineId;
|
||||||
use constellation_traits::EmbedderToConstellationMessage;
|
use constellation_traits::EmbedderToConstellationMessage;
|
||||||
use embedder_traits::{
|
use embedder_traits::{
|
||||||
AllowOrDeny, AuthenticationResponse, ContextMenuResult, Cursor, FilterPattern,
|
AllowOrDeny, AuthenticationResponse, ContextMenuResult, Cursor, FilterPattern,
|
||||||
GamepadHapticEffectType, InputMethodType, LoadStatus, MediaSessionEvent, Notification,
|
GamepadHapticEffectType, InputMethodType, KeyboardEvent, LoadStatus, MediaSessionEvent,
|
||||||
PermissionFeature, RgbColor, ScreenGeometry, SelectElementOptionOrOptgroup, SimpleDialog,
|
Notification, PermissionFeature, RgbColor, ScreenGeometry, SelectElementOptionOrOptgroup,
|
||||||
WebResourceRequest, WebResourceResponse, WebResourceResponseMsg,
|
SimpleDialog, WebResourceRequest, WebResourceResponse, WebResourceResponseMsg,
|
||||||
};
|
};
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use keyboard_types::KeyboardEvent;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
|
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use keyboard_types::{CompositionEvent, KeyboardEvent};
|
use keyboard_types::{Code, CompositionEvent, Key, KeyState, Location, Modifiers};
|
||||||
use log::error;
|
use log::error;
|
||||||
use malloc_size_of_derive::MallocSizeOf;
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -53,7 +53,7 @@ impl InputEvent {
|
||||||
InputEvent::EditingAction(..) => None,
|
InputEvent::EditingAction(..) => None,
|
||||||
InputEvent::Gamepad(..) => None,
|
InputEvent::Gamepad(..) => None,
|
||||||
InputEvent::Ime(..) => None,
|
InputEvent::Ime(..) => None,
|
||||||
InputEvent::Keyboard(..) => None,
|
InputEvent::Keyboard(event) => event.webdriver_id,
|
||||||
InputEvent::MouseButton(event) => event.webdriver_id,
|
InputEvent::MouseButton(event) => event.webdriver_id,
|
||||||
InputEvent::MouseMove(event) => event.webdriver_id,
|
InputEvent::MouseMove(event) => event.webdriver_id,
|
||||||
InputEvent::Touch(..) => None,
|
InputEvent::Touch(..) => None,
|
||||||
|
@ -67,7 +67,9 @@ impl InputEvent {
|
||||||
InputEvent::EditingAction(..) => {},
|
InputEvent::EditingAction(..) => {},
|
||||||
InputEvent::Gamepad(..) => {},
|
InputEvent::Gamepad(..) => {},
|
||||||
InputEvent::Ime(..) => {},
|
InputEvent::Ime(..) => {},
|
||||||
InputEvent::Keyboard(..) => {},
|
InputEvent::Keyboard(ref mut event) => {
|
||||||
|
event.webdriver_id = webdriver_id;
|
||||||
|
},
|
||||||
InputEvent::MouseButton(ref mut event) => {
|
InputEvent::MouseButton(ref mut event) => {
|
||||||
event.webdriver_id = webdriver_id;
|
event.webdriver_id = webdriver_id;
|
||||||
},
|
},
|
||||||
|
@ -85,6 +87,51 @@ impl InputEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Recreate KeyboardEvent from keyboard_types to pair it with webdriver_id,
|
||||||
|
/// which is used for webdriver action synchronization.
|
||||||
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||||
|
pub struct KeyboardEvent {
|
||||||
|
pub event: ::keyboard_types::KeyboardEvent,
|
||||||
|
webdriver_id: Option<WebDriverMessageId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyboardEvent {
|
||||||
|
pub fn new(keyboard_event: ::keyboard_types::KeyboardEvent) -> Self {
|
||||||
|
Self {
|
||||||
|
event: keyboard_event,
|
||||||
|
webdriver_id: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_without_event(
|
||||||
|
state: KeyState,
|
||||||
|
key: Key,
|
||||||
|
code: Code,
|
||||||
|
location: Location,
|
||||||
|
modifiers: Modifiers,
|
||||||
|
repeat: bool,
|
||||||
|
is_composing: bool,
|
||||||
|
) -> Self {
|
||||||
|
Self::new(::keyboard_types::KeyboardEvent {
|
||||||
|
state,
|
||||||
|
key,
|
||||||
|
code,
|
||||||
|
location,
|
||||||
|
modifiers,
|
||||||
|
repeat,
|
||||||
|
is_composing,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_state_and_key(state: KeyState, key: Key) -> Self {
|
||||||
|
Self::new(::keyboard_types::KeyboardEvent {
|
||||||
|
state,
|
||||||
|
key,
|
||||||
|
..::keyboard_types::KeyboardEvent::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||||
pub struct MouseButtonEvent {
|
pub struct MouseButtonEvent {
|
||||||
pub action: MouseButtonAction,
|
pub action: MouseButtonAction,
|
||||||
|
|
|
@ -25,7 +25,6 @@ use crossbeam_channel::Sender;
|
||||||
use euclid::{Scale, Size2D};
|
use euclid::{Scale, Size2D};
|
||||||
use http::{HeaderMap, Method, StatusCode};
|
use http::{HeaderMap, Method, StatusCode};
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
pub use keyboard_types::{KeyboardEvent, Modifiers};
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use malloc_size_of::malloc_size_of_is_0;
|
use malloc_size_of::malloc_size_of_is_0;
|
||||||
use malloc_size_of_derive::MallocSizeOf;
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
|
|
|
@ -42,7 +42,13 @@ pub enum WebDriverCommandMsg {
|
||||||
/// Act as if keys were pressed in the browsing context with the given ID.
|
/// Act as if keys were pressed in the browsing context with the given ID.
|
||||||
SendKeys(BrowsingContextId, Vec<WebDriverInputEvent>),
|
SendKeys(BrowsingContextId, Vec<WebDriverInputEvent>),
|
||||||
/// Act as if keys were pressed or release in the browsing context with the given ID.
|
/// Act as if keys were pressed or release in the browsing context with the given ID.
|
||||||
KeyboardAction(BrowsingContextId, KeyboardEvent),
|
KeyboardAction(
|
||||||
|
BrowsingContextId,
|
||||||
|
KeyboardEvent,
|
||||||
|
// Should never be None.
|
||||||
|
Option<WebDriverMessageId>,
|
||||||
|
IpcSender<WebDriverCommandResponse>,
|
||||||
|
),
|
||||||
/// Act as if the mouse was clicked in the browsing context with the given ID.
|
/// Act as if the mouse was clicked in the browsing context with the given ID.
|
||||||
MouseButtonAction(
|
MouseButtonAction(
|
||||||
WebViewId,
|
WebViewId,
|
||||||
|
|
|
@ -157,7 +157,7 @@ impl Handler {
|
||||||
// Step 1.4. Wait for
|
// Step 1.4. Wait for
|
||||||
// The user agent event loop has spun enough times to process the DOM events
|
// The user agent event loop has spun enough times to process the DOM events
|
||||||
// generated by the last invocation of the dispatch tick actions steps.
|
// generated by the last invocation of the dispatch tick actions steps.
|
||||||
self.wait_for_user_agent_handling_complete(tick_actions)?;
|
self.wait_for_user_agent_handling_complete()?;
|
||||||
// At least tick duration milliseconds have passed.
|
// At least tick duration milliseconds have passed.
|
||||||
let elapsed = now.elapsed();
|
let elapsed = now.elapsed();
|
||||||
if elapsed.as_millis() < tick_duration as u128 {
|
if elapsed.as_millis() < tick_duration as u128 {
|
||||||
|
@ -171,29 +171,13 @@ impl Handler {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_for_user_agent_handling_complete(
|
fn wait_for_user_agent_handling_complete(&self) -> Result<(), ErrorStatus> {
|
||||||
&self,
|
|
||||||
tick_actions: &TickActions,
|
|
||||||
) -> Result<(), ErrorStatus> {
|
|
||||||
// TODO: Add matches! for key actions
|
|
||||||
// after implmenting webdriver id for key events.
|
|
||||||
let count_non_null_actions_in_tick = tick_actions
|
|
||||||
.iter()
|
|
||||||
.filter(|(_, action)| {
|
|
||||||
matches!(
|
|
||||||
action,
|
|
||||||
ActionItem::Pointer(PointerActionItem::Pointer(_)) |
|
|
||||||
ActionItem::Wheel(WheelActionItem::Wheel(_))
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.count();
|
|
||||||
|
|
||||||
// To ensure we wait for all events to be processed, only the last event
|
// To ensure we wait for all events to be processed, only the last event
|
||||||
// in each tick action step holds the message id.
|
// in each tick action step holds the message id.
|
||||||
// Whenever a new event is generated, the message id is passed to it.
|
// Whenever a new event is generated, the message id is passed to it.
|
||||||
//
|
//
|
||||||
// Wait for count_non_null_actions_in_tick number of responses
|
// Wait for num_pending_actions number of responses
|
||||||
for _ in 0..count_non_null_actions_in_tick {
|
for _ in 0..self.num_pending_actions.get() {
|
||||||
match self.constellation_receiver.recv() {
|
match self.constellation_receiver.recv() {
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
let current_waiting_id = self
|
let current_waiting_id = self
|
||||||
|
@ -213,6 +197,8 @@ impl Handler {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.num_pending_actions.set(0);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,9 +306,13 @@ impl Handler {
|
||||||
let keyboard_event = key_input_state.dispatch_keydown(raw_key);
|
let keyboard_event = key_input_state.dispatch_keydown(raw_key);
|
||||||
|
|
||||||
// Step 12
|
// Step 12
|
||||||
|
self.increment_num_pending_actions();
|
||||||
|
let msg_id = self.current_action_id.get();
|
||||||
let cmd_msg = WebDriverCommandMsg::KeyboardAction(
|
let cmd_msg = WebDriverCommandMsg::KeyboardAction(
|
||||||
self.session().unwrap().browsing_context_id,
|
self.session().unwrap().browsing_context_id,
|
||||||
keyboard_event,
|
keyboard_event,
|
||||||
|
msg_id,
|
||||||
|
self.constellation_sender.clone(),
|
||||||
);
|
);
|
||||||
self.constellation_chan
|
self.constellation_chan
|
||||||
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
|
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
|
||||||
|
@ -342,9 +332,13 @@ impl Handler {
|
||||||
|
|
||||||
if let Some(keyboard_event) = key_input_state.dispatch_keyup(raw_key) {
|
if let Some(keyboard_event) = key_input_state.dispatch_keyup(raw_key) {
|
||||||
// Step 12
|
// Step 12
|
||||||
|
self.increment_num_pending_actions();
|
||||||
|
let msg_id = self.current_action_id.get();
|
||||||
let cmd_msg = WebDriverCommandMsg::KeyboardAction(
|
let cmd_msg = WebDriverCommandMsg::KeyboardAction(
|
||||||
self.session().unwrap().browsing_context_id,
|
self.session().unwrap().browsing_context_id,
|
||||||
keyboard_event,
|
keyboard_event,
|
||||||
|
msg_id,
|
||||||
|
self.constellation_sender.clone(),
|
||||||
);
|
);
|
||||||
self.constellation_chan
|
self.constellation_chan
|
||||||
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
|
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
|
||||||
|
@ -367,6 +361,7 @@ impl Handler {
|
||||||
}
|
}
|
||||||
pointer_input_state.pressed.insert(action.button);
|
pointer_input_state.pressed.insert(action.button);
|
||||||
|
|
||||||
|
self.increment_num_pending_actions();
|
||||||
let msg_id = self.current_action_id.get();
|
let msg_id = self.current_action_id.get();
|
||||||
let cmd_msg = WebDriverCommandMsg::MouseButtonAction(
|
let cmd_msg = WebDriverCommandMsg::MouseButtonAction(
|
||||||
session.webview_id,
|
session.webview_id,
|
||||||
|
@ -397,6 +392,7 @@ impl Handler {
|
||||||
}
|
}
|
||||||
pointer_input_state.pressed.remove(&action.button);
|
pointer_input_state.pressed.remove(&action.button);
|
||||||
|
|
||||||
|
self.increment_num_pending_actions();
|
||||||
let msg_id = self.current_action_id.get();
|
let msg_id = self.current_action_id.get();
|
||||||
let cmd_msg = WebDriverCommandMsg::MouseButtonAction(
|
let cmd_msg = WebDriverCommandMsg::MouseButtonAction(
|
||||||
session.webview_id,
|
session.webview_id,
|
||||||
|
@ -523,6 +519,7 @@ impl Handler {
|
||||||
if x != current_x || y != current_y || last {
|
if x != current_x || y != current_y || last {
|
||||||
// Step 7.2
|
// Step 7.2
|
||||||
let msg_id = if last {
|
let msg_id = if last {
|
||||||
|
self.increment_num_pending_actions();
|
||||||
self.current_action_id.get()
|
self.current_action_id.get()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -660,6 +657,7 @@ impl Handler {
|
||||||
if delta_x != 0 || delta_y != 0 || last {
|
if delta_x != 0 || delta_y != 0 || last {
|
||||||
// Perform implementation-specific action dispatch steps
|
// Perform implementation-specific action dispatch steps
|
||||||
let msg_id = if last {
|
let msg_id = if last {
|
||||||
|
self.increment_num_pending_actions();
|
||||||
self.current_action_id.get()
|
self.current_action_id.get()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -227,6 +227,9 @@ struct Handler {
|
||||||
current_action_id: Cell<Option<WebDriverMessageId>>,
|
current_action_id: Cell<Option<WebDriverMessageId>>,
|
||||||
|
|
||||||
resize_timeout: u32,
|
resize_timeout: u32,
|
||||||
|
|
||||||
|
/// Number of pending actions of which WebDriver is waiting for responses.
|
||||||
|
num_pending_actions: Cell<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
@ -459,9 +462,16 @@ impl Handler {
|
||||||
id_generator: WebDriverMessageIdGenerator::new(),
|
id_generator: WebDriverMessageIdGenerator::new(),
|
||||||
current_action_id: Cell::new(None),
|
current_action_id: Cell::new(None),
|
||||||
resize_timeout: 500,
|
resize_timeout: 500,
|
||||||
|
num_pending_actions: Cell::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn increment_num_pending_actions(&self) {
|
||||||
|
// Increase the num_pending_actions by one every time we dispatch non null actions.
|
||||||
|
self.num_pending_actions
|
||||||
|
.set(self.num_pending_actions.get() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
fn focus_webview_id(&self) -> WebDriverResult<WebViewId> {
|
fn focus_webview_id(&self) -> WebDriverResult<WebViewId> {
|
||||||
debug!("Getting focused context.");
|
debug!("Getting focused context.");
|
||||||
let (sender, receiver) = ipc::channel().unwrap();
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use euclid::Vector2D;
|
use euclid::Vector2D;
|
||||||
use keyboard_types::{Key, KeyboardEvent, Modifiers, ShortcutMatcher};
|
use keyboard_types::{Key, Modifiers, ShortcutMatcher};
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use servo::base::id::WebViewId;
|
use servo::base::id::WebViewId;
|
||||||
use servo::config::{opts, pref};
|
use servo::config::{opts, pref};
|
||||||
|
@ -17,8 +17,8 @@ use servo::webrender_api::ScrollLocation;
|
||||||
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize};
|
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize};
|
||||||
use servo::{
|
use servo::{
|
||||||
AllowOrDenyRequest, AuthenticationRequest, FilterPattern, FormControl, GamepadHapticEffectType,
|
AllowOrDenyRequest, AuthenticationRequest, FilterPattern, FormControl, GamepadHapticEffectType,
|
||||||
LoadStatus, PermissionRequest, Servo, ServoDelegate, ServoError, SimpleDialog, TouchEventType,
|
KeyboardEvent, LoadStatus, PermissionRequest, Servo, ServoDelegate, ServoError, SimpleDialog,
|
||||||
WebView, WebViewBuilder, WebViewDelegate,
|
TouchEventType, WebView, WebViewBuilder, WebViewDelegate,
|
||||||
};
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -314,7 +314,7 @@ impl RunningAppState {
|
||||||
/// Handle servoshell key bindings that may have been prevented by the page in the focused webview.
|
/// Handle servoshell key bindings that may have been prevented by the page in the focused webview.
|
||||||
fn handle_overridable_key_bindings(&self, webview: ::servo::WebView, event: KeyboardEvent) {
|
fn handle_overridable_key_bindings(&self, webview: ::servo::WebView, event: KeyboardEvent) {
|
||||||
let origin = webview.rect().min.ceil().to_i32();
|
let origin = webview.rect().min.ceil().to_i32();
|
||||||
ShortcutMatcher::from_event(event)
|
ShortcutMatcher::from_event(event.event)
|
||||||
.shortcut(CMD_OR_CONTROL, '=', || {
|
.shortcut(CMD_OR_CONTROL, '=', || {
|
||||||
webview.set_zoom(1.1);
|
webview.set_zoom(1.1);
|
||||||
})
|
})
|
||||||
|
|
|
@ -184,16 +184,16 @@ impl Window {
|
||||||
// no keyboard event is emitted. A dummy event is created in this case.
|
// no keyboard event is emitted. A dummy event is created in this case.
|
||||||
(KeyboardEvent::default(), None)
|
(KeyboardEvent::default(), None)
|
||||||
};
|
};
|
||||||
event.key = Key::Character(character.to_string());
|
event.event.key = Key::Character(character.to_string());
|
||||||
|
|
||||||
if event.state == KeyState::Down {
|
if event.event.state == KeyState::Down {
|
||||||
// Ensure that when we receive a keyup event from winit, we are able
|
// Ensure that when we receive a keyup event from winit, we are able
|
||||||
// to infer that it's related to this character and set the event
|
// to infer that it's related to this character and set the event
|
||||||
// properties appropriately.
|
// properties appropriately.
|
||||||
if let Some(key_code) = key_code {
|
if let Some(key_code) = key_code {
|
||||||
self.keys_down
|
self.keys_down
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.insert(key_code, event.key.clone());
|
.insert(key_code, event.event.key.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,20 +223,24 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if keyboard_event.state == KeyState::Down && keyboard_event.key == Key::Unidentified {
|
if keyboard_event.event.state == KeyState::Down &&
|
||||||
|
keyboard_event.event.key == Key::Unidentified
|
||||||
|
{
|
||||||
// If pressed and probably printable, we expect a ReceivedCharacter event.
|
// If pressed and probably printable, we expect a ReceivedCharacter event.
|
||||||
// Wait for that to be received and don't queue any event right now.
|
// Wait for that to be received and don't queue any event right now.
|
||||||
self.last_pressed
|
self.last_pressed
|
||||||
.set(Some((keyboard_event, Some(winit_event.logical_key))));
|
.set(Some((keyboard_event, Some(winit_event.logical_key))));
|
||||||
return;
|
return;
|
||||||
} else if keyboard_event.state == KeyState::Up && keyboard_event.key == Key::Unidentified {
|
} else if keyboard_event.event.state == KeyState::Up &&
|
||||||
|
keyboard_event.event.key == Key::Unidentified
|
||||||
|
{
|
||||||
// If release and probably printable, this is following a ReceiverCharacter event.
|
// If release and probably printable, this is following a ReceiverCharacter event.
|
||||||
if let Some(key) = self.keys_down.borrow_mut().remove(&winit_event.logical_key) {
|
if let Some(key) = self.keys_down.borrow_mut().remove(&winit_event.logical_key) {
|
||||||
keyboard_event.key = key;
|
keyboard_event.event.key = key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if keyboard_event.key != Key::Unidentified {
|
if keyboard_event.event.key != Key::Unidentified {
|
||||||
self.last_pressed.set(None);
|
self.last_pressed.set(None);
|
||||||
let xr_poses = self.xr_window_poses.borrow();
|
let xr_poses = self.xr_window_poses.borrow();
|
||||||
for xr_window_pose in &*xr_poses {
|
for xr_window_pose in &*xr_poses {
|
||||||
|
@ -284,7 +288,7 @@ impl Window {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut handled = true;
|
let mut handled = true;
|
||||||
ShortcutMatcher::from_event(key_event.clone())
|
ShortcutMatcher::from_event(key_event.event.clone())
|
||||||
.shortcut(CMD_OR_CONTROL, 'R', || focused_webview.reload())
|
.shortcut(CMD_OR_CONTROL, 'R', || focused_webview.reload())
|
||||||
.shortcut(CMD_OR_CONTROL, 'W', || {
|
.shortcut(CMD_OR_CONTROL, 'W', || {
|
||||||
state.close_webview(focused_webview.id());
|
state.close_webview(focused_webview.id());
|
||||||
|
@ -828,14 +832,14 @@ impl servo::webxr::glwindow::GlWindow for XRWindow {
|
||||||
|
|
||||||
impl XRWindowPose {
|
impl XRWindowPose {
|
||||||
fn handle_xr_translation(&self, input: &KeyboardEvent) {
|
fn handle_xr_translation(&self, input: &KeyboardEvent) {
|
||||||
if input.state != KeyState::Down {
|
if input.event.state != KeyState::Down {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const NORMAL_TRANSLATE: f32 = 0.1;
|
const NORMAL_TRANSLATE: f32 = 0.1;
|
||||||
const QUICK_TRANSLATE: f32 = 1.0;
|
const QUICK_TRANSLATE: f32 = 1.0;
|
||||||
let mut x = 0.0;
|
let mut x = 0.0;
|
||||||
let mut z = 0.0;
|
let mut z = 0.0;
|
||||||
match input.key {
|
match input.event.key {
|
||||||
Key::Character(ref k) => match &**k {
|
Key::Character(ref k) => match &**k {
|
||||||
"w" => z = -NORMAL_TRANSLATE,
|
"w" => z = -NORMAL_TRANSLATE,
|
||||||
"W" => z = -QUICK_TRANSLATE,
|
"W" => z = -QUICK_TRANSLATE,
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use keyboard_types::{Code, Key, KeyState, KeyboardEvent, Location, Modifiers};
|
use keyboard_types::{Code, Key, KeyState, Location, Modifiers};
|
||||||
|
use servo::KeyboardEvent;
|
||||||
use winit::event::{ElementState, KeyEvent};
|
use winit::event::{ElementState, KeyEvent};
|
||||||
use winit::keyboard::{
|
use winit::keyboard::{
|
||||||
Key as WinitKey, KeyCode, KeyLocation as WinitKeyLocation, ModifiersState, NamedKey,
|
Key as WinitKey, KeyCode, KeyLocation as WinitKeyLocation, ModifiersState, NamedKey,
|
||||||
|
@ -583,13 +584,13 @@ fn keyboard_modifiers_from_winit_modifiers(mods: ModifiersState) -> Modifiers {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keyboard_event_from_winit(key_event: &KeyEvent, state: ModifiersState) -> KeyboardEvent {
|
pub fn keyboard_event_from_winit(key_event: &KeyEvent, state: ModifiersState) -> KeyboardEvent {
|
||||||
KeyboardEvent {
|
KeyboardEvent::new_without_event(
|
||||||
state: KeyState::from_winit_key_event(key_event),
|
KeyState::from_winit_key_event(key_event),
|
||||||
key: Key::from_winit_key_event(key_event),
|
Key::from_winit_key_event(key_event),
|
||||||
code: Code::from_winit_key_event(key_event),
|
Code::from_winit_key_event(key_event),
|
||||||
location: Location::from_winit_key_event(key_event),
|
Location::from_winit_key_event(key_event),
|
||||||
modifiers: keyboard_modifiers_from_winit_modifiers(state),
|
keyboard_modifiers_from_winit_modifiers(state),
|
||||||
repeat: false,
|
false,
|
||||||
is_composing: false,
|
false,
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -626,22 +626,14 @@ impl RunningAppState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn key_down(&self, key: Key) {
|
pub fn key_down(&self, key: Key) {
|
||||||
let key_event = KeyboardEvent {
|
let key_event = KeyboardEvent::from_state_and_key(KeyState::Down, key);
|
||||||
state: KeyState::Down,
|
|
||||||
key,
|
|
||||||
..KeyboardEvent::default()
|
|
||||||
};
|
|
||||||
self.active_webview()
|
self.active_webview()
|
||||||
.notify_input_event(InputEvent::Keyboard(key_event));
|
.notify_input_event(InputEvent::Keyboard(key_event));
|
||||||
self.perform_updates();
|
self.perform_updates();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn key_up(&self, key: Key) {
|
pub fn key_up(&self, key: Key) {
|
||||||
let key_event = KeyboardEvent {
|
let key_event = KeyboardEvent::from_state_and_key(KeyState::Up, key);
|
||||||
state: KeyState::Up,
|
|
||||||
key,
|
|
||||||
..KeyboardEvent::default()
|
|
||||||
};
|
|
||||||
self.active_webview()
|
self.active_webview()
|
||||||
.notify_input_event(InputEvent::Keyboard(key_event));
|
.notify_input_event(InputEvent::Keyboard(key_event));
|
||||||
self.perform_updates();
|
self.perform_updates();
|
||||||
|
@ -653,22 +645,20 @@ impl RunningAppState {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let active_webview = self.active_webview();
|
let active_webview = self.active_webview();
|
||||||
active_webview.notify_input_event(InputEvent::Keyboard(KeyboardEvent {
|
active_webview.notify_input_event(InputEvent::Keyboard(KeyboardEvent::from_state_and_key(
|
||||||
state: KeyState::Down,
|
KeyState::Down,
|
||||||
key: Key::Process,
|
Key::Process,
|
||||||
..KeyboardEvent::default()
|
)));
|
||||||
}));
|
|
||||||
active_webview.notify_input_event(InputEvent::Ime(ImeEvent::Composition(
|
active_webview.notify_input_event(InputEvent::Ime(ImeEvent::Composition(
|
||||||
CompositionEvent {
|
CompositionEvent {
|
||||||
state: CompositionState::End,
|
state: CompositionState::End,
|
||||||
data: text,
|
data: text,
|
||||||
},
|
},
|
||||||
)));
|
)));
|
||||||
active_webview.notify_input_event(InputEvent::Keyboard(KeyboardEvent {
|
active_webview.notify_input_event(InputEvent::Keyboard(KeyboardEvent::from_state_and_key(
|
||||||
state: KeyState::Up,
|
KeyState::Up,
|
||||||
key: Key::Process,
|
Key::Process,
|
||||||
..KeyboardEvent::default()
|
)));
|
||||||
}));
|
|
||||||
self.perform_updates();
|
self.perform_updates();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,6 @@
|
||||||
[test_key_down_closes_browsing_context]
|
[test_key_down_closes_browsing_context]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_backspace_erases_keys]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_element_in_shadow_tree[outer-open\]]
|
[test_element_in_shadow_tree[outer-open\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[key_shortcuts.py]
|
|
||||||
[test_mod_a_mod_c_right_mod_v_pastes_text]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_mod_a_mod_x_deletes_all_text]
|
|
||||||
expected: FAIL
|
|
|
@ -1,7 +1,4 @@
|
||||||
[key_special_keys.py]
|
[key_special_keys.py]
|
||||||
[test_codepoint_keys_behave_correctly[\\U0001f60d\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_codepoint_keys_behave_correctly[\\u0ba8\\u0bbf\]]
|
[test_codepoint_keys_behave_correctly[\\u0ba8\\u0bbf\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue