fix: mobile mouse mode, cursor range (#9811)

Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
fufesou 2024-11-04 22:37:21 +08:00 committed by GitHub
parent 040253b319
commit 12c1337b7b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 84 additions and 37 deletions

View File

@ -86,7 +86,7 @@ class CustomTouchGestureRecognizer extends ScaleGestureRecognizer {
// end // end
switch (_currentState) { switch (_currentState) {
case GestureState.oneFingerPan: case GestureState.oneFingerPan:
debugPrint("TwoFingerState.pan onEnd"); debugPrint("OneFingerState.pan onEnd");
if (onOneFingerPanEnd != null) { if (onOneFingerPanEnd != null) {
onOneFingerPanEnd!(_getDragEndDetails(d)); onOneFingerPanEnd!(_getDragEndDetails(d));
} }

View File

@ -169,6 +169,13 @@ const int kWindowMainId = 0;
const String kPointerEventKindTouch = "touch"; const String kPointerEventKindTouch = "touch";
const String kPointerEventKindMouse = "mouse"; const String kPointerEventKindMouse = "mouse";
const String kMouseEventTypeDefault = "";
const String kMouseEventTypePanStart = "pan_start";
const String kMouseEventTypePanUpdate = "pan_update";
const String kMouseEventTypePanEnd = "pan_end";
const String kMouseEventTypeDown = "down";
const String kMouseEventTypeUp = "up";
const String kKeyFlutterKey = "flutter_key"; const String kKeyFlutterKey = "flutter_key";
const String kKeyShowDisplaysAsIndividualWindows = const String kKeyShowDisplaysAsIndividualWindows =

View File

@ -856,7 +856,7 @@ class InputModel {
_stopFling = true; _stopFling = true;
if (isViewOnly) return; if (isViewOnly) return;
if (peerPlatform == kPeerPlatformAndroid) { if (peerPlatform == kPeerPlatformAndroid) {
handlePointerEvent('touch', 'pan_start', e.position); handlePointerEvent('touch', kMouseEventTypePanStart, e.position);
} }
} }
@ -899,8 +899,8 @@ class InputModel {
} }
if (x != 0 || y != 0) { if (x != 0 || y != 0) {
if (peerPlatform == kPeerPlatformAndroid) { if (peerPlatform == kPeerPlatformAndroid) {
handlePointerEvent( handlePointerEvent('touch', kMouseEventTypePanUpdate,
'touch', 'pan_update', Offset(x.toDouble(), y.toDouble())); Offset(x.toDouble(), y.toDouble()));
} else { } else {
bind.sessionSendMouse( bind.sessionSendMouse(
sessionId: sessionId, sessionId: sessionId,
@ -962,7 +962,7 @@ class InputModel {
void onPointerPanZoomEnd(PointerPanZoomEndEvent e) { void onPointerPanZoomEnd(PointerPanZoomEndEvent e) {
if (peerPlatform == kPeerPlatformAndroid) { if (peerPlatform == kPeerPlatformAndroid) {
handlePointerEvent('touch', 'pan_end', e.position); handlePointerEvent('touch', kMouseEventTypePanEnd, e.position);
return; return;
} }
@ -1080,7 +1080,7 @@ class InputModel {
onExit: true, onExit: true,
); );
int trySetNearestRange(int v, int min, int max, int n) { static int tryGetNearestRange(int v, int min, int max, int n) {
if (v < min && v >= min - n) { if (v < min && v >= min - n) {
v = min; v = min;
} }
@ -1120,13 +1120,13 @@ class InputModel {
// to-do: handle mouse events // to-do: handle mouse events
late final dynamic evtValue; late final dynamic evtValue;
if (type == 'pan_update') { if (type == kMouseEventTypePanUpdate) {
evtValue = { evtValue = {
'x': x.toInt(), 'x': x.toInt(),
'y': y.toInt(), 'y': y.toInt(),
}; };
} else { } else {
final isMoveTypes = ['pan_start', 'pan_end']; final isMoveTypes = [kMouseEventTypePanStart, kMouseEventTypePanEnd];
final pos = handlePointerDevicePos( final pos = handlePointerDevicePos(
kPointerEventKindTouch, kPointerEventKindTouch,
x, x,
@ -1181,14 +1181,14 @@ class InputModel {
return; return;
} }
var type = ''; var type = kMouseEventTypeDefault;
var isMove = false; var isMove = false;
switch (evt['type']) { switch (evt['type']) {
case _kMouseEventDown: case _kMouseEventDown:
type = 'down'; type = kMouseEventTypeDown;
break; break;
case _kMouseEventUp: case _kMouseEventUp:
type = 'up'; type = kMouseEventTypeUp;
break; break;
case _kMouseEventMove: case _kMouseEventMove:
_pointerMovedAfterEnter = true; _pointerMovedAfterEnter = true;
@ -1199,7 +1199,7 @@ class InputModel {
} }
evt['type'] = type; evt['type'] = type;
if (type == 'down' && !_pointerMovedAfterEnter) { if (type == kMouseEventTypeDown && !_pointerMovedAfterEnter) {
// Move mouse to the position of the down event first. // Move mouse to the position of the down event first.
lastMousePos = ui.Offset(x, y); lastMousePos = ui.Offset(x, y);
refreshMousePos(); refreshMousePos();
@ -1372,6 +1372,14 @@ class InputModel {
return null; return null;
} }
return InputModel.getPointInRemoteRect(
true, peerPlatform, kind, evtType, evtX, evtY, rect,
buttons: buttons);
}
static Point? getPointInRemoteRect(bool isLocalDesktop, String? peerPlatform,
String kind, String evtType, int evtX, int evtY, Rect rect,
{int buttons = kPrimaryMouseButton}) {
int minX = rect.left.toInt(); int minX = rect.left.toInt();
// https://github.com/rustdesk/rustdesk/issues/6678 // https://github.com/rustdesk/rustdesk/issues/6678
// For Windows, [0,maxX], [0,maxY] should be set to enable window snapping. // For Windows, [0,maxX], [0,maxY] should be set to enable window snapping.
@ -1380,16 +1388,35 @@ class InputModel {
int minY = rect.top.toInt(); int minY = rect.top.toInt();
int maxY = (rect.top + rect.height).toInt() - int maxY = (rect.top + rect.height).toInt() -
(peerPlatform == kPeerPlatformWindows ? 0 : 1); (peerPlatform == kPeerPlatformWindows ? 0 : 1);
evtX = trySetNearestRange(evtX, minX, maxX, 5); evtX = InputModel.tryGetNearestRange(evtX, minX, maxX, 5);
evtY = trySetNearestRange(evtY, minY, maxY, 5); evtY = InputModel.tryGetNearestRange(evtY, minY, maxY, 5);
if (isLocalDesktop) {
if (kind == kPointerEventKindMouse) { if (kind == kPointerEventKindMouse) {
if (evtX < minX || evtY < minY || evtX > maxX || evtY > maxY) { if (evtX < minX || evtY < minY || evtX > maxX || evtY > maxY) {
// If left mouse up, no early return. // If left mouse up, no early return.
if (!(buttons == kPrimaryMouseButton && evtType == 'up')) { if (!(buttons == kPrimaryMouseButton &&
evtType == kMouseEventTypeUp)) {
return null; return null;
} }
} }
} }
} else {
bool evtXInRange = evtX >= minX && evtX <= maxX;
bool evtYInRange = evtY >= minY && evtY <= maxY;
if (!(evtXInRange || evtYInRange)) {
return null;
}
if (evtX < minX) {
evtX = minX;
} else if (evtX > maxX) {
evtX = maxX;
}
if (evtY < minY) {
evtY = minY;
} else if (evtY > maxY) {
evtY = maxY;
}
}
return Point(evtX, evtY); return Point(evtX, evtY);
} }

View File

@ -6,6 +6,7 @@ import 'dart:ui' as ui;
import 'package:bot_toast/bot_toast.dart'; import 'package:bot_toast/bot_toast.dart';
import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_hbb/common/widgets/peers_view.dart'; import 'package:flutter_hbb/common/widgets/peers_view.dart';
@ -1516,10 +1517,13 @@ class CanvasModel with ChangeNotifier {
_x = (size.width - displayWidth * _scale) / 2; _x = (size.width - displayWidth * _scale) / 2;
_y = (size.height - displayHeight * _scale) / 2; _y = (size.height - displayHeight * _scale) / 2;
_imageOverflow.value = _x < 0 || y < 0; _imageOverflow.value = _x < 0 || y < 0;
if (isMobile && style == kRemoteViewStyleOriginal) {
_moveToCenterCursor();
}
if (notify) { if (notify) {
notifyListeners(); notifyListeners();
} }
if (refreshMousePos) { if (!isMobile && refreshMousePos) {
parent.target?.inputModel.refreshMousePos(); parent.target?.inputModel.refreshMousePos();
} }
tryUpdateScrollStyle(Duration.zero, style); tryUpdateScrollStyle(Duration.zero, style);
@ -1709,8 +1713,6 @@ class CanvasModel with ChangeNotifier {
_timerMobileFocusCanvasCursor = _timerMobileFocusCanvasCursor =
Timer(Duration(milliseconds: 100), () async { Timer(Duration(milliseconds: 100), () async {
await updateViewStyle(refreshMousePos: false, notify: false); await updateViewStyle(refreshMousePos: false, notify: false);
_moveToCenterCursor();
parent.target?.cursorModel.ensureCursorInVisibleRect();
notifyListeners(); notifyListeners();
}); });
} }
@ -2015,17 +2017,6 @@ class CursorModel with ChangeNotifier {
return Offset(xoffset, yoffset); return Offset(xoffset, yoffset);
} }
void ensureCursorInVisibleRect() {
final ensureVisibleValue = 50.0;
final r = getVisibleRect();
final minX = r.left;
final maxX = max(r.right - ensureVisibleValue, r.left);
final minY = r.top;
final maxY = max(r.bottom - ensureVisibleValue, minY);
_x = min(max(_x, minX), maxX);
_y = min(max(_y, minY), maxY);
}
get scale => parent.target?.canvasModel.scale ?? 1.0; get scale => parent.target?.canvasModel.scale ?? 1.0;
// mobile Soft keyboard, block touch event from the KeyHelpTools // mobile Soft keyboard, block touch event from the KeyHelpTools
@ -2042,6 +2033,7 @@ class CursorModel with ChangeNotifier {
return false; return false;
} }
// For touch mode
move(double x, double y) { move(double x, double y) {
if (shouldBlock(x, y)) { if (shouldBlock(x, y)) {
_lastIsBlocked = true; _lastIsBlocked = true;
@ -2129,13 +2121,34 @@ class CursorModel with ChangeNotifier {
} }
if (dx == 0 && dy == 0) return; if (dx == 0 && dy == 0) return;
_x += dx;
_y += dy; Point? newPos;
final rect = parent.target?.ffiModel.rect;
if (rect == null) {
// unreachable
return;
}
newPos = InputModel.getPointInRemoteRect(
false,
parent.target?.ffiModel.pi.platform,
kPointerEventKindMouse,
kMouseEventTypeDefault,
(_x + dx).toInt(),
(_y + dy).toInt(),
rect,
buttons: kPrimaryButton);
if (newPos == null) {
return;
}
dx = newPos.x - _x;
dy = newPos.y - _y;
_x = newPos.x.toDouble();
_y = newPos.y.toDouble();
if (tryMoveCanvasX && dx != 0) { if (tryMoveCanvasX && dx != 0) {
parent.target?.canvasModel.panX(-dx); parent.target?.canvasModel.panX(-dx * scale);
} }
if (tryMoveCanvasY && dy != 0) { if (tryMoveCanvasY && dy != 0) {
parent.target?.canvasModel.panY(-dy); parent.target?.canvasModel.panY(-dy * scale);
} }
parent.target?.inputModel.moveMouse(_x, _y); parent.target?.inputModel.moveMouse(_x, _y);