fix, win mouse, touchpad scroll

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2023-06-07 20:01:01 +08:00
parent c69d59596b
commit c4f9650d7f
5 changed files with 96 additions and 89 deletions

View File

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'dart:ui' as ui; import 'dart:ui' as ui;
@ -45,12 +46,11 @@ class InputModel {
var command = false; var command = false;
// trackpad // trackpad
final _trackpadSpeed = 0.06;
var _trackpadLastDelta = Offset.zero; var _trackpadLastDelta = Offset.zero;
var _trackpadScrollUnsent = Offset.zero;
var _stopFling = true; var _stopFling = true;
var _fling = false;
Timer? _flingTimer; Timer? _flingTimer;
final _flingBaseDelay = 10; final _flingBaseDelay = 30;
// mouse // mouse
final isPhysicalMouse = false.obs; final isPhysicalMouse = false.obs;
@ -327,63 +327,39 @@ class InputModel {
// https://docs.flutter.dev/release/breaking-changes/trackpad-gestures // https://docs.flutter.dev/release/breaking-changes/trackpad-gestures
// TODO(support zoom in/out) // TODO(support zoom in/out)
void onPointerPanZoomUpdate(PointerPanZoomUpdateEvent e) { void onPointerPanZoomUpdate(PointerPanZoomUpdateEvent e) {
var delta = e.panDelta; final delta = e.panDelta;
_trackpadLastDelta = delta; _trackpadLastDelta = delta;
_trackpadScrollUnsent += (delta * _trackpadSpeed); var x = delta.dx.toInt();
var x = _trackpadScrollUnsent.dx.truncate(); var y = delta.dy.toInt();
var y = _trackpadScrollUnsent.dy.truncate(); if (x != 0 || y != 0) {
_trackpadScrollUnsent -= Offset(x.toDouble(), y.toDouble()); bind.sessionSendMouse(
bind.sessionSendMouse( id: id, msg: '{"type": "trackpad", "x": "$x", "y": "$y"}');
id: id, msg: '{"type": "trackpad", "x": "$x", "y": "$y"}'); }
} }
void _scheduleFling(double x, double y, int delay) { void _scheduleFling(double x, double y, int delay) {
if ((x == 0 && y == 0) || _stopFling) { if ((x == 0 && y == 0) || _stopFling) {
_fling = false;
return; return;
} }
_flingTimer = Timer(Duration(milliseconds: delay), () { _flingTimer = Timer(Duration(milliseconds: delay), () {
if (_stopFling) { if (_stopFling) {
_fling = false;
return; return;
} }
final d = 0.93; final d = 0.97;
x *= d; x *= d;
y *= d; y *= d;
final dx0 = x * _trackpadSpeed;
final dy0 = y * _trackpadSpeed;
// Try set delta (x,y) and delay. // Try set delta (x,y) and delay.
var dx = dx0.truncate(); var dx = x.toInt();
var dy = dy0.truncate(); var dy = y.toInt();
var delay = _flingBaseDelay; 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) { if (dx == 0 && dy == 0) {
_fling = false;
return; 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) { void onPointerPanZoomEnd(PointerPanZoomEndEvent e) {
waitLastFlingDone();
_stopFling = false; _stopFling = false;
_trackpadScrollUnsent = Offset.zero;
// 2.0 is an experience value // 2.0 is an experience value
double minFlingValue = 2.0; double minFlingValue = 2.0;
if (_trackpadLastDelta.dx.abs() > minFlingValue || if (_trackpadLastDelta.dx.abs() > minFlingValue ||
_trackpadLastDelta.dy.abs() > minFlingValue) { _trackpadLastDelta.dy.abs() > minFlingValue) {
_fling = true;
_scheduleFling( _scheduleFling(
_trackpadLastDelta.dx, _trackpadLastDelta.dy, _flingBaseDelay); _trackpadLastDelta.dx, _trackpadLastDelta.dy, _flingBaseDelay);
} }

View File

@ -1,4 +1,5 @@
use enigo::{Enigo, MouseButton, MouseControllable}; use enigo::{Enigo, MouseButton, MouseControllable};
use winapi::um::winuser::WHEEL_DELTA;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
@ -11,30 +12,22 @@ fn main() {
enigo.mouse_move_to(500, 200); enigo.mouse_move_to(500, 200);
thread::sleep(wait_time); 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); enigo.mouse_click(MouseButton::Left);
thread::sleep(wait_time); thread::sleep(wait_time);
#[cfg(not(target_os = "macos"))] #[cfg(not(target_os = "macos"))]
{ {
enigo.mouse_scroll_x(2); enigo.mouse_scroll_x(2 * WHEEL_DELTA as i32);
thread::sleep(wait_time); thread::sleep(wait_time);
enigo.mouse_scroll_x(-2); enigo.mouse_scroll_x(-2 * WHEEL_DELTA as i32);
thread::sleep(wait_time); thread::sleep(wait_time);
enigo.mouse_scroll_y(2); enigo.mouse_scroll_y(2 * WHEEL_DELTA as i32);
thread::sleep(wait_time); thread::sleep(wait_time);
enigo.mouse_scroll_y(-2); enigo.mouse_scroll_y(-2 * WHEEL_DELTA as i32);
thread::sleep(wait_time); thread::sleep(wait_time);
} }
} }

View File

@ -21,11 +21,9 @@ static mut LAYOUT: HKL = std::ptr::null_mut();
pub const ENIGO_INPUT_EXTRA_VALUE: ULONG_PTR = 100; pub const ENIGO_INPUT_EXTRA_VALUE: ULONG_PTR = 100;
fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD { fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD {
let mut input: INPUT = unsafe { std::mem::MaybeUninit::zeroed().assume_init() }; let mut u = INPUT_u::default();
input.type_ = INPUT_MOUSE;
unsafe { unsafe {
let dst_ptr = (&mut input.u as *mut _) as *mut u8; *u.mi_mut() = MOUSEINPUT {
let m = MOUSEINPUT {
dx, dx,
dy, dy,
mouseData: data, mouseData: data,
@ -33,9 +31,11 @@ fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD {
time: 0, time: 0,
dwExtraInfo: ENIGO_INPUT_EXTRA_VALUE, dwExtraInfo: ENIGO_INPUT_EXTRA_VALUE,
}; };
let src_ptr = (&m as *const _) as *const u8;
std::ptr::copy_nonoverlapping(src_ptr, dst_ptr, size_of::<MOUSEINPUT>());
} }
let mut input = INPUT {
type_: INPUT_MOUSE,
u,
};
unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) } unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) }
} }
@ -154,8 +154,8 @@ impl MouseControllable for Enigo {
} }
}, },
match button { match button {
MouseButton::Back => XBUTTON1 as _, MouseButton::Back => XBUTTON1 as u32 * WHEEL_DELTA as u32,
MouseButton::Forward => XBUTTON2 as _, MouseButton::Forward => XBUTTON2 as u32 * WHEEL_DELTA as u32,
_ => 0, _ => 0,
}, },
0, 0,
@ -199,11 +199,11 @@ impl MouseControllable for Enigo {
} }
fn mouse_scroll_x(&mut self, length: i32) { 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) { 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);
} }
} }

