Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial actions support in WebDriver
- Loading branch information
1 parent
79b456d
commit 75efb09
Showing
6 changed files
with
291 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
/* 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 https://mozilla.org/MPL/2.0/. */ | ||
|
||
use crate::Handler; | ||
use keyboard_types::webdriver::KeyInputState; | ||
use script_traits::{ConstellationMsg, WebDriverCommandMsg}; | ||
use std::cmp; | ||
use std::collections::HashSet; | ||
use webdriver::actions::{ActionSequence, ActionsType, GeneralAction, NullActionItem}; | ||
use webdriver::actions::{KeyAction, KeyActionItem, KeyDownAction, KeyUpAction}; | ||
use webdriver::actions::{PointerAction, PointerActionItem, PointerType}; | ||
|
||
// https://w3c.github.io/webdriver/#dfn-input-source-state | ||
pub(crate) enum InputSourceState { | ||
Null, | ||
Key(KeyInputState), | ||
Pointer(PointerInputState), | ||
} | ||
|
||
// https://w3c.github.io/webdriver/#dfn-pointer-input-source | ||
pub(crate) struct PointerInputState { | ||
_subtype: PointerType, | ||
_pressed: HashSet<u64>, | ||
_x: u64, | ||
_y: u64, | ||
} | ||
|
||
impl PointerInputState { | ||
pub fn new(subtype: &PointerType) -> PointerInputState { | ||
PointerInputState { | ||
_subtype: match subtype { | ||
PointerType::Mouse => PointerType::Mouse, | ||
PointerType::Pen => PointerType::Pen, | ||
PointerType::Touch => PointerType::Touch, | ||
}, | ||
_pressed: HashSet::new(), | ||
_x: 0, | ||
_y: 0, | ||
} | ||
} | ||
} | ||
|
||
// https://w3c.github.io/webdriver/#dfn-computing-the-tick-duration | ||
fn compute_tick_duration(tick_actions: &ActionSequence) -> u64 { | ||
let mut duration = 0; | ||
match &tick_actions.actions { | ||
ActionsType::Null { actions } => { | ||
for action in actions.iter() { | ||
let NullActionItem::General(GeneralAction::Pause(pause_action)) = action; | ||
duration = cmp::max(duration, pause_action.duration.unwrap_or(0)); | ||
} | ||
}, | ||
ActionsType::Pointer { | ||
parameters: _, | ||
actions, | ||
} => { | ||
for action in actions.iter() { | ||
let action_duration = match action { | ||
PointerActionItem::General(GeneralAction::Pause(action)) => action.duration, | ||
PointerActionItem::Pointer(PointerAction::Move(action)) => action.duration, | ||
_ => None, | ||
}; | ||
duration = cmp::max(duration, action_duration.unwrap_or(0)); | ||
} | ||
}, | ||
ActionsType::Key { actions: _ } => (), | ||
} | ||
duration | ||
} | ||
|
||
impl Handler { | ||
// https://w3c.github.io/webdriver/#dfn-dispatch-actions | ||
pub(crate) fn dispatch_actions(&mut self, actions_by_tick: &[ActionSequence]) { | ||
for tick_actions in actions_by_tick.iter() { | ||
let tick_duration = compute_tick_duration(&tick_actions); | ||
self.dispatch_tick_actions(&tick_actions, tick_duration); | ||
} | ||
} | ||
|
||
fn dispatch_general_action(&mut self, source_id: &str) { | ||
self.session_mut() | ||
.unwrap() | ||
.input_state_table | ||
.entry(source_id.to_string()) | ||
.or_insert(InputSourceState::Null); | ||
// https://w3c.github.io/webdriver/#dfn-dispatch-a-pause-action | ||
// Nothing to be done | ||
} | ||
|
||
// https://w3c.github.io/webdriver/#dfn-dispatch-tick-actions | ||
fn dispatch_tick_actions(&mut self, tick_actions: &ActionSequence, tick_duration: u64) { | ||
let source_id = &tick_actions.id; | ||
match &tick_actions.actions { | ||
ActionsType::Null { actions } => { | ||
for _action in actions.iter() { | ||
self.dispatch_general_action(source_id); | ||
} | ||
}, | ||
ActionsType::Key { actions } => { | ||
for action in actions.iter() { | ||
match action { | ||
KeyActionItem::General(_action) => { | ||
self.dispatch_general_action(source_id); | ||
}, | ||
KeyActionItem::Key(action) => { | ||
self.session_mut() | ||
.unwrap() | ||
.input_state_table | ||
.entry(source_id.to_string()) | ||
.or_insert(InputSourceState::Key(KeyInputState::new())); | ||
match action { | ||
KeyAction::Down(action) => { | ||
self.dispatch_keydown_action(&source_id, &action, tick_duration) | ||
}, | ||
KeyAction::Up(action) => { | ||
self.dispatch_keyup_action(&source_id, &action, tick_duration) | ||
}, | ||
}; | ||
}, | ||
} | ||
} | ||
}, | ||
ActionsType::Pointer { | ||
parameters, | ||
actions, | ||
} => { | ||
for action in actions.iter() { | ||
match action { | ||
PointerActionItem::General(_action) => { | ||
self.dispatch_general_action(source_id); | ||
}, | ||
PointerActionItem::Pointer(action) => { | ||
self.session_mut() | ||
.unwrap() | ||
.input_state_table | ||
.entry(source_id.to_string()) | ||
.or_insert(InputSourceState::Pointer(PointerInputState::new( | ||
¶meters.pointer_type, | ||
))); | ||
match action { | ||
PointerAction::Cancel => (), | ||
PointerAction::Down(_action) => (), | ||
PointerAction::Move(_action) => (), | ||
PointerAction::Up(_action) => (), | ||
} | ||
}, | ||
} | ||
} | ||
}, | ||
} | ||
} | ||
|
||
// https://w3c.github.io/webdriver/#dfn-dispatch-a-keydown-action | ||
fn dispatch_keydown_action( | ||
&mut self, | ||
source_id: &str, | ||
action: &KeyDownAction, | ||
_tick_duration: u64, | ||
) { | ||
let session = self.session.as_mut().unwrap(); | ||
|
||
let raw_key = action.value.chars().next().unwrap(); | ||
let key_input_state = match session.input_state_table.get_mut(source_id).unwrap() { | ||
InputSourceState::Null => unreachable!(), | ||
InputSourceState::Key(key_input_state) => key_input_state, | ||
InputSourceState::Pointer(_) => unreachable!(), | ||
}; | ||
|
||
session.input_cancel_list.push(ActionSequence { | ||
id: source_id.into(), | ||
actions: ActionsType::Key { | ||
actions: vec![KeyActionItem::Key(KeyAction::Up(KeyUpAction { | ||
value: action.value.clone(), | ||
}))], | ||
}, | ||
}); | ||
|
||
let keyboard_event = key_input_state.dispatch_keydown(raw_key); | ||
let cmd_msg = | ||
WebDriverCommandMsg::KeyboardAction(session.browsing_context_id, keyboard_event); | ||
self.constellation_chan | ||
.send(ConstellationMsg::WebDriverCommand(cmd_msg)) | ||
.unwrap(); | ||
} | ||
|
||
// https://w3c.github.io/webdriver/#dfn-dispatch-a-keyup-action | ||
fn dispatch_keyup_action( | ||
&mut self, | ||
source_id: &str, | ||
action: &KeyUpAction, | ||
_tick_duration: u64, | ||
) { | ||
let session = self.session.as_mut().unwrap(); | ||
|
||
let raw_key = action.value.chars().next().unwrap(); | ||
let key_input_state = match session.input_state_table.get_mut(source_id).unwrap() { | ||
InputSourceState::Null => unreachable!(), | ||
InputSourceState::Key(key_input_state) => key_input_state, | ||
InputSourceState::Pointer(_) => unreachable!(), | ||
}; | ||
|
||
session.input_cancel_list.push(ActionSequence { | ||
id: source_id.into(), | ||
actions: ActionsType::Key { | ||
actions: vec![KeyActionItem::Key(KeyAction::Up(KeyUpAction { | ||
value: action.value.clone(), | ||
}))], | ||
}, | ||
}); | ||
|
||
if let Some(keyboard_event) = key_input_state.dispatch_keyup(raw_key) { | ||
let cmd_msg = | ||
WebDriverCommandMsg::KeyboardAction(session.browsing_context_id, keyboard_event); | ||
self.constellation_chan | ||
.send(ConstellationMsg::WebDriverCommand(cmd_msg)) | ||
.unwrap(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 3 additions & 1 deletion
4
tests/wpt/metadata/webdriver/tests/perform_actions/none.py.ini
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
[none.py] | ||
disabled: Unimplemented WebDriver command | ||
[test_no_browsing_context] | ||
expected: ERROR | ||
|
2 changes: 0 additions & 2 deletions
2
tests/wpt/metadata/webdriver/tests/perform_actions/validity.py.ini
This file was deleted.
Oops, something went wrong.