mirror of
https://github.com/lexmount/moli.git
synced 2026-10-31 00:06:19 +00:00
fix(input): release individual CDP touch contacts
This commit is contained in:
@@ -416,13 +416,13 @@ fn validate_coordinate_input_params(
|
||||
if cdp_modifiers(params.modifiers).is_err() {
|
||||
return Err(PendingInputCommandStartError::invalid_params());
|
||||
}
|
||||
let valid_point_count =
|
||||
match params.r#type {
|
||||
CdpDispatchTouchEventType::TouchStart
|
||||
| CdpDispatchTouchEventType::TouchMove => !params.touch_points.is_empty(),
|
||||
CdpDispatchTouchEventType::TouchEnd
|
||||
| CdpDispatchTouchEventType::TouchCancel => params.touch_points.is_empty(),
|
||||
};
|
||||
let valid_point_count = match params.r#type {
|
||||
CdpDispatchTouchEventType::TouchStart | CdpDispatchTouchEventType::TouchMove => {
|
||||
!params.touch_points.is_empty()
|
||||
}
|
||||
CdpDispatchTouchEventType::TouchEnd => true,
|
||||
CdpDispatchTouchEventType::TouchCancel => params.touch_points.is_empty(),
|
||||
};
|
||||
let point_ids_are_consistent = params.touch_points.is_empty()
|
||||
|| params.touch_points.iter().all(|point| point.id.is_some())
|
||||
|| params.touch_points.iter().all(|point| point.id.is_none());
|
||||
|
||||
@@ -1878,6 +1878,66 @@ async fn coordinate_touch_commands_complete_through_pending_layout_dispatch() {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn coordinate_touch_end_releases_only_the_requested_contact() {
|
||||
let mut ctx = TestContext::new();
|
||||
with_loaded_document(
|
||||
&mut ctx,
|
||||
r#"<html><body style='margin:0'>
|
||||
<button id='btn' style='width:80px;height:80px'>tap</button>
|
||||
<script>
|
||||
window.__touchContacts = [];
|
||||
for (const type of ['touchmove', 'touchend']) {
|
||||
document.addEventListener(type, e => __touchContacts.push([
|
||||
type, Array.from(e.touches, t => t.identifier),
|
||||
Array.from(e.changedTouches, t => t.identifier)
|
||||
]));
|
||||
}
|
||||
</script>
|
||||
</body></html>"#,
|
||||
)
|
||||
.await;
|
||||
ctx.capture_fixture_layout(None).await;
|
||||
|
||||
for (id, event_type, touch_points) in [
|
||||
(
|
||||
4110,
|
||||
"touchStart",
|
||||
json!([
|
||||
{ "id": 11, "x": INPUT_HIT_X, "y": INPUT_HIT_Y },
|
||||
{ "id": 12, "x": INPUT_HIT_X + 4, "y": INPUT_HIT_Y }
|
||||
]),
|
||||
),
|
||||
(
|
||||
4111,
|
||||
"touchEnd",
|
||||
json!([{ "id": 11, "x": INPUT_HIT_X, "y": INPUT_HIT_Y }]),
|
||||
),
|
||||
(
|
||||
4112,
|
||||
"touchMove",
|
||||
json!([{ "id": 12, "x": INPUT_HIT_X + 8, "y": INPUT_HIT_Y }]),
|
||||
),
|
||||
(
|
||||
4113,
|
||||
"touchEnd",
|
||||
json!([{ "id": 12, "x": INPUT_HIT_X + 8, "y": INPUT_HIT_Y }]),
|
||||
),
|
||||
] {
|
||||
ctx.process_async(json!({
|
||||
"id": id,
|
||||
"method": "Input.dispatchTouchEvent",
|
||||
"params": { "type": event_type, "touchPoints": touch_points }
|
||||
}))
|
||||
.await;
|
||||
ctx.expect_result(id, json!({}), None);
|
||||
}
|
||||
assert_eq!(
|
||||
evaluate_string(&mut ctx, "JSON.stringify(__touchContacts)").await,
|
||||
r#"[["touchend",[12],[11]],["touchmove",[12],[12]],["touchend",[],[12]]]"#
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn coordinate_drag_event_completes_through_pending_layout_dispatch() {
|
||||
let mut ctx = TestContext::new();
|
||||
|
||||
@@ -1708,7 +1708,7 @@ impl ScriptVm {
|
||||
let ending_points = self.active_touch_contact_samples();
|
||||
return self.dispatch_touch_changed_event(&ending_points, event_name, false);
|
||||
}
|
||||
let points = if event_name == "touchend" {
|
||||
let points = if event_name == "touchend" && points.is_empty() {
|
||||
self.active_touch_contact_samples()
|
||||
} else {
|
||||
// CDP orders changed contacts by identifier, independently of the
|
||||
|
||||
@@ -303,6 +303,75 @@ fn contact_updates_preserve_existing_touches_and_emit_only_changed_contacts() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ending_contact_updates_preserves_other_touches_and_their_capture() {
|
||||
for first_id in [0, 11] {
|
||||
let mut vm = new_touch_contact_test_vm();
|
||||
vm.eval(
|
||||
r#"
|
||||
globalThis.__touchEnds = [];
|
||||
globalThis.__touchPointers = {};
|
||||
document.addEventListener('pointerdown', e => __touchPointers[e.target.id] = e.pointerId);
|
||||
for (const type of ['touchmove', 'touchend']) {
|
||||
document.addEventListener(type, e => __touchEnds.push({
|
||||
type, target:e.target.id,
|
||||
touches:Array.from(e.touches, t => t.identifier),
|
||||
targetTouches:Array.from(e.targetTouches, t => t.identifier),
|
||||
changed:Array.from(e.changedTouches, t => t.identifier)
|
||||
}));
|
||||
}
|
||||
'ready'
|
||||
"#,
|
||||
).unwrap();
|
||||
let first = crate::runtime::RendererTouchPoint {
|
||||
id: first_id,
|
||||
x: 80.0,
|
||||
y: 80.0,
|
||||
};
|
||||
let second = crate::runtime::RendererTouchPoint {
|
||||
id: first_id + 1,
|
||||
x: 260.0,
|
||||
y: 80.0,
|
||||
};
|
||||
vm.dispatch_touch_contact_updates(&[second, first], "touchstart")
|
||||
.unwrap();
|
||||
vm.dispatch_touch_contact_updates(&[first], "touchend")
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
vm.eval(
|
||||
r#"(() => {
|
||||
const first = document.getElementById('first');
|
||||
const second = document.getElementById('second');
|
||||
let retired = false;
|
||||
try { first.releasePointerCapture(__touchPointers.first); }
|
||||
catch (e) { retired = e instanceof DOMException && e.name === 'NotFoundError'; }
|
||||
return retired && !first.hasPointerCapture(__touchPointers.first)
|
||||
&& second.hasPointerCapture(__touchPointers.second);
|
||||
})()"#,
|
||||
)
|
||||
.unwrap(),
|
||||
"true"
|
||||
);
|
||||
let moved_second = crate::runtime::RendererTouchPoint { x: 264.0, ..second };
|
||||
vm.dispatch_touch_contact_updates(&[moved_second], "touchmove")
|
||||
.unwrap();
|
||||
vm.dispatch_touch_contact_updates(&[moved_second], "touchend")
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
vm.eval("JSON.stringify(__touchEnds)").unwrap(),
|
||||
format!(
|
||||
r#"[{{"type":"touchend","target":"first","touches":[{second_id}],"targetTouches":[],"changed":[{first_id}]}},{{"type":"touchmove","target":"second","touches":[{second_id}],"targetTouches":[{second_id}],"changed":[{second_id}]}},{{"type":"touchend","target":"second","touches":[],"targetTouches":[],"changed":[{second_id}]}}]"#,
|
||||
second_id = first_id + 1
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
vm.eval("document.getElementById('second').hasPointerCapture(__touchPointers.second)")
|
||||
.unwrap(),
|
||||
"false"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn contact_updates_on_move_can_start_an_additional_contact() {
|
||||
let mut vm = new_pointer_activity_test_vm("touch", false, 2);
|
||||
|
||||
Reference in New Issue
Block a user