View File

@ -6,6 +6,10 @@ use crate::{
common::make_fd_to_json, common::make_fd_to_json,
flutter::{self, SESSIONS}, flutter::{self, SESSIONS},
flutter::{session_add, session_start_}, 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, *}, ui_interface::{self, *},
}; };
use flutter_rust_bridge::{StreamSink, SyncReturn}; use flutter_rust_bridge::{StreamSink, SyncReturn};
@ -1054,20 +1058,20 @@ pub fn session_send_mouse(id: String, msg: String) {
let mut mask = 0; let mut mask = 0;
if let Some(_type) = m.get("type") { if let Some(_type) = m.get("type") {
mask = match _type.as_str() { mask = match _type.as_str() {
"down" => 1, "down" => MOUSE_TYPE_DOWN,
"up" => 2, "up" => MOUSE_TYPE_UP,
"wheel" => 3, "wheel" => MOUSE_TYPE_WHEEL,
"trackpad" => 4, "trackpad" => MOUSE_TYPE_TRACKPAD,
_ => 0, _ => 0,
}; };
} }
if let Some(buttons) = m.get("buttons") { if let Some(buttons) = m.get("buttons") {
mask |= match buttons.as_str() { mask |= match buttons.as_str() {
"left" => 0x01, "left" => MOUSE_BUTTON_LEFT,
"right" => 0x02, "right" => MOUSE_BUTTON_RIGHT,
"wheel" => 0x04, "wheel" => MOUSE_BUTTON_WHEEL,
"back" => 0x08, "back" => MOUSE_BUTTON_BACK,
"forward" => 0x10, "forward" => MOUSE_BUTTON_FORWARD,
_ => 0, _ => 0,
} << 3; } << 3;
} }

View File

@ -17,9 +17,22 @@ use std::{
thread, thread,
time::{self, Duration, Instant}, time::{self, Duration, Instant},
}; };
use winapi::um::winuser::WHEEL_DELTA;
const INVALID_CURSOR_POS: i32 = i32::MIN; 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)] #[derive(Default)]
struct StateCursor { struct StateCursor {
hcursor: u64, hcursor: u64,
@ -777,7 +790,7 @@ pub fn handle_mouse_(evt: &MouseEvent, conn: i32) {
} }
} }
match evt_type { match evt_type {
0 => { MOUSE_TYPE_MOVE => {
en.mouse_move_to(evt.x, evt.y); en.mouse_move_to(evt.x, evt.y);
*LATEST_PEER_INPUT_CURSOR.lock().unwrap() = Input { *LATEST_PEER_INPUT_CURSOR.lock().unwrap() = Input {
conn, conn,
@ -786,43 +799,43 @@ pub fn handle_mouse_(evt: &MouseEvent, conn: i32) {
y: evt.y, y: evt.y,
}; };
} }
1 => match buttons { MOUSE_TYPE_DOWN => match buttons {
0x01 => { MOUSE_BUTTON_LEFT => {
allow_err!(en.mouse_down(MouseButton::Left)); allow_err!(en.mouse_down(MouseButton::Left));
} }
0x02 => { MOUSE_BUTTON_RIGHT => {
allow_err!(en.mouse_down(MouseButton::Right)); allow_err!(en.mouse_down(MouseButton::Right));
} }
0x04 => { MOUSE_BUTTON_WHEEL => {
allow_err!(en.mouse_down(MouseButton::Middle)); allow_err!(en.mouse_down(MouseButton::Middle));
} }
0x08 => { MOUSE_BUTTON_BACK => {
allow_err!(en.mouse_down(MouseButton::Back)); allow_err!(en.mouse_down(MouseButton::Back));
} }
0x10 => { MOUSE_BUTTON_FORWARD => {
allow_err!(en.mouse_down(MouseButton::Forward)); allow_err!(en.mouse_down(MouseButton::Forward));
} }
_ => {} _ => {}
}, },
2 => match buttons { MOUSE_TYPE_UP => match buttons {
0x01 => { MOUSE_BUTTON_LEFT => {
en.mouse_up(MouseButton::Left); en.mouse_up(MouseButton::Left);
} }
0x02 => { MOUSE_BUTTON_RIGHT => {
en.mouse_up(MouseButton::Right); en.mouse_up(MouseButton::Right);
} }
0x04 => { MOUSE_BUTTON_WHEEL => {
en.mouse_up(MouseButton::Middle); en.mouse_up(MouseButton::Middle);
} }
0x08 => { MOUSE_BUTTON_BACK => {
en.mouse_up(MouseButton::Back); en.mouse_up(MouseButton::Back);
} }
0x10 => { MOUSE_BUTTON_FORWARD => {
en.mouse_up(MouseButton::Forward); en.mouse_up(MouseButton::Forward);
} }
_ => {} _ => {}
}, },
3 | 4 => { MOUSE_TYPE_WHEEL | MOUSE_TYPE_TRACKPAD => {
#[allow(unused_mut)] #[allow(unused_mut)]
let mut x = evt.x; let mut x = evt.x;
#[allow(unused_mut)] #[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"))] #[cfg(not(target_os = "macos"))]
{ {
if x != 0 {
en.mouse_scroll_x(x);
}
if y != 0 { if y != 0 {
en.mouse_scroll_y(y); en.mouse_scroll_y(y);
} }
if x != 0 {
en.mouse_scroll_x(x);
}
} }
} }
_ => {} _ => {}