fix: touch input, ensure message orders (#9855)

Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
fufesou 2024-11-07 21:23:41 +08:00 committed by GitHub
parent 69277dd16b
commit d0ef52e418
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 70 additions and 63 deletions

View File

@ -106,7 +106,7 @@ class _RawTouchGestureDetectorRegionState
); );
} }
onTapDown(TapDownDetails d) { onTapDown(TapDownDetails d) async {
lastDeviceKind = d.kind; lastDeviceKind = d.kind;
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
@ -114,45 +114,49 @@ class _RawTouchGestureDetectorRegionState
if (handleTouch) { if (handleTouch) {
_lastPosOfDoubleTapDown = d.localPosition; _lastPosOfDoubleTapDown = d.localPosition;
// Desktop or mobile "Touch mode" // Desktop or mobile "Touch mode"
if (ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy)) { final isMoved =
inputModel.tapDown(MouseButtons.left); await ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy);
if (isMoved) {
await inputModel.tapDown(MouseButtons.left);
} }
} }
} }
onTapUp(TapUpDetails d) { onTapUp(TapUpDetails d) async {
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
} }
if (handleTouch) { if (handleTouch) {
if (ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy)) { final isMoved =
await ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy);
if (isMoved) {
inputModel.tapUp(MouseButtons.left); inputModel.tapUp(MouseButtons.left);
} }
} }
} }
onTap() { onTap() async {
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
} }
if (!handleTouch) { if (!handleTouch) {
// Mobile, "Mouse mode" // Mobile, "Mouse mode"
inputModel.tap(MouseButtons.left); await inputModel.tap(MouseButtons.left);
} }
} }
onDoubleTapDown(TapDownDetails d) { onDoubleTapDown(TapDownDetails d) async {
lastDeviceKind = d.kind; lastDeviceKind = d.kind;
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
} }
if (handleTouch) { if (handleTouch) {
_lastPosOfDoubleTapDown = d.localPosition; _lastPosOfDoubleTapDown = d.localPosition;
ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy); await ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy);
} }
} }
onDoubleTap() { onDoubleTap() async {
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
} }
@ -163,11 +167,11 @@ class _RawTouchGestureDetectorRegionState
!ffi.cursorModel.isInRemoteRect(_lastPosOfDoubleTapDown)) { !ffi.cursorModel.isInRemoteRect(_lastPosOfDoubleTapDown)) {
return; return;
} }
inputModel.tap(MouseButtons.left); await inputModel.tap(MouseButtons.left);
inputModel.tap(MouseButtons.left); await inputModel.tap(MouseButtons.left);
} }
onLongPressDown(LongPressDownDetails d) { onLongPressDown(LongPressDownDetails d) async {
lastDeviceKind = d.kind; lastDeviceKind = d.kind;
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
@ -175,39 +179,42 @@ class _RawTouchGestureDetectorRegionState
if (handleTouch) { if (handleTouch) {
_lastPosOfDoubleTapDown = d.localPosition; _lastPosOfDoubleTapDown = d.localPosition;
_cacheLongPressPosition = d.localPosition; _cacheLongPressPosition = d.localPosition;
if (!ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy)) { final isMoved =
await ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy);
if (!isMoved) {
return; return;
} }
_cacheLongPressPositionTs = DateTime.now().millisecondsSinceEpoch; _cacheLongPressPositionTs = DateTime.now().millisecondsSinceEpoch;
} }
} }
onLongPressUp() { onLongPressUp() async {
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
} }
if (handleTouch) { if (handleTouch) {
inputModel.tapUp(MouseButtons.left); await inputModel.tapUp(MouseButtons.left);
} }
} }
// for mobiles // for mobiles
onLongPress() { onLongPress() async {
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
} }
if (handleTouch) { if (handleTouch) {
if (!ffi.cursorModel final isMoved = await ffi.cursorModel
.move(_cacheLongPressPosition.dx, _cacheLongPressPosition.dy)) { .move(_cacheLongPressPosition.dx, _cacheLongPressPosition.dy);
if (!isMoved) {
return; return;
} }
} }
if (!ffi.ffiModel.isPeerMobile) { if (!ffi.ffiModel.isPeerMobile) {
inputModel.tap(MouseButtons.right); await inputModel.tap(MouseButtons.right);
} }
} }
onDoubleFinerTapDown(TapDownDetails d) { onDoubleFinerTapDown(TapDownDetails d) async {
lastDeviceKind = d.kind; lastDeviceKind = d.kind;
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
@ -216,7 +223,7 @@ class _RawTouchGestureDetectorRegionState
// ignore for desktop and mobile // ignore for desktop and mobile
} }
onDoubleFinerTap(TapDownDetails d) { onDoubleFinerTap(TapDownDetails d) async {
lastDeviceKind = d.kind; lastDeviceKind = d.kind;
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
@ -228,39 +235,39 @@ class _RawTouchGestureDetectorRegionState
final isDesktopInRemoteRect = (isDesktop || isWebDesktop) && final isDesktopInRemoteRect = (isDesktop || isWebDesktop) &&
ffi.cursorModel.isInRemoteRect(_doubleFinerTapPosition); ffi.cursorModel.isInRemoteRect(_doubleFinerTapPosition);
if (isMobileMouseMode || isDesktopInRemoteRect) { if (isMobileMouseMode || isDesktopInRemoteRect) {
inputModel.tap(MouseButtons.right); await inputModel.tap(MouseButtons.right);
} }
} }
onHoldDragStart(DragStartDetails d) { onHoldDragStart(DragStartDetails d) async {
lastDeviceKind = d.kind; lastDeviceKind = d.kind;
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
} }
if (!handleTouch) { if (!handleTouch) {
inputModel.sendMouse('down', MouseButtons.left); await inputModel.sendMouse('down', MouseButtons.left);
} }
} }
onHoldDragUpdate(DragUpdateDetails d) { onHoldDragUpdate(DragUpdateDetails d) async {
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
} }
if (!handleTouch) { if (!handleTouch) {
ffi.cursorModel.updatePan(d.delta, d.localPosition, handleTouch); await ffi.cursorModel.updatePan(d.delta, d.localPosition, handleTouch);
} }
} }
onHoldDragEnd(DragEndDetails d) { onHoldDragEnd(DragEndDetails d) async {
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
} }
if (!handleTouch) { if (!handleTouch) {
inputModel.sendMouse('up', MouseButtons.left); await inputModel.sendMouse('up', MouseButtons.left);
} }
} }
onOneFingerPanStart(BuildContext context, DragStartDetails d) { onOneFingerPanStart(BuildContext context, DragStartDetails d) async {
lastDeviceKind = d.kind ?? lastDeviceKind; lastDeviceKind = d.kind ?? lastDeviceKind;
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
@ -285,11 +292,11 @@ class _RawTouchGestureDetectorRegionState
// TODO: We should find a better way to send the first pan event as soon as possible. // TODO: We should find a better way to send the first pan event as soon as possible.
if (DateTime.now().millisecondsSinceEpoch - _cacheLongPressPositionTs < if (DateTime.now().millisecondsSinceEpoch - _cacheLongPressPositionTs <
500) { 500) {
ffi.cursorModel await ffi.cursorModel
.move(_cacheLongPressPosition.dx, _cacheLongPressPosition.dy); .move(_cacheLongPressPosition.dx, _cacheLongPressPosition.dy);
} }
inputModel.sendMouse('down', MouseButtons.left); await inputModel.sendMouse('down', MouseButtons.left);
ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy); await ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy);
} else { } else {
final offset = ffi.cursorModel.offset; final offset = ffi.cursorModel.offset;
final cursorX = offset.dx; final cursorX = offset.dx;
@ -298,12 +305,12 @@ class _RawTouchGestureDetectorRegionState
ffi.cursorModel.getVisibleRect().inflate(1); // extend edges ffi.cursorModel.getVisibleRect().inflate(1); // extend edges
final size = MediaQueryData.fromView(View.of(context)).size; final size = MediaQueryData.fromView(View.of(context)).size;
if (!visible.contains(Offset(cursorX, cursorY))) { if (!visible.contains(Offset(cursorX, cursorY))) {
ffi.cursorModel.move(size.width / 2, size.height / 2); await ffi.cursorModel.move(size.width / 2, size.height / 2);
} }
} }
} }
onOneFingerPanUpdate(DragUpdateDetails d) { onOneFingerPanUpdate(DragUpdateDetails d) async {
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
} }
@ -313,10 +320,10 @@ class _RawTouchGestureDetectorRegionState
if (handleTouch && !_touchModePanStarted) { if (handleTouch && !_touchModePanStarted) {
return; return;
} }
ffi.cursorModel.updatePan(d.delta, d.localPosition, handleTouch); await ffi.cursorModel.updatePan(d.delta, d.localPosition, handleTouch);
} }
onOneFingerPanEnd(DragEndDetails d) { onOneFingerPanEnd(DragEndDetails d) async {
_touchModePanStarted = false; _touchModePanStarted = false;
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
@ -324,7 +331,7 @@ class _RawTouchGestureDetectorRegionState
if (isDesktop || isWebDesktop) { if (isDesktop || isWebDesktop) {
ffi.cursorModel.clearRemoteWindowCoords(); ffi.cursorModel.clearRemoteWindowCoords();
} }
inputModel.sendMouse('up', MouseButtons.left); await inputModel.sendMouse('up', MouseButtons.left);
} }
// scale + pan event // scale + pan event
@ -334,7 +341,7 @@ class _RawTouchGestureDetectorRegionState
} }
} }
onTwoFingerScaleUpdate(ScaleUpdateDetails d) { onTwoFingerScaleUpdate(ScaleUpdateDetails d) async {
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
} }
@ -343,7 +350,7 @@ class _RawTouchGestureDetectorRegionState
_scale = d.scale; _scale = d.scale;
if (scale != 0) { if (scale != 0) {
bind.sessionSendPointer( await bind.sessionSendPointer(
sessionId: sessionId, sessionId: sessionId,
msg: json.encode( msg: json.encode(
PointerEventToRust(kPointerEventKindTouch, 'scale', scale) PointerEventToRust(kPointerEventKindTouch, 'scale', scale)
@ -358,12 +365,12 @@ class _RawTouchGestureDetectorRegionState
} }
} }
onTwoFingerScaleEnd(ScaleEndDetails d) { onTwoFingerScaleEnd(ScaleEndDetails d) async {
if (lastDeviceKind != PointerDeviceKind.touch) { if (lastDeviceKind != PointerDeviceKind.touch) {
return; return;
} }
if ((isDesktop || isWebDesktop)) { if ((isDesktop || isWebDesktop)) {
bind.sessionSendPointer( await bind.sessionSendPointer(
sessionId: sessionId, sessionId: sessionId,
msg: json.encode( msg: json.encode(
PointerEventToRust(kPointerEventKindTouch, 'scale', 0).toJson())); PointerEventToRust(kPointerEventKindTouch, 'scale', 0).toJson()));
@ -373,7 +380,7 @@ class _RawTouchGestureDetectorRegionState
// No idea why we need to set the view style to "" here. // No idea why we need to set the view style to "" here.
// bind.sessionSetViewStyle(sessionId: sessionId, value: ""); // bind.sessionSetViewStyle(sessionId: sessionId, value: "");
} }
inputModel.sendMouse('up', MouseButtons.left); await inputModel.sendMouse('up', MouseButtons.left);
} }
get onHoldDragCancel => null; get onHoldDragCancel => null;

View File

@ -768,22 +768,22 @@ class InputModel {
} }
/// Send a mouse tap event(down and up). /// Send a mouse tap event(down and up).
void tap(MouseButtons button) { Future<void> tap(MouseButtons button) async {
sendMouse('down', button); await sendMouse('down', button);
sendMouse('up', button); await sendMouse('up', button);
} }
void tapDown(MouseButtons button) { Future<void> tapDown(MouseButtons button) async {
sendMouse('down', button); await sendMouse('down', button);
} }
void tapUp(MouseButtons button) { Future<void> tapUp(MouseButtons button) async {
sendMouse('up', button); await sendMouse('up', button);
} }
/// Send scroll event with scroll distance [y]. /// Send scroll event with scroll distance [y].
void scroll(int y) { Future<void> scroll(int y) async {
bind.sessionSendMouse( await bind.sessionSendMouse(
sessionId: sessionId, sessionId: sessionId,
msg: json msg: json
.encode(modify({'id': id, 'type': 'wheel', 'y': y.toString()}))); .encode(modify({'id': id, 'type': 'wheel', 'y': y.toString()})));
@ -804,9 +804,9 @@ class InputModel {
} }
/// Send mouse press event. /// Send mouse press event.
void sendMouse(String type, MouseButtons button) { Future<void> sendMouse(String type, MouseButtons button) async {
if (!keyboardPerm) return; if (!keyboardPerm) return;
bind.sessionSendMouse( await bind.sessionSendMouse(
sessionId: sessionId, sessionId: sessionId,
msg: json.encode(modify({'type': type, 'buttons': button.value}))); msg: json.encode(modify({'type': type, 'buttons': button.value})));
} }
@ -830,11 +830,11 @@ class InputModel {
} }
/// Send mouse movement event with distance in [x] and [y]. /// Send mouse movement event with distance in [x] and [y].
void moveMouse(double x, double y) { Future<void> moveMouse(double x, double y) async {
if (!keyboardPerm) return; if (!keyboardPerm) return;
var x2 = x.toInt(); var x2 = x.toInt();
var y2 = y.toInt(); var y2 = y.toInt();
bind.sessionSendMouse( await bind.sessionSendMouse(
sessionId: sessionId, sessionId: sessionId,
msg: json.encode(modify({'x': '$x2', 'y': '$y2'}))); msg: json.encode(modify({'x': '$x2', 'y': '$y2'})));
} }

View File

@ -2038,7 +2038,7 @@ class CursorModel with ChangeNotifier {
} }
// For touch mode // For touch mode
move(double x, double y) { Future<bool> move(double x, double y) async {
if (shouldBlock(x, y)) { if (shouldBlock(x, y)) {
_lastIsBlocked = true; _lastIsBlocked = true;
return false; return false;
@ -2047,7 +2047,7 @@ class CursorModel with ChangeNotifier {
if (!_moveLocalIfInRemoteRect(x, y)) { if (!_moveLocalIfInRemoteRect(x, y)) {
return false; return false;
} }
parent.target?.inputModel.moveMouse(_x, _y); await parent.target?.inputModel.moveMouse(_x, _y);
return true; return true;
} }
@ -2105,9 +2105,9 @@ class CursorModel with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
updatePan(Offset delta, Offset localPosition, bool touchMode) { updatePan(Offset delta, Offset localPosition, bool touchMode) async {
if (touchMode) { if (touchMode) {
_handleTouchMode(delta, localPosition); await _handleTouchMode(delta, localPosition);
return; return;
} }
double dx = delta.dx; double dx = delta.dx;
@ -2205,7 +2205,7 @@ class CursorModel with ChangeNotifier {
return x >= 0 && y >= 0 && x <= w && y <= h; return x >= 0 && y >= 0 && x <= w && y <= h;
} }
_handleTouchMode(Offset delta, Offset localPosition) { _handleTouchMode(Offset delta, Offset localPosition) async {
bool isMoved = false; bool isMoved = false;
if (_remoteWindowCoords.isNotEmpty && if (_remoteWindowCoords.isNotEmpty &&
_windowRect != null && _windowRect != null &&
@ -2221,7 +2221,7 @@ class CursorModel with ChangeNotifier {
coords.canvas.scale; coords.canvas.scale;
x2 += coords.cursor.offset.dx; x2 += coords.cursor.offset.dx;
y2 += coords.cursor.offset.dy; y2 += coords.cursor.offset.dy;
parent.target?.inputModel.moveMouse(x2, y2); await parent.target?.inputModel.moveMouse(x2, y2);
isMoved = true; isMoved = true;
} }
} }
@ -2264,7 +2264,7 @@ class CursorModel with ChangeNotifier {
_x = movement.dx; _x = movement.dx;
_y = movement.dy; _y = movement.dy;
parent.target?.inputModel.moveMouse(_x, _y); await parent.target?.inputModel.moveMouse(_x, _y);
} }
notifyListeners(); notifyListeners();
} }