diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index 95e900653..9e85b2b82 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:io'; import 'dart:math'; import 'dart:ui' as ui; @@ -45,12 +46,11 @@ class InputModel { var command = false; // trackpad - final _trackpadSpeed = 0.06; var _trackpadLastDelta = Offset.zero; - var _trackpadScrollUnsent = Offset.zero; var _stopFling = true; + var _fling = false; Timer? _flingTimer; - final _flingBaseDelay = 10; + final _flingBaseDelay = 30; // mouse final isPhysicalMouse = false.obs; @@ -327,63 +327,39 @@ class InputModel { // https://docs.flutter.dev/release/breaking-changes/trackpad-gestures // TODO(support zoom in/out) void onPointerPanZoomUpdate(PointerPanZoomUpdateEvent e) { - var delta = e.panDelta; + final delta = e.panDelta; _trackpadLastDelta = delta; - _trackpadScrollUnsent += (delta * _trackpadSpeed); - var x = _trackpadScrollUnsent.dx.truncate(); - var y = _trackpadScrollUnsent.dy.truncate(); - _trackpadScrollUnsent -= Offset(x.toDouble(), y.toDouble()); - bind.sessionSendMouse( - id: id, msg: '{"type": "trackpad", "x": "$x", "y": "$y"}'); + var x = delta.dx.toInt(); + var y = delta.dy.toInt(); + if (x != 0 || y != 0) { + bind.sessionSendMouse( + id: id, msg: '{"type": "trackpad", "x": "$x", "y": "$y"}'); + } } void _scheduleFling(double x, double y, int delay) { if ((x == 0 && y == 0) || _stopFling) { + _fling = false; return; } _flingTimer = Timer(Duration(milliseconds: delay), () { if (_stopFling) { + _fling = false; return; } - final d = 0.93; + final d = 0.97; x *= d; y *= d; - final dx0 = x * _trackpadSpeed; - final dy0 = y * _trackpadSpeed; // Try set delta (x,y) and delay. - var dx = dx0.truncate(); - var dy = dy0.truncate(); + var dx = x.toInt(); + var dy = y.toInt(); var delay = _flingBaseDelay; - setMinDelta(double v) { - double minThr = _trackpadSpeed * 2; - return v > minThr ? 1 : (v < -minThr ? -1 : 0); - } - - // Try set min delta (x,y), and increase delay. - if (dx == 0 && dy == 0) { - final thr = 25; - var vx = thr; - var vy = thr; - if (dx0 != 0) { - vx = 1.0 ~/ dx0.abs(); - } - if (dy0 != 0) { - vy = 1.0 ~/ dy0.abs(); - } - if (vx < vy) { - delay *= (vx < thr ? vx : thr); - dx = setMinDelta(dx0); - } else if (vy < thr) { - delay *= (vy < thr ? vy : thr); - dy = setMinDelta(dy0); - } - } - if (dx == 0 && dy == 0) { + _fling = false; return; } @@ -393,13 +369,28 @@ class InputModel { }); } + void waitLastFlingDone() { + if (_fling) { + _stopFling = true; + } + for (var i = 0; i < 5; i++) { + if (!_fling) { + break; + } + sleep(Duration(milliseconds: 10)); + } + _flingTimer?.cancel(); + } + void onPointerPanZoomEnd(PointerPanZoomEndEvent e) { + waitLastFlingDone(); _stopFling = false; - _trackpadScrollUnsent = Offset.zero; + // 2.0 is an experience value double minFlingValue = 2.0; if (_trackpadLastDelta.dx.abs() > minFlingValue || _trackpadLastDelta.dy.abs() > minFlingValue) { + _fling = true; _scheduleFling( _trackpadLastDelta.dx, _trackpadLastDelta.dy, _flingBaseDelay); } diff --git a/libs/enigo/examples/mouse.rs b/libs/enigo/examples/mouse.rs index f963e041e..c815b2d59 100644 --- a/libs/enigo/examples/mouse.rs +++ b/libs/enigo/examples/mouse.rs @@ -1,4 +1,5 @@ use enigo::{Enigo, MouseButton, MouseControllable}; +use winapi::um::winuser::WHEEL_DELTA; use std::thread; use std::time::Duration; @@ -11,30 +12,22 @@ fn main() { enigo.mouse_move_to(500, 200); thread::sleep(wait_time); - enigo.mouse_down(MouseButton::Left).ok(); - thread::sleep(wait_time); - - enigo.mouse_move_relative(100, 100); - thread::sleep(wait_time); - - enigo.mouse_up(MouseButton::Left); - thread::sleep(wait_time); enigo.mouse_click(MouseButton::Left); thread::sleep(wait_time); #[cfg(not(target_os = "macos"))] { - enigo.mouse_scroll_x(2); + enigo.mouse_scroll_x(2 * WHEEL_DELTA as i32); thread::sleep(wait_time); - enigo.mouse_scroll_x(-2); + enigo.mouse_scroll_x(-2 * WHEEL_DELTA as i32); thread::sleep(wait_time); - enigo.mouse_scroll_y(2); + enigo.mouse_scroll_y(2 * WHEEL_DELTA as i32); thread::sleep(wait_time); - enigo.mouse_scroll_y(-2); + enigo.mouse_scroll_y(-2 * WHEEL_DELTA as i32); thread::sleep(wait_time); } } diff --git a/libs/enigo/src/win/win_impl.rs b/libs/enigo/src/win/win_impl.rs index f183e94ae..0598eb608 100644 --- a/libs/enigo/src/win/win_impl.rs +++ b/libs/enigo/src/win/win_impl.rs @@ -21,11 +21,9 @@ static mut LAYOUT: HKL = std::ptr::null_mut(); pub const ENIGO_INPUT_EXTRA_VALUE: ULONG_PTR = 100; fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD { - let mut input: INPUT = unsafe { std::mem::MaybeUninit::zeroed().assume_init() }; - input.type_ = INPUT_MOUSE; + let mut u = INPUT_u::default(); unsafe { - let dst_ptr = (&mut input.u as *mut _) as *mut u8; - let m = MOUSEINPUT { + *u.mi_mut() = MOUSEINPUT { dx, dy, mouseData: data, @@ -33,9 +31,11 @@ fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD { time: 0, dwExtraInfo: ENIGO_INPUT_EXTRA_VALUE, }; - let src_ptr = (&m as *const _) as *const u8; - std::ptr::copy_nonoverlapping(src_ptr, dst_ptr, size_of::()); } + let mut input = INPUT { + type_: INPUT_MOUSE, + u, + }; unsafe { SendInput(1, &mut input as LPINPUT, size_of::() as c_int) } } @@ -154,8 +154,8 @@ impl MouseControllable for Enigo { } }, match button { - MouseButton::Back => XBUTTON1 as _, - MouseButton::Forward => XBUTTON2 as _, + MouseButton::Back => XBUTTON1 as u32 * WHEEL_DELTA as u32, + MouseButton::Forward => XBUTTON2 as u32 * WHEEL_DELTA as u32, _ => 0, }, 0, @@ -199,11 +199,11 @@ impl MouseControllable for Enigo { } fn mouse_scroll_x(&mut self, length: i32) { - mouse_event(MOUSEEVENTF_HWHEEL, unsafe { transmute(length * 120) }, 0, 0); + mouse_event(MOUSEEVENTF_HWHEEL, length as _, 0, 0); } fn mouse_scroll_y(&mut self, length: i32) { - mouse_event(MOUSEEVENTF_WHEEL, unsafe { transmute(length * 120) }, 0, 0); + mouse_event(MOUSEEVENTF_WHEEL, length as _, 0, 0); } } diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 0e3aa59c3..2455a4673 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -6,6 +6,10 @@ use crate::{ common::make_fd_to_json, flutter::{self, SESSIONS}, flutter::{session_add, session_start_}, + server::input_service::{ + MOUSE_BUTTON_BACK, MOUSE_BUTTON_FORWARD, MOUSE_BUTTON_LEFT, MOUSE_BUTTON_RIGHT, + MOUSE_BUTTON_WHEEL, MOUSE_TYPE_DOWN, MOUSE_TYPE_TRACKPAD, MOUSE_TYPE_UP, MOUSE_TYPE_WHEEL, + }, ui_interface::{self, *}, }; use flutter_rust_bridge::{StreamSink, SyncReturn}; @@ -1054,20 +1058,20 @@ pub fn session_send_mouse(id: String, msg: String) { let mut mask = 0; if let Some(_type) = m.get("type") { mask = match _type.as_str() { - "down" => 1, - "up" => 2, - "wheel" => 3, - "trackpad" => 4, + "down" => MOUSE_TYPE_DOWN, + "up" => MOUSE_TYPE_UP, + "wheel" => MOUSE_TYPE_WHEEL, + "trackpad" => MOUSE_TYPE_TRACKPAD, _ => 0, }; } if let Some(buttons) = m.get("buttons") { mask |= match buttons.as_str() { - "left" => 0x01, - "right" => 0x02, - "wheel" => 0x04, - "back" => 0x08, - "forward" => 0x10, + "left" => MOUSE_BUTTON_LEFT, + "right" => MOUSE_BUTTON_RIGHT, + "wheel" => MOUSE_BUTTON_WHEEL, + "back" => MOUSE_BUTTON_BACK, + "forward" => MOUSE_BUTTON_FORWARD, _ => 0, } << 3; } diff --git a/src/server/input_service.rs b/src/server/input_service.rs index ed34ed00c..2c6cf1726 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -17,9 +17,22 @@ use std::{ thread, time::{self, Duration, Instant}, }; +use winapi::um::winuser::WHEEL_DELTA; const INVALID_CURSOR_POS: i32 = i32::MIN; +pub const MOUSE_TYPE_MOVE: i32 = 0; +pub const MOUSE_TYPE_DOWN: i32 = 1; +pub const MOUSE_TYPE_UP: i32 = 2; +pub const MOUSE_TYPE_WHEEL: i32 = 3; +pub const MOUSE_TYPE_TRACKPAD: i32 = 4; + +pub const MOUSE_BUTTON_LEFT: i32 = 0x01; +pub const MOUSE_BUTTON_RIGHT: i32 = 0x02; +pub const MOUSE_BUTTON_WHEEL: i32 = 0x04; +pub const MOUSE_BUTTON_BACK: i32 = 0x08; +pub const MOUSE_BUTTON_FORWARD: i32 = 0x10; + #[derive(Default)] struct StateCursor { hcursor: u64, @@ -777,7 +790,7 @@ pub fn handle_mouse_(evt: &MouseEvent, conn: i32) { } } match evt_type { - 0 => { + MOUSE_TYPE_MOVE => { en.mouse_move_to(evt.x, evt.y); *LATEST_PEER_INPUT_CURSOR.lock().unwrap() = Input { conn, @@ -786,43 +799,43 @@ pub fn handle_mouse_(evt: &MouseEvent, conn: i32) { y: evt.y, }; } - 1 => match buttons { - 0x01 => { + MOUSE_TYPE_DOWN => match buttons { + MOUSE_BUTTON_LEFT => { allow_err!(en.mouse_down(MouseButton::Left)); } - 0x02 => { + MOUSE_BUTTON_RIGHT => { allow_err!(en.mouse_down(MouseButton::Right)); } - 0x04 => { + MOUSE_BUTTON_WHEEL => { allow_err!(en.mouse_down(MouseButton::Middle)); } - 0x08 => { + MOUSE_BUTTON_BACK => { allow_err!(en.mouse_down(MouseButton::Back)); } - 0x10 => { + MOUSE_BUTTON_FORWARD => { allow_err!(en.mouse_down(MouseButton::Forward)); } _ => {} }, - 2 => match buttons { - 0x01 => { + MOUSE_TYPE_UP => match buttons { + MOUSE_BUTTON_LEFT => { en.mouse_up(MouseButton::Left); } - 0x02 => { + MOUSE_BUTTON_RIGHT => { en.mouse_up(MouseButton::Right); } - 0x04 => { + MOUSE_BUTTON_WHEEL => { en.mouse_up(MouseButton::Middle); } - 0x08 => { + MOUSE_BUTTON_BACK => { en.mouse_up(MouseButton::Back); } - 0x10 => { + MOUSE_BUTTON_FORWARD => { en.mouse_up(MouseButton::Forward); } _ => {} }, - 3 | 4 => { + MOUSE_TYPE_WHEEL | MOUSE_TYPE_TRACKPAD => { #[allow(unused_mut)] let mut x = evt.x; #[allow(unused_mut)] @@ -857,14 +870,20 @@ pub fn handle_mouse_(evt: &MouseEvent, conn: i32) { } } + #[cfg(windows)] + if evt_type == MOUSE_TYPE_WHEEL { + x *= WHEEL_DELTA as i32; + y *= WHEEL_DELTA as i32; + } + #[cfg(not(target_os = "macos"))] { - if x != 0 { - en.mouse_scroll_x(x); - } if y != 0 { en.mouse_scroll_y(y); } + if x != 0 { + en.mouse_scroll_x(x); + } } } _ => {}