From a3afb0310940aa6afe7772f52a10a8049332a8c6 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 13 Nov 2022 23:41:07 +0800 Subject: [PATCH 1/7] fix cursor (hotx,hoty) && add default remote cursor image Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_page.dart | 20 ++-- flutter/lib/mobile/pages/remote_page.dart | 14 ++- flutter/lib/models/model.dart | 107 ++++++++++++--------- 3 files changed, 83 insertions(+), 58 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 21cbe45b9..8d0de3b41 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -340,10 +340,8 @@ class ImagePaint extends StatelessWidget { return FlutterCustomMemoryImageCursor( pixbuf: cache.data, key: key, - // hotx: cache.hotx, - // hoty: cache.hoty, - hotx: 0, - hoty: 0, + hotx: cache.hotx, + hoty: cache.hoty, imageWidth: (cache.width * cache.scale).toInt(), imageHeight: (cache.height * cache.scale).toInt(), ); @@ -488,11 +486,19 @@ class CursorPaint extends StatelessWidget { final m = Provider.of(context); final c = Provider.of(context); // final adjust = m.adjustForKeyboard(); + double hotx = m.hotx; + double hoty = m.hoty; + if (m.image == null) { + if (m.defaultCache != null) { + hotx = m.defaultCache!.hotx; + hoty = m.defaultCache!.hoty; + } + } return CustomPaint( painter: ImagePainter( - image: m.image, - x: m.x - m.hotx + c.x / c.scale, - y: m.y - m.hoty + c.y / c.scale, + image: m.image ?? m.defaultImage, + x: m.x - hotx + c.x / c.scale, + y: m.y - hoty + c.y / c.scale, scale: c.scale), ); } diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 0662fce2b..5dd01264b 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -862,11 +862,19 @@ class CursorPaint extends StatelessWidget { final c = Provider.of(context); final adjust = gFFI.cursorModel.adjustForKeyboard(); var s = c.scale; + double hotx = m.hotx; + double hoty = m.hoty; + if (m.image == null) { + if (m.defaultCache != null) { + hotx = m.defaultCache!.hotx; + hoty = m.defaultCache!.hoty; + } + } return CustomPaint( painter: ImagePainter( - image: m.image, - x: m.x * s - m.hotx + c.x, - y: m.y * s - m.hoty + c.y - adjust, + image: m.image ?? m.defaultImage, + x: m.x * s - hotx + c.x, + y: m.y * s - hoty + c.y - adjust, scale: 1), ); } diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 53a040eed..61185b016 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -721,8 +721,11 @@ class CursorData { height: (height * scale).toInt(), ) .getBytes(format: img2.Format.bgra); - hotx = (width * scale) / 2; - hoty = (height * scale) / 2; + if (hotx > 0 && hoty > 0) { + // default cursor data + hotx = (width * scale) / 2; + hoty = (height * scale) / 2; + } } } this.scale = scale; @@ -737,6 +740,7 @@ class CursorData { class CursorModel with ChangeNotifier { ui.Image? _image; + ui.Image? _defaultImage; final _images = >{}; CursorData? _cache; final _defaultCacheId = -1; @@ -756,6 +760,7 @@ class CursorModel with ChangeNotifier { WeakReference parent; ui.Image? get image => _image; + ui.Image? get defaultImage => _defaultImage; CursorData? get cache => _cache; CursorData? get defaultCache => _getDefaultCache(); @@ -771,30 +776,45 @@ class CursorModel with ChangeNotifier { DateTime.now().difference(_last_peer_mouse).inMilliseconds < kMouseControlTimeoutMSec; - CursorModel(this.parent); + CursorModel(this.parent) { + _getDefaultImage(); + _getDefaultCache(); + } Set get cachedKeys => _cacheKeys; addKey(String key) => _cacheKeys.add(key); + Future _getDefaultImage() async { + if (_defaultImage == null) { + final defaultImg = defaultCursorImage!; + // This function is called only one time, no need to care about the performance. + Uint8List data = defaultImg.getBytes(format: img2.Format.rgba); + _defaultImage = await img.decodeImageFromPixels( + data, defaultImg.width, defaultImg.height, ui.PixelFormat.rgba8888); + } + return _defaultImage; + } + CursorData? _getDefaultCache() { if (_defaultCache == null) { + Uint8List data; if (Platform.isWindows) { - Uint8List data = defaultCursorImage!.getBytes(format: img2.Format.bgra); - _hotx = defaultCursorImage!.width / 2; - _hoty = defaultCursorImage!.height / 2; - - _defaultCache = CursorData( - peerId: id, - id: _defaultCacheId, - image: defaultCursorImage?.clone(), - scale: 1.0, - data: data, - hotx: _hotx, - hoty: _hoty, - width: defaultCursorImage!.width, - height: defaultCursorImage!.height, - ); + data = defaultCursorImage!.getBytes(format: img2.Format.bgra); + } else { + data = Uint8List.fromList(img2.encodePng(defaultCursorImage!)); } + double scale = 1.0; + _defaultCache = CursorData( + peerId: id, + id: _defaultCacheId, + image: defaultCursorImage?.clone(), + scale: scale, + data: data, + hotx: (defaultCursorImage!.width * scale) / 2, + hoty: (defaultCursorImage!.height * scale) / 2, + width: defaultCursorImage!.width, + height: defaultCursorImage!.height, + ); } return _defaultCache; } @@ -926,13 +946,15 @@ class CursorModel with ChangeNotifier { var height = int.parse(evt['height']); List colors = json.decode(evt['colors']); final rgba = Uint8List.fromList(colors.map((s) => s as int).toList()); - var pid = parent.target?.id; final image = await img.decodeImageFromPixels( rgba, width, height, ui.PixelFormat.rgba8888); - if (parent.target?.id != pid) return; _image = image; - _images[id] = Tuple3(image, _hotx, _hoty); - await _updateCache(image, id, width, height); + if (await _updateCache(image, id, width, height)) { + _images[id] = Tuple3(image, _hotx, _hoty); + } else { + _hotx = 0; + _hoty = 0; + } try { // my throw exception, because the listener maybe already dispose notifyListeners(); @@ -941,44 +963,33 @@ class CursorModel with ChangeNotifier { } } - _updateCache(ui.Image image, int id, int w, int h) async { - Uint8List? data; - img2.Image? image2; + Future _updateCache(ui.Image image, int id, int w, int h) async { + ui.ImageByteFormat imgFormat = ui.ImageByteFormat.png; if (Platform.isWindows) { - ByteData? data2 = - await image.toByteData(format: ui.ImageByteFormat.rawRgba); - if (data2 != null) { - data = data2.buffer.asUint8List(); - image2 = img2.Image.fromBytes(w, h, data); - } else { - data = defaultCursorImage?.getBytes(format: img2.Format.bgra); - image2 = defaultCursorImage?.clone(); - _hotx = defaultCursorImage!.width / 2; - _hoty = defaultCursorImage!.height / 2; - } - } else { - ByteData? data2 = await image.toByteData(format: ui.ImageByteFormat.png); - if (data2 != null) { - data = data2.buffer.asUint8List(); - } else { - data = Uint8List.fromList(img2.encodePng(defaultCursorImage!)); - _hotx = defaultCursorImage!.width / 2; - _hoty = defaultCursorImage!.height / 2; - } + imgFormat = ui.ImageByteFormat.rawRgba; } + ByteData? imgBytes = await image.toByteData(format: imgFormat); + if (imgBytes == null) { + return false; + } + + Uint8List? data = imgBytes.buffer.asUint8List(); _cache = CursorData( peerId: this.id, id: id, - image: image2, + image: Platform.isWindows ? img2.Image.fromBytes(w, h, data) : null, scale: 1.0, data: data, - hotx: _hotx, - hoty: _hoty, + hotx: 0, + hoty: 0, + // hotx: _hotx, + // hoty: _hoty, width: w, height: h, ); _cacheMap[id] = _cache!; + return true; } updateCursorId(Map evt) async { From 60a30042c0b1359bb846f579787bc3a8b65a8bbb Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 13 Nov 2022 19:35:59 -0800 Subject: [PATCH 2/7] cursor pos linux Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_page.dart | 4 ++-- flutter/lib/mobile/pages/remote_page.dart | 8 ++++---- flutter/lib/models/model.dart | 19 +++++++++++-------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 8d0de3b41..015eb3037 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -490,8 +490,8 @@ class CursorPaint extends StatelessWidget { double hoty = m.hoty; if (m.image == null) { if (m.defaultCache != null) { - hotx = m.defaultCache!.hotx; - hoty = m.defaultCache!.hoty; + hotx = m.defaultImage!.width / 2; + hoty = m.defaultImage!.height / 2; } } return CustomPaint( diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 5dd01264b..07304d2d3 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -866,15 +866,15 @@ class CursorPaint extends StatelessWidget { double hoty = m.hoty; if (m.image == null) { if (m.defaultCache != null) { - hotx = m.defaultCache!.hotx; - hoty = m.defaultCache!.hoty; + hotx = m.defaultImage!.width / 2; + hoty = m.defaultImage!.height / 2; } } return CustomPaint( painter: ImagePainter( image: m.image ?? m.defaultImage, - x: m.x * s - hotx + c.x, - y: m.y * s - hoty + c.y - adjust, + x: m.x * s - hotx * s + c.x, + y: m.y * s - hoty * s + c.y - adjust, scale: 1), ); } diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 61185b016..cf4c63952 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -721,14 +721,14 @@ class CursorData { height: (height * scale).toInt(), ) .getBytes(format: img2.Format.bgra); - if (hotx > 0 && hoty > 0) { - // default cursor data - hotx = (width * scale) / 2; - hoty = (height * scale) / 2; - } } } this.scale = scale; + if (hotx > 0 && hoty > 0) { + // default cursor data + hotx = (width * scale) / 2; + hoty = (height * scale) / 2; + } return scale; } @@ -798,20 +798,23 @@ class CursorModel with ChangeNotifier { CursorData? _getDefaultCache() { if (_defaultCache == null) { Uint8List data; + double scale = 1.0; + double hotx = (defaultCursorImage!.width * scale) / 2; + double hoty = (defaultCursorImage!.height * scale) / 2; if (Platform.isWindows) { data = defaultCursorImage!.getBytes(format: img2.Format.bgra); } else { data = Uint8List.fromList(img2.encodePng(defaultCursorImage!)); } - double scale = 1.0; + _defaultCache = CursorData( peerId: id, id: _defaultCacheId, image: defaultCursorImage?.clone(), scale: scale, data: data, - hotx: (defaultCursorImage!.width * scale) / 2, - hoty: (defaultCursorImage!.height * scale) / 2, + hotx: hotx, + hoty: hoty, width: defaultCursorImage!.width, height: defaultCursorImage!.height, ); From 98bb47a81ddf751b16d87ccaa4f6da77ff4eda67 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 14 Nov 2022 15:05:44 +0800 Subject: [PATCH 3/7] fix cursor lost control sometime && refactor some Camel-Case flutter Signed-off-by: fufesou --- flutter/lib/models/input_model.dart | 22 +++++++++++----------- flutter/lib/models/model.dart | 14 +++++++------- src/server/input_service.rs | 20 ++++++++++++++++---- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index 30a01cda7..83171514d 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -42,7 +42,7 @@ class InputModel { // mouse final isPhysicalMouse = false.obs; int _lastMouseDownButtons = 0; - Offset last_mouse_pos = Offset.zero; + Offset lastMousePos = Offset.zero; get id => parent.target?.id ?? ""; @@ -308,23 +308,23 @@ class InputModel { double y = max(0.0, evt['y']); final cursorModel = parent.target!.cursorModel; - if (cursorModel.is_peer_control_protected) { - last_mouse_pos = ui.Offset(x, y); + if (cursorModel.isPeerControlProtected) { + lastMousePos = ui.Offset(x, y); return; } - if (!cursorModel.got_mouse_control) { - bool self_get_control = - (x - last_mouse_pos.dx).abs() > kMouseControlDistance || - (y - last_mouse_pos.dy).abs() > kMouseControlDistance; - if (self_get_control) { - cursorModel.got_mouse_control = true; + if (!cursorModel.gotMouseControl) { + bool selfGetControl = + (x - lastMousePos.dx).abs() > kMouseControlDistance || + (y - lastMousePos.dy).abs() > kMouseControlDistance; + if (selfGetControl) { + cursorModel.gotMouseControl = true; } else { - last_mouse_pos = ui.Offset(x, y); + lastMousePos = ui.Offset(x, y); return; } } - last_mouse_pos = ui.Offset(x, y); + lastMousePos = ui.Offset(x, y); var type = ''; var isMove = false; diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index cf4c63952..d7fc414d5 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -753,8 +753,8 @@ class CursorModel with ChangeNotifier { double _hoty = 0; double _displayOriginX = 0; double _displayOriginY = 0; - bool got_mouse_control = true; - DateTime _last_peer_mouse = DateTime.now() + bool gotMouseControl = true; + DateTime _lastPeerMouse = DateTime.now() .subtract(Duration(milliseconds: 2 * kMouseControlTimeoutMSec)); String id = ''; WeakReference parent; @@ -772,8 +772,8 @@ class CursorModel with ChangeNotifier { double get hotx => _hotx; double get hoty => _hoty; - bool get is_peer_control_protected => - DateTime.now().difference(_last_peer_mouse).inMilliseconds < + bool get isPeerControlProtected => + DateTime.now().difference(_lastPeerMouse).inMilliseconds < kMouseControlTimeoutMSec; CursorModel(this.parent) { @@ -806,7 +806,7 @@ class CursorModel with ChangeNotifier { } else { data = Uint8List.fromList(img2.encodePng(defaultCursorImage!)); } - + _defaultCache = CursorData( peerId: id, id: _defaultCacheId, @@ -1012,8 +1012,8 @@ class CursorModel with ChangeNotifier { /// Update the cursor position. updateCursorPosition(Map evt, String id) async { - got_mouse_control = false; - _last_peer_mouse = DateTime.now(); + gotMouseControl = false; + _lastPeerMouse = DateTime.now(); _x = double.parse(evt['x']); _y = double.parse(evt['y']); try { diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 780c1106a..653187bc3 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -209,6 +209,7 @@ lazy_static::lazy_static! { static EXITING: AtomicBool = AtomicBool::new(false); const MOUSE_MOVE_PROTECTION_TIMEOUT: Duration = Duration::from_millis(1_000); +// Actual diff of (x,y) is (1,1) here. But 5 may be tolerant. const MOUSE_ACTIVE_DISTANCE: i32 = 5; // mac key input must be run in main thread, otherwise crash on >= osx 10.15 @@ -406,14 +407,25 @@ fn active_mouse_(conn: i32) -> bool { return false; } + let in_actived_dist = |a: i32, b: i32| -> bool { (a - b).abs() < MOUSE_ACTIVE_DISTANCE }; + // check if input is in valid range match crate::get_cursor_pos() { Some((x, y)) => { - let can_active = (last_input.x - x).abs() < MOUSE_ACTIVE_DISTANCE - && (last_input.y - y).abs() < MOUSE_ACTIVE_DISTANCE; + let mut can_active = + in_actived_dist(last_input.x, x) && in_actived_dist(last_input.y, y); if !can_active { - last_input.x = -MOUSE_ACTIVE_DISTANCE * 2; - last_input.y = -MOUSE_ACTIVE_DISTANCE * 2; + // Try agin + // No need to care about sleep here. It's not a common case. + std::thread::sleep(std::time::Duration::from_micros(10)); + if let Some((x2, y2)) = crate::get_cursor_pos() { + can_active = + in_actived_dist(last_input.x, x2) && in_actived_dist(last_input.y, y2); + } + } + if !can_active { + last_input.x = INVALID_CURSOR_POS / 2; + last_input.y = INVALID_CURSOR_POS / 2; } can_active } From 7f640b77f0a902f7659e54944b3b86db9794b159 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 14 Nov 2022 16:16:38 +0800 Subject: [PATCH 4/7] fix cursor linux force update after remote cursor moved Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_page.dart | 34 ++++++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 015eb3037..2b8c99940 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -251,14 +251,12 @@ class _RemotePageState extends State bool get wantKeepAlive => true; } -class ImagePaint extends StatelessWidget { +class ImagePaint extends StatefulWidget { final String id; final Rx cursorOverImage; final Rx keyboardEnabled; final Rx remoteCursorMoved; final Widget Function(Widget)? listenerBuilder; - final ScrollController _horizontal = ScrollController(); - final ScrollController _vertical = ScrollController(); ImagePaint( {Key? key, @@ -269,6 +267,21 @@ class ImagePaint extends StatelessWidget { this.listenerBuilder}) : super(key: key); + @override + State createState() => _ImagePaintState(); +} + +class _ImagePaintState extends State { + bool _lastRemoteCursorMoved = false; + final ScrollController _horizontal = ScrollController(); + final ScrollController _vertical = ScrollController(); + + String get id => widget.id; + Rx get cursorOverImage => widget.cursorOverImage; + Rx get keyboardEnabled => widget.keyboardEnabled; + Rx get remoteCursorMoved => widget.remoteCursorMoved; + Widget Function(Widget)? get listenerBuilder => widget.listenerBuilder; + @override Widget build(BuildContext context) { final m = Provider.of(context); @@ -278,9 +291,18 @@ class ImagePaint extends StatelessWidget { mouseRegion({child}) => Obx(() => MouseRegion( cursor: cursorOverImage.isTrue ? keyboardEnabled.isTrue - ? (remoteCursorMoved.isTrue - ? SystemMouseCursors.none - : _buildCustomCursor(context, s)) + ? (() { + if (remoteCursorMoved.isTrue) { + _lastRemoteCursorMoved = true; + return SystemMouseCursors.none; + } else { + if (_lastRemoteCursorMoved) { + _lastRemoteCursorMoved = false; + _firstEnterImage.value = true; + } + return _buildCustomCursor(context, s); + } + }()) : _buildDisabledCursor(context, s) : MouseCursor.defer, onHover: (evt) {}, From 3d5be47b1b42802d0b3cd0a74a14dae35e8e53c6 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 14 Nov 2022 17:17:15 +0800 Subject: [PATCH 5/7] fix cursor key mismatch Signed-off-by: fufesou --- flutter/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index 56cb4b204..ed7fad5dd 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -72,7 +72,7 @@ dependencies: flutter_custom_cursor: git: url: https://github.com/Kingtous/rustdesk_flutter_custom_cursor - ref: ac3c1bf816197863cdcfa42d008962ff644132b0 + ref: bfb19c84a8244771488bc05cc5f9c9b5e0324cfd window_size: git: url: https://github.com/google/flutter-desktop-embedding.git From 47d7e7ad938103193e898cee4a2e730264545cb7 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 14 Nov 2022 17:54:39 +0800 Subject: [PATCH 6/7] input service, trivial refactor for cursor Signed-off-by: fufesou --- src/server/input_service.rs | 43 ++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 653187bc3..4650865bd 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -126,7 +126,7 @@ pub fn new_pos() -> GenericService { } fn update_last_cursor_pos(x: i32, y: i32) { - let mut lock = LATEST_CURSOR_POS.lock().unwrap(); + let mut lock = LATEST_SYS_CURSOR_POS.lock().unwrap(); if lock.1 .0 != x || lock.1 .1 != y { (lock.0, lock.1) = (Instant::now(), (x, y)) } @@ -144,7 +144,7 @@ fn run_pos(sp: GenericService, state: &mut StatePos) -> ResultType<()> { }); let exclude = { let now = get_time(); - let lock = LATEST_INPUT_CURSOR.lock().unwrap(); + let lock = LATEST_PEER_INPUT_CURSOR.lock().unwrap(); if now - lock.time < 300 { lock.conn } else { @@ -203,8 +203,8 @@ lazy_static::lazy_static! { Arc::new(Mutex::new(Enigo::new())) }; static ref KEYS_DOWN: Arc>> = Default::default(); - static ref LATEST_INPUT_CURSOR: Arc> = Default::default(); - static ref LATEST_CURSOR_POS: Arc> = Arc::new(Mutex::new((Instant::now().sub(MOUSE_MOVE_PROTECTION_TIMEOUT), (0, 0)))); + static ref LATEST_PEER_INPUT_CURSOR: Arc> = Default::default(); + static ref LATEST_SYS_CURSOR_POS: Arc> = Arc::new(Mutex::new((Instant::now().sub(MOUSE_MOVE_PROTECTION_TIMEOUT), (0, 0)))); } static EXITING: AtomicBool = AtomicBool::new(false); @@ -397,13 +397,12 @@ fn fix_modifiers(modifiers: &[EnumOrUnknown], en: &mut Enigo, ck: i3 fn active_mouse_(conn: i32) -> bool { // out of time protection - if LATEST_CURSOR_POS.lock().unwrap().0.elapsed() > MOUSE_MOVE_PROTECTION_TIMEOUT { + if LATEST_SYS_CURSOR_POS.lock().unwrap().0.elapsed() > MOUSE_MOVE_PROTECTION_TIMEOUT { return true; } - let mut last_input = LATEST_INPUT_CURSOR.lock().unwrap(); // last conn input may be protected - if last_input.conn != conn { + if LATEST_PEER_INPUT_CURSOR.lock().unwrap().conn != conn { return false; } @@ -412,20 +411,25 @@ fn active_mouse_(conn: i32) -> bool { // check if input is in valid range match crate::get_cursor_pos() { Some((x, y)) => { + let (last_in_x, last_in_y) = { + let lock = LATEST_PEER_INPUT_CURSOR.lock().unwrap(); + (lock.x, lock.y) + }; let mut can_active = - in_actived_dist(last_input.x, x) && in_actived_dist(last_input.y, y); + in_actived_dist(last_in_x, x) && in_actived_dist(last_in_y, y); if !can_active { // Try agin // No need to care about sleep here. It's not a common case. std::thread::sleep(std::time::Duration::from_micros(10)); if let Some((x2, y2)) = crate::get_cursor_pos() { can_active = - in_actived_dist(last_input.x, x2) && in_actived_dist(last_input.y, y2); + in_actived_dist(last_in_x, x2) && in_actived_dist(last_in_y, y2); } } if !can_active { - last_input.x = INVALID_CURSOR_POS / 2; - last_input.y = INVALID_CURSOR_POS / 2; + let mut lock = LATEST_PEER_INPUT_CURSOR.lock().unwrap(); + lock.x = INVALID_CURSOR_POS / 2; + lock.y = INVALID_CURSOR_POS / 2; } can_active } @@ -446,15 +450,6 @@ fn handle_mouse_(evt: &MouseEvent, conn: i32) { crate::platform::windows::try_change_desktop(); let buttons = evt.mask >> 3; let evt_type = evt.mask & 0x7; - if evt_type == 0 { - let time = get_time(); - *LATEST_INPUT_CURSOR.lock().unwrap() = Input { - time, - conn, - x: evt.x, - y: evt.y, - }; - } let mut en = ENIGO.lock().unwrap(); #[cfg(not(target_os = "macos"))] let mut to_release = Vec::new(); @@ -479,6 +474,14 @@ fn handle_mouse_(evt: &MouseEvent, conn: i32) { } match evt_type { 0 => { + let time = get_time(); + *LATEST_PEER_INPUT_CURSOR.lock().unwrap() = Input { + time, + conn, + x: evt.x, + y: evt.y, + }; + en.mouse_move_to(evt.x, evt.y); } 1 => match buttons { From e6698f32d79cda41b84896f9e5485049fa75fe48 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 14 Nov 2022 18:39:49 +0800 Subject: [PATCH 7/7] Add some comments on mouse handler(input service) Signed-off-by: fufesou --- src/server/input_service.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 4650865bd..f2591df0b 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -408,7 +408,7 @@ fn active_mouse_(conn: i32) -> bool { let in_actived_dist = |a: i32, b: i32| -> bool { (a - b).abs() < MOUSE_ACTIVE_DISTANCE }; - // check if input is in valid range + // Check if input is in valid range match crate::get_cursor_pos() { Some((x, y)) => { let (last_in_x, last_in_y) = { @@ -417,10 +417,13 @@ fn active_mouse_(conn: i32) -> bool { }; let mut can_active = in_actived_dist(last_in_x, x) && in_actived_dist(last_in_y, y); + // The cursor may not have been moved to last input position if system is busy now. + // While this is not a common case, we check it again after some time later. if !can_active { - // Try agin - // No need to care about sleep here. It's not a common case. + // 10 micros may be enough for system to move cursor. + // We do not care about the situation which system is too slow(more than 10 micros is required). std::thread::sleep(std::time::Duration::from_micros(10)); + // Sleep here can also somehow suppress delay accumulation. if let Some((x2, y2)) = crate::get_cursor_pos() { can_active = in_actived_dist(last_in_x, x2) && in_actived_dist(last_in_y, y2);