diff --git a/flutter/lib/common/widgets/gestures.dart b/flutter/lib/common/widgets/gestures.dart
index 6c2696567..b3cfeae6e 100644
--- a/flutter/lib/common/widgets/gestures.dart
+++ b/flutter/lib/common/widgets/gestures.dart
@@ -86,7 +86,7 @@ class CustomTouchGestureRecognizer extends ScaleGestureRecognizer {
       // end
       switch (_currentState) {
         case GestureState.oneFingerPan:
-          debugPrint("TwoFingerState.pan onEnd");
+          debugPrint("OneFingerState.pan onEnd");
           if (onOneFingerPanEnd != null) {
             onOneFingerPanEnd!(_getDragEndDetails(d));
           }
diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart
index 352da9e6f..c313958bd 100644
--- a/flutter/lib/consts.dart
+++ b/flutter/lib/consts.dart
@@ -169,6 +169,13 @@ const int kWindowMainId = 0;
 const String kPointerEventKindTouch = "touch";
 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 kKeyShowDisplaysAsIndividualWindows =
diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart
index 3f413c499..0cc0537d6 100644
--- a/flutter/lib/models/input_model.dart
+++ b/flutter/lib/models/input_model.dart
@@ -856,7 +856,7 @@ class InputModel {
     _stopFling = true;
     if (isViewOnly) return;
     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 (peerPlatform == kPeerPlatformAndroid) {
-        handlePointerEvent(
-            'touch', 'pan_update', Offset(x.toDouble(), y.toDouble()));
+        handlePointerEvent('touch', kMouseEventTypePanUpdate,
+            Offset(x.toDouble(), y.toDouble()));
       } else {
         bind.sessionSendMouse(
             sessionId: sessionId,
@@ -962,7 +962,7 @@ class InputModel {
 
   void onPointerPanZoomEnd(PointerPanZoomEndEvent e) {
     if (peerPlatform == kPeerPlatformAndroid) {
-      handlePointerEvent('touch', 'pan_end', e.position);
+      handlePointerEvent('touch', kMouseEventTypePanEnd, e.position);
       return;
     }
 
@@ -1080,7 +1080,7 @@ class InputModel {
         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) {
       v = min;
     }
@@ -1120,13 +1120,13 @@ class InputModel {
     // to-do: handle mouse events
 
     late final dynamic evtValue;
-    if (type == 'pan_update') {
+    if (type == kMouseEventTypePanUpdate) {
       evtValue = {
         'x': x.toInt(),
         'y': y.toInt(),
       };
     } else {
-      final isMoveTypes = ['pan_start', 'pan_end'];
+      final isMoveTypes = [kMouseEventTypePanStart, kMouseEventTypePanEnd];
       final pos = handlePointerDevicePos(
         kPointerEventKindTouch,
         x,
@@ -1181,14 +1181,14 @@ class InputModel {
       return;
     }
 
-    var type = '';
+    var type = kMouseEventTypeDefault;
     var isMove = false;
     switch (evt['type']) {
       case _kMouseEventDown:
-        type = 'down';
+        type = kMouseEventTypeDown;
         break;
       case _kMouseEventUp:
-        type = 'up';
+        type = kMouseEventTypeUp;
         break;
       case _kMouseEventMove:
         _pointerMovedAfterEnter = true;
@@ -1199,7 +1199,7 @@ class InputModel {
     }
     evt['type'] = type;
 
-    if (type == 'down' && !_pointerMovedAfterEnter) {
+    if (type == kMouseEventTypeDown && !_pointerMovedAfterEnter) {
       // Move mouse to the position of the down event first.
       lastMousePos = ui.Offset(x, y);
       refreshMousePos();
@@ -1372,6 +1372,14 @@ class InputModel {
       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();
     // https://github.com/rustdesk/rustdesk/issues/6678
     // For Windows, [0,maxX], [0,maxY] should be set to enable window snapping.
@@ -1380,15 +1388,34 @@ class InputModel {
     int minY = rect.top.toInt();
     int maxY = (rect.top + rect.height).toInt() -
         (peerPlatform == kPeerPlatformWindows ? 0 : 1);
-    evtX = trySetNearestRange(evtX, minX, maxX, 5);
-    evtY = trySetNearestRange(evtY, minY, maxY, 5);
-    if (kind == kPointerEventKindMouse) {
-      if (evtX < minX || evtY < minY || evtX > maxX || evtY > maxY) {
-        // If left mouse up, no early return.
-        if (!(buttons == kPrimaryMouseButton && evtType == 'up')) {
-          return null;
+    evtX = InputModel.tryGetNearestRange(evtX, minX, maxX, 5);
+    evtY = InputModel.tryGetNearestRange(evtY, minY, maxY, 5);
+    if (isLocalDesktop) {
+      if (kind == kPointerEventKindMouse) {
+        if (evtX < minX || evtY < minY || evtX > maxX || evtY > maxY) {
+          // If left mouse up, no early return.
+          if (!(buttons == kPrimaryMouseButton &&
+              evtType == kMouseEventTypeUp)) {
+            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);
diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart
index 80a6809d5..7765ebc40 100644
--- a/flutter/lib/models/model.dart
+++ b/flutter/lib/models/model.dart
@@ -6,6 +6,7 @@ import 'dart:ui' as ui;
 
 import 'package:bot_toast/bot_toast.dart';
 import 'package:desktop_multi_window/desktop_multi_window.dart';
+import 'package:flutter/gestures.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_hbb/common/widgets/peers_view.dart';
@@ -1516,10 +1517,13 @@ class CanvasModel with ChangeNotifier {
     _x = (size.width - displayWidth * _scale) / 2;
     _y = (size.height - displayHeight * _scale) / 2;
     _imageOverflow.value = _x < 0 || y < 0;
+    if (isMobile && style == kRemoteViewStyleOriginal) {
+      _moveToCenterCursor();
+    }
     if (notify) {
       notifyListeners();
     }
-    if (refreshMousePos) {
+    if (!isMobile && refreshMousePos) {
       parent.target?.inputModel.refreshMousePos();
     }
     tryUpdateScrollStyle(Duration.zero, style);
@@ -1709,8 +1713,6 @@ class CanvasModel with ChangeNotifier {
     _timerMobileFocusCanvasCursor =
         Timer(Duration(milliseconds: 100), () async {
       await updateViewStyle(refreshMousePos: false, notify: false);
-      _moveToCenterCursor();
-      parent.target?.cursorModel.ensureCursorInVisibleRect();
       notifyListeners();
     });
   }
@@ -2015,17 +2017,6 @@ class CursorModel with ChangeNotifier {
     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;
 
   // mobile Soft keyboard, block touch event from the KeyHelpTools
@@ -2042,6 +2033,7 @@ class CursorModel with ChangeNotifier {
     return false;
   }
 
+  // For touch mode
   move(double x, double y) {
     if (shouldBlock(x, y)) {
       _lastIsBlocked = true;
@@ -2129,13 +2121,34 @@ class CursorModel with ChangeNotifier {
     }
 
     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) {
-      parent.target?.canvasModel.panX(-dx);
+      parent.target?.canvasModel.panX(-dx * scale);
     }
     if (tryMoveCanvasY && dy != 0) {
-      parent.target?.canvasModel.panY(-dy);
+      parent.target?.canvasModel.panY(-dy * scale);
     }
 
     parent.target?.inputModel.moveMouse(_x, _y);