Fix the problem that touchmove crashes occasionally. Fix crash when multiple touch cancels occur (#35763)

* Fix the problem that touchmove crashes occasionally.
Check whether touchSequenceInfo exists when touch_sequence_map is modified in on_touch_event_processed.

Signed-off-by: kongbai1996 <1782765876@qq.com>

* Remove outdated todo.

We already transition to Finished in `on_touch_cancel`
in the Touch handler, so we don't need any logic
in the event handler.

Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>

---------

Signed-off-by: kongbai1996 <1782765876@qq.com>
Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
Co-authored-by: Jonathan Schwender <schwenderjonathan@gmail.com>
This commit is contained in:
Bi Fuguo 2025-03-03 23:30:57 +08:00 committed by GitHub
parent 5650fa2e79
commit a22f95a6a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 49 additions and 51 deletions

View file

@ -1474,23 +1474,25 @@ impl IOCompositor {
}, },
TouchEventType::Move => { TouchEventType::Move => {
// script thread processed the touch move event, mark this false. // script thread processed the touch move event, mark this false.
let info = self.touch_handler.get_touch_sequence_mut(sequence_id); if let Some(info) = self.touch_handler.get_touch_sequence_mut(sequence_id) {
info.prevent_move = TouchMoveAllowed::Prevented; info.prevent_move = TouchMoveAllowed::Prevented;
if let TouchSequenceState::PendingFling { .. } = info.state { if let TouchSequenceState::PendingFling { .. } = info.state {
info.state = TouchSequenceState::Finished; info.state = TouchSequenceState::Finished;
}
self.touch_handler.set_handling_touch_move(
self.touch_handler.current_sequence_id,
false,
);
self.touch_handler
.remove_pending_touch_move_action(sequence_id);
} }
self.touch_handler.prevent_move(sequence_id);
self.touch_handler
.set_handling_touch_move(self.touch_handler.current_sequence_id, false);
self.touch_handler
.remove_pending_touch_move_action(sequence_id);
}, },
TouchEventType::Up => { TouchEventType::Up => {
// Note: We don't have to consider PendingFling here, since we handle that // Note: We don't have to consider PendingFling here, since we handle that
// in the DefaultAllowed case of the touch_move event. // in the DefaultAllowed case of the touch_move event.
// Note: Removing can and should fail, if we still have an active Fling, // Note: Removing can and should fail, if we still have an active Fling,
let Some(info) = let Some(info) =
&mut self.touch_handler.touch_sequence_map.get_mut(&sequence_id) &mut self.touch_handler.get_touch_sequence_mut(sequence_id)
else { else {
// The sequence ID could already be removed, e.g. if Fling finished, // The sequence ID could already be removed, e.g. if Fling finished,
// before the touch_up event was handled (since fling can start // before the touch_up event was handled (since fling can start
@ -1526,10 +1528,6 @@ impl IOCompositor {
// actions, and try to remove the touch sequence. // actions, and try to remove the touch sequence.
self.touch_handler self.touch_handler
.remove_pending_touch_move_action(sequence_id); .remove_pending_touch_move_action(sequence_id);
// Todo: Perhaps we need to check how many fingers are still active.
self.touch_handler.get_touch_sequence_mut(sequence_id).state =
TouchSequenceState::Finished;
// Cancel should be the last event for a given sequence_id.
self.touch_handler.try_remove_touch_sequence(sequence_id); self.touch_handler.try_remove_touch_sequence(sequence_id);
}, },
} }
@ -1581,15 +1579,17 @@ impl IOCompositor {
} }
self.touch_handler self.touch_handler
.set_handling_touch_move(self.touch_handler.current_sequence_id, false); .set_handling_touch_move(self.touch_handler.current_sequence_id, false);
let info = self.touch_handler.get_touch_sequence_mut(sequence_id); if let Some(info) = self.touch_handler.get_touch_sequence_mut(sequence_id) {
info.prevent_move = TouchMoveAllowed::Allowed; info.prevent_move = TouchMoveAllowed::Allowed;
if let TouchSequenceState::PendingFling { velocity, cursor } = info.state { if let TouchSequenceState::PendingFling { velocity, cursor } =
info.state = TouchSequenceState::Flinging { velocity, cursor } info.state
{
info.state = TouchSequenceState::Flinging { velocity, cursor }
}
} }
}, },
TouchEventType::Up => { TouchEventType::Up => {
let Some(info) = let Some(info) = self.touch_handler.get_touch_sequence_mut(sequence_id)
self.touch_handler.touch_sequence_map.get_mut(&sequence_id)
else { else {
// The sequence was already removed because there is no default action. // The sequence was already removed because there is no default action.
return; return;
@ -1626,7 +1626,7 @@ impl IOCompositor {
TouchEventType::Cancel => { TouchEventType::Cancel => {
self.touch_handler self.touch_handler
.remove_pending_touch_move_action(sequence_id); .remove_pending_touch_move_action(sequence_id);
self.touch_handler.remove_touch_sequence(sequence_id); self.touch_handler.try_remove_touch_sequence(sequence_id);
}, },
} }
}, },

View file

@ -26,7 +26,7 @@ const FLING_MAX_SCREEN_PX: f32 = 4000.0;
pub struct TouchHandler { pub struct TouchHandler {
pub current_sequence_id: TouchSequenceId, pub current_sequence_id: TouchSequenceId,
// todo: VecDeque + modulo arithmetic would be more efficient. // todo: VecDeque + modulo arithmetic would be more efficient.
pub touch_sequence_map: HashMap<TouchSequenceId, TouchSequenceInfo>, touch_sequence_map: HashMap<TouchSequenceId, TouchSequenceInfo>,
} }
/// Whether the default move action is allowed or not. /// Whether the default move action is allowed or not.
@ -213,41 +213,39 @@ impl TouchHandler {
} }
pub(crate) fn set_handling_touch_move(&mut self, sequence_id: TouchSequenceId, flag: bool) { pub(crate) fn set_handling_touch_move(&mut self, sequence_id: TouchSequenceId, flag: bool) {
self.touch_sequence_map if let Some(sequence) = self.touch_sequence_map.get_mut(&sequence_id) {
.get_mut(&sequence_id) sequence.handling_touch_move = flag;
.unwrap() }
.handling_touch_move = flag;
} }
pub(crate) fn is_handling_touch_move(&self, sequence_id: TouchSequenceId) -> bool { pub(crate) fn is_handling_touch_move(&self, sequence_id: TouchSequenceId) -> bool {
self.touch_sequence_map if let Some(sequence) = self.touch_sequence_map.get(&sequence_id) {
.get(&sequence_id) sequence.handling_touch_move
.unwrap() } else {
.handling_touch_move false
}
} }
pub(crate) fn prevent_click(&mut self, sequence_id: TouchSequenceId) { pub(crate) fn prevent_click(&mut self, sequence_id: TouchSequenceId) {
self.touch_sequence_map if let Some(sequence) = self.touch_sequence_map.get_mut(&sequence_id) {
.get_mut(&sequence_id) sequence.prevent_click = true;
.unwrap() }
.prevent_click = true;
} }
pub(crate) fn prevent_move(&mut self, sequence_id: TouchSequenceId) { pub(crate) fn prevent_move(&mut self, sequence_id: TouchSequenceId) {
self.touch_sequence_map if let Some(sequence) = self.touch_sequence_map.get_mut(&sequence_id) {
.get_mut(&sequence_id) sequence.prevent_move = TouchMoveAllowed::Prevented;
.unwrap() }
.prevent_move = TouchMoveAllowed::Prevented;
} }
/// Returns true if default move actions are allowed, false if prevented or the result /// Returns true if default move actions are allowed, false if prevented or the result
/// is still pending., /// is still pending.,
pub(crate) fn move_allowed(&mut self, sequence_id: TouchSequenceId) -> bool { pub(crate) fn move_allowed(&mut self, sequence_id: TouchSequenceId) -> bool {
self.touch_sequence_map if let Some(sequence) = self.touch_sequence_map.get_mut(&sequence_id) {
.get(&sequence_id) sequence.prevent_move == TouchMoveAllowed::Allowed
.unwrap() } else {
.prevent_move == true
TouchMoveAllowed::Allowed }
} }
pub(crate) fn pending_touch_move_action( pub(crate) fn pending_touch_move_action(
@ -294,10 +292,8 @@ impl TouchHandler {
pub(crate) fn get_touch_sequence_mut( pub(crate) fn get_touch_sequence_mut(
&mut self, &mut self,
sequence_id: TouchSequenceId, sequence_id: TouchSequenceId,
) -> &mut TouchSequenceInfo { ) -> Option<&mut TouchSequenceInfo> {
self.touch_sequence_map self.touch_sequence_map.get_mut(&sequence_id)
.get_mut(&sequence_id)
.expect("Touch sequence not found.")
} }
pub fn on_touch_down(&mut self, id: TouchId, point: Point2D<f32, DevicePixel>) { pub fn on_touch_down(&mut self, id: TouchId, point: Point2D<f32, DevicePixel>) {
@ -377,7 +373,7 @@ impl TouchHandler {
id: TouchId, id: TouchId,
point: Point2D<f32, DevicePixel>, point: Point2D<f32, DevicePixel>,
) -> TouchMoveAction { ) -> TouchMoveAction {
let touch_sequence = self.get_touch_sequence_mut(self.current_sequence_id); let touch_sequence = self.get_current_touch_sequence_mut();
let idx = match touch_sequence let idx = match touch_sequence
.active_touch_points .active_touch_points
.iter_mut() .iter_mut()
@ -454,7 +450,7 @@ impl TouchHandler {
} }
pub fn on_touch_up(&mut self, id: TouchId, point: Point2D<f32, DevicePixel>) { pub fn on_touch_up(&mut self, id: TouchId, point: Point2D<f32, DevicePixel>) {
let touch_sequence = self.get_touch_sequence_mut(self.current_sequence_id); let touch_sequence = self.get_current_touch_sequence_mut();
let old = match touch_sequence let old = match touch_sequence
.active_touch_points .active_touch_points
.iter() .iter()
@ -531,7 +527,7 @@ impl TouchHandler {
} }
pub fn on_touch_cancel(&mut self, id: TouchId, _point: Point2D<f32, DevicePixel>) { pub fn on_touch_cancel(&mut self, id: TouchId, _point: Point2D<f32, DevicePixel>) {
let touch_sequence = self.get_touch_sequence_mut(self.current_sequence_id); let touch_sequence = self.get_current_touch_sequence_mut();
match touch_sequence match touch_sequence
.active_touch_points .active_touch_points
.iter() .iter()
@ -545,6 +541,8 @@ impl TouchHandler {
return; return;
}, },
} }
touch_sequence.state = Finished; if touch_sequence.active_touch_points.is_empty() {
touch_sequence.state = Finished;
}
} }
} }