From 260c924010361137dd67be145e9d5c0850804768 Mon Sep 17 00:00:00 2001 From: xxrl <837951112@qq.com> Date: Mon, 7 Nov 2022 01:25:36 +0800 Subject: [PATCH 1/3] opt: mac scroll to fast --- libs/enigo/src/macos/macos_impl.rs | 57 ++++++++++++++++++++++++++++++ src/client.rs | 23 ++++++++++++ src/server/input_service.rs | 41 +++++++++++++++------ 3 files changed, 111 insertions(+), 10 deletions(-) diff --git a/libs/enigo/src/macos/macos_impl.rs b/libs/enigo/src/macos/macos_impl.rs index 520c9dca1..fb9c2d680 100644 --- a/libs/enigo/src/macos/macos_impl.rs +++ b/libs/enigo/src/macos/macos_impl.rs @@ -580,6 +580,63 @@ impl Enigo { _ => u16::MAX, } } + + #[inline] + fn mouse_scroll_impl(&mut self, length: i32, is_track_pad: bool, is_horizontal: bool) { + let mut scroll_direction = -1; // 1 left -1 right; + let mut length = length; + + if length < 0 { + length *= -1; + scroll_direction *= -1; + } + + // fix scroll distance for track pad + if is_track_pad { + length *= 3; + } + + if let Some(src) = self.event_source.as_ref() { + for _ in 0..length { + unsafe { + let units = if is_track_pad { + ScrollUnit::Pixel + } else { + ScrollUnit::Line + }; + let mouse_ev = if is_horizontal { + CGEventCreateScrollWheelEvent( + &src, + units, + 2, // CGWheelCount 1 = y 2 = xy 3 = xyz + 0, + scroll_direction, + ) + } else { + CGEventCreateScrollWheelEvent( + &src, + units, + 1, // CGWheelCount 1 = y 2 = xy 3 = xyz + scroll_direction, + ) + }; + + CGEventPost(CGEventTapLocation::HID, mouse_ev); + CFRelease(mouse_ev as *const std::ffi::c_void); + } + } + } + } + + /// handle scroll vertically + pub fn mouse_scroll_y(&mut self, length: i32, is_track_pad: bool) { + self.mouse_scroll_impl(length, is_track_pad, false) + } + + /// handle scroll horizontally + pub fn mouse_scroll_x(&mut self, length: i32, is_track_pad: bool) { + self.mouse_scroll_impl(length, is_track_pad, true) + } } #[inline] diff --git a/src/client.rs b/src/client.rs index d00df1c48..2be71828d 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1529,6 +1529,25 @@ pub async fn handle_test_delay(t: TestDelay, peer: &mut Stream) { } } +#[inline] +#[cfg(target_os = "macos")] +fn check_scroll_on_mac(mask: i32, x: i32, y: i32) -> bool { + if mask & 3 != 3 { + return false; + } + let btn = mask >> 3; + if y == -1 { + btn != 0xff88 && btn != -0x780000 + } else if y == 1 { + btn != 0x78 && btn != 0x780000 + } else if x != 0 { + // No mouse support horizontal scrolling. + true + } else { + false + } +} + /// Send mouse data. /// /// # Arguments @@ -1574,6 +1593,10 @@ pub fn send_mouse( if command { mouse_event.modifiers.push(ControlKey::Meta.into()); } + #[cfg(target_os = "macos")] + if check_scroll_on_mac(mask, x, y) { + mouse_event.modifiers.push(ControlKey::Scroll.into()); + } msg_out.set_mouse_event(mouse_event); interface.send(Data::Message(msg_out)); } diff --git a/src/server/input_service.rs b/src/server/input_service.rs index d91e9a799..ac46726ac 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -429,18 +429,39 @@ fn handle_mouse_(evt: &MouseEvent, conn: i32) { x = -x; y = -y; } - - // fix shift + scroll(down/up) #[cfg(target_os = "macos")] - if evt.modifiers.contains(&EnumOrUnknown::new(ControlKey::Shift)){ - x = y; - y = 0; + { + // TODO: support track pad on win. + let is_track_pad = evt + .modifiers + .contains(&EnumOrUnknown::new(ControlKey::Scroll)); + + // fix shift + scroll(down/up) + if !is_track_pad + && evt + .modifiers + .contains(&EnumOrUnknown::new(ControlKey::Shift)) + { + x = y; + y = 0; + } + + if x != 0 { + en.mouse_scroll_x(x, is_track_pad); + } + if y != 0 { + en.mouse_scroll_y(y, is_track_pad); + } } - if x != 0 { - en.mouse_scroll_x(x); - } - if y != 0 { - en.mouse_scroll_y(y); + + #[cfg(not(target_os = "macos"))] + { + if x != 0 { + en.mouse_scroll_x(x); + } + if y != 0 { + en.mouse_scroll_y(y); + } } } _ => {} From 4ce4830274b044584b8e52c9865ea203d2daedd0 Mon Sep 17 00:00:00 2001 From: xxrl <837951112@qq.com> Date: Sat, 12 Nov 2022 20:39:16 +0800 Subject: [PATCH 2/3] fix: disable check scroll for flutter mac --- src/client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client.rs b/src/client.rs index 2be71828d..768e7bc33 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1530,7 +1530,7 @@ pub async fn handle_test_delay(t: TestDelay, peer: &mut Stream) { } #[inline] -#[cfg(target_os = "macos")] +#[cfg(all(target_os = "macos", not(feature = "flutter")))] fn check_scroll_on_mac(mask: i32, x: i32, y: i32) -> bool { if mask & 3 != 3 { return false; @@ -1593,7 +1593,7 @@ pub fn send_mouse( if command { mouse_event.modifiers.push(ControlKey::Meta.into()); } - #[cfg(target_os = "macos")] + #[cfg(all(target_os = "macos", not(feature = "flutter")))] if check_scroll_on_mac(mask, x, y) { mouse_event.modifiers.push(ControlKey::Scroll.into()); } From 13fd55557be8a0f68dcdd0ed2f31d009ae4e7fb0 Mon Sep 17 00:00:00 2001 From: xxrl <837951112@qq.com> Date: Sun, 20 Nov 2022 22:46:27 +0800 Subject: [PATCH 3/3] feat: support track pad scroll on flutter --- flutter/lib/common/widgets/remote_input.dart | 3 ++ flutter/lib/models/input_model.dart | 57 ++++++++++++++++++++ src/client.rs | 11 ++-- src/flutter_ffi.rs | 2 + src/server/input_service.rs | 2 +- 5 files changed, 71 insertions(+), 4 deletions(-) diff --git a/flutter/lib/common/widgets/remote_input.dart b/flutter/lib/common/widgets/remote_input.dart index ad50d4839..89443e14f 100644 --- a/flutter/lib/common/widgets/remote_input.dart +++ b/flutter/lib/common/widgets/remote_input.dart @@ -51,6 +51,9 @@ class RawPointerMouseRegion extends StatelessWidget { onPointerUp: inputModel.onPointUpImage, onPointerMove: inputModel.onPointMoveImage, onPointerSignal: inputModel.onPointerSignalImage, + onPointerPanZoomStart: inputModel.onPointerPanZoomStart, + onPointerPanZoomUpdate: inputModel.onPointerPanZoomUpdate, + onPointerPanZoomEnd: inputModel.onPointerPanZoomEnd, child: MouseRegion( cursor: cursor ?? MouseCursor.defer, onEnter: onEnter, diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index 83171514d..eb1b4a3ff 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:math'; import 'dart:ui' as ui; @@ -39,6 +40,10 @@ class InputModel { var alt = false; var command = false; + // trackpad + var trackpadScrollDistance = Offset.zero; + Timer? _flingTimer; + // mouse final isPhysicalMouse = false.obs; int _lastMouseDownButtons = 0; @@ -236,6 +241,7 @@ class InputModel { if (!enter) { resetModifiers(); } + _flingTimer?.cancel(); bind.sessionEnterOrLeave(id: id, enter: enter); } @@ -258,6 +264,57 @@ class InputModel { } } + int _signOrZero(num x) { + if (x == 0) { + return 0; + } else { + return x > 0 ? 1 : -1; + } + } + + void onPointerPanZoomStart(PointerPanZoomStartEvent e) {} + + // https://docs.flutter.dev/release/breaking-changes/trackpad-gestures + // TODO(support zoom in/out) + void onPointerPanZoomUpdate(PointerPanZoomUpdateEvent e) { + var delta = e.panDelta; + trackpadScrollDistance += delta; + bind.sessionSendMouse( + id: id, + msg: + '{"type": "trackpad", "x": "${delta.dx.toInt()}", "y": "${delta.dy.toInt()}"}'); + } + + // Simple simulation for fling. + void _scheduleFling(var x, y, dx, dy) { + if (dx <= 0 && dy <= 0) { + return; + } + _flingTimer = Timer(Duration(milliseconds: 10), () { + bind.sessionSendMouse( + id: id, msg: '{"type": "trackpad", "x": "$x", "y": "$y"}'); + dx--; + dy--; + if (dx == 0) { + x = 0; + } + if (dy == 0) { + y = 0; + } + _scheduleFling(x, y, dx, dy); + }); + } + + void onPointerPanZoomEnd(PointerPanZoomEndEvent e) { + var x = _signOrZero(trackpadScrollDistance.dx); + var y = _signOrZero(trackpadScrollDistance.dy); + var dx = trackpadScrollDistance.dx.abs() ~/ 40; + var dy = trackpadScrollDistance.dy.abs() ~/ 40; + _scheduleFling(x, y, dx, dy); + + trackpadScrollDistance = Offset.zero; + } + void onPointDownImage(PointerDownEvent e) { debugPrint("onPointDownImage"); if (e.kind != ui.PointerDeviceKind.mouse) { diff --git a/src/client.rs b/src/client.rs index 3f738a369..b3be51cb4 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1572,9 +1572,14 @@ pub async fn handle_test_delay(t: TestDelay, peer: &mut Stream) { } } +/// Whether is track pad scrolling. #[inline] -#[cfg(all(target_os = "macos", not(feature = "flutter")))] +#[cfg(all(target_os = "macos"))] fn check_scroll_on_mac(mask: i32, x: i32, y: i32) -> bool { + // flutter version we set mask type bit to 4 when track pad scrolling. + if mask & 7 == 4 { + return true; + } if mask & 3 != 3 { return false; } @@ -1597,7 +1602,7 @@ fn check_scroll_on_mac(mask: i32, x: i32, y: i32) -> bool { /// /// * `mask` - Mouse event. /// * mask = buttons << 3 | type -/// * type, 1: down, 2: up, 3: wheel +/// * type, 1: down, 2: up, 3: wheel, 4: trackpad /// * buttons, 1: left, 2: right, 4: middle /// * `x` - X coordinate. /// * `y` - Y coordinate. @@ -1636,7 +1641,7 @@ pub fn send_mouse( if command { mouse_event.modifiers.push(ControlKey::Meta.into()); } - #[cfg(all(target_os = "macos", not(feature = "flutter")))] + #[cfg(all(target_os = "macos"))] if check_scroll_on_mac(mask, x, y) { mouse_event.modifiers.push(ControlKey::Scroll.into()); } diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 36e38f86e..bfee92f88 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -156,6 +156,7 @@ pub fn session_reconnect(id: String) { pub fn session_toggle_option(id: String, value: String) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { + log::warn!("toggle option {}", value); session.toggle_option(value); } } @@ -907,6 +908,7 @@ pub fn session_send_mouse(id: String, msg: String) { "down" => 1, "up" => 2, "wheel" => 3, + "trackpad" => 4, _ => 0, }; } diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 005c828bc..ca63fed94 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -513,7 +513,7 @@ pub fn handle_mouse_(evt: &MouseEvent) { } _ => {} }, - 3 => { + 3 | 4 => { #[allow(unused_mut)] let mut x = evt.x; #[allow(unused_mut)]