webdriver: Implement Pointer ID (#39642)

This is necessary first step to distinguish pointer sources: "mouse,
pen, touch".

Spec: https://w3c.github.io/webdriver/#dfn-get-a-pointer-id.

Testing: No behaviour change yet as we still only dispatch pointer type:
mouse.
Fixes: Part of #39264.

---------

Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
This commit is contained in:
Euclid Ye
2025-10-04 23:16:34 +08:00
committed by GitHub
parent 3a8c56d96b
commit 44d287cc39
3 changed files with 53 additions and 13 deletions

View File

@@ -41,11 +41,11 @@ pub(crate) enum ActionItem {
Wheel(WheelActionItem),
}
// A set of actions with multiple sources executed within a single tick.
// The `id` is used to identify the source of the actions.
/// A set of actions with multiple sources executed within a single tick.
/// The `id` is used to identify the source of the actions.
pub(crate) type TickActions = Vec<(String, ActionItem)>;
// Consumed by the `dispatch_actions` method.
/// Consumed by the `dispatch_actions` method.
pub(crate) type ActionsByTick = Vec<TickActions>;
/// <https://w3c.github.io/webdriver/#dfn-input-source-state>
@@ -63,19 +63,38 @@ pub(crate) enum InputSourceState {
pub(crate) struct PointerInputState {
subtype: PointerType,
pressed: FxHashSet<u64>,
pub(crate) pointer_id: u32,
x: f64,
y: f64,
}
impl PointerInputState {
pub fn new(subtype: PointerType) -> PointerInputState {
/// <https://w3c.github.io/webdriver/#dfn-create-a-pointer-input-source>
pub(crate) fn new(subtype: PointerType, pointer_ids: FxHashSet<u32>) -> PointerInputState {
PointerInputState {
subtype,
pressed: FxHashSet::default(),
pointer_id: Self::get_pointer_id(subtype, pointer_ids),
x: 0.0,
y: 0.0,
}
}
/// <https://w3c.github.io/webdriver/#dfn-get-a-pointer-id>
pub(crate) fn get_pointer_id(subtype: PointerType, pointer_ids: FxHashSet<u32>) -> u32 {
// Step 2 - 4: Let pointer ids be all the values in input state map which is
// pointer input source. This is already done and passed by the caller.
if subtype == PointerType::Mouse {
for id in 0..=1 {
if !pointer_ids.contains(&id) {
return id;
}
}
}
// We are dealing with subtype other than mouse, which has minimum id 2.
1 + pointer_ids.into_iter().max().unwrap_or(1)
}
}
/// <https://w3c.github.io/webdriver/#dfn-computing-the-tick-duration>
@@ -902,13 +921,13 @@ impl Handler {
// Step 2. Let id be the value of the id property of action sequence.
let id = action_sequence.id.clone();
let mut input_state_table = self.session().unwrap().input_state_table_mut();
match action_sequence.actions {
ActionsType::Null {
actions: null_actions,
} => {
input_state_table
self.session()
.unwrap()
.input_state_table_mut()
.entry(id)
.or_insert(InputSourceState::Null);
null_actions.into_iter().map(ActionItem::Null).collect()
@@ -916,7 +935,9 @@ impl Handler {
ActionsType::Key {
actions: key_actions,
} => {
input_state_table
self.session()
.unwrap()
.input_state_table_mut()
.entry(id)
.or_insert(InputSourceState::Key(KeyInputState::new()));
key_actions.into_iter().map(ActionItem::Key).collect()
@@ -925,10 +946,14 @@ impl Handler {
parameters: _,
actions: pointer_actions,
} => {
input_state_table
let pointer_ids = self.session().unwrap().pointer_ids();
self.session()
.unwrap()
.input_state_table_mut()
.entry(id)
.or_insert(InputSourceState::Pointer(PointerInputState::new(
PointerType::Mouse,
pointer_ids,
)));
pointer_actions
.into_iter()
@@ -938,7 +963,9 @@ impl Handler {
ActionsType::Wheel {
actions: wheel_actions,
} => {
input_state_table
self.session()
.unwrap()
.input_state_table_mut()
.entry(id)
.or_insert(InputSourceState::Wheel);
wheel_actions.into_iter().map(ActionItem::Wheel).collect()

View File

@@ -2248,14 +2248,16 @@ impl Handler {
}
}
/// <https://w3c.github.io/webdriver/#element-click>
/// Step 8 for elements other than <option>
fn perform_element_click(&mut self, element: String) -> WebDriverResult<WebDriverResponse> {
// Step 8 for elements other than <option>
// Step 8.1 - 8.4: Create UUID, create input source "pointer".
let id = Uuid::new_v4().to_string();
// Step 8.1
let pointer_ids = self.session()?.pointer_ids();
self.session_mut()?.input_state_table_mut().insert(
id.clone(),
InputSourceState::Pointer(PointerInputState::new(PointerType::Mouse)),
InputSourceState::Pointer(PointerInputState::new(PointerType::Mouse, pointer_ids)),
);
// Step 8.7. Construct a pointer move action.

View File

@@ -6,6 +6,7 @@ use std::cell::{Ref, RefCell, RefMut};
use std::collections::HashMap;
use base::id::{BrowsingContextId, WebViewId};
use rustc_hash::FxHashSet;
use serde_json::{Map, Value, json};
use uuid::Uuid;
use webdriver::error::WebDriverResult;
@@ -129,6 +130,16 @@ impl WebDriverSession {
self.input_state_table.borrow_mut()
}
pub fn pointer_ids(&self) -> FxHashSet<u32> {
self.input_state_table()
.values()
.filter_map(|source| match source {
InputSourceState::Pointer(pointer_state) => Some(pointer_state.pointer_id),
_ => None,
})
.collect()
}
pub fn input_cancel_list_mut(&self) -> RefMut<'_, Vec<(String, ActionItem)>> {
self.input_cancel_list.borrow_mut()
}