mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-03-30 00:21:02 +03:00
feat: Add relative mouse mode (#13928)
* feat: Add relative mouse mode - Add "Relative Mouse Mode" toggle in desktop toolbar and bind to InputModel - Implement relative mouse movement path: Flutter pointer deltas -> `type: move_relative` -> new `MOUSE_TYPE_MOVE_RELATIVE` in Rust - In server input service, simulate relative movement via Enigo and keep latest cursor position in sync - Track pointer-lock center in Flutter (local widget + screen coordinates) and re-center OS cursor after each relative move - Update pointer-lock center on window move/resize/restore/maximize and when remote display geometry changes - Hide local cursor when relative mouse mode is active (both Flutter cursor and OS cursor), restore on leave/disable - On Windows, clip OS cursor to the window rect while in relative mode and release clip when leaving/turning off - Implement platform helpers: `get_cursor_pos`, `set_cursor_pos`, `show_cursor`, `clip_cursor` (no-op clip/hide on Linux for now) - Add keyboard shortcut Ctrl+Alt+Shift+M to toggle relative mode (enabled by default, works on all platforms) - Remove `enable-relative-mouse-shortcut` config option - shortcut is now always available when keyboard permission is granted - Handle window blur/focus/minimize events to properly release/restore cursor constraints - Add MOUSE_TYPE_MASK constant and unit tests for mouse event constants Note: Relative mouse mode state is NOT persisted to config (session-only). Note: On Linux, show_cursor and clip_cursor are no-ops; cursor hiding is handled by Flutter side. Signed-off-by: fufesou <linlong1266@gmail.com> * feat(mouse): relative mouse mode, exit hint Signed-off-by: fufesou <linlong1266@gmail.com> * refact(relative mouse): shortcut Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
@@ -71,6 +71,19 @@ pub mod input {
|
||||
pub const MOUSE_TYPE_UP: i32 = 2;
|
||||
pub const MOUSE_TYPE_WHEEL: i32 = 3;
|
||||
pub const MOUSE_TYPE_TRACKPAD: i32 = 4;
|
||||
/// Relative mouse movement type for gaming/3D applications.
|
||||
/// This type sends delta (dx, dy) values instead of absolute coordinates.
|
||||
/// NOTE: This is only supported by the Flutter client. The Sciter client (deprecated)
|
||||
/// does not support relative mouse mode due to:
|
||||
/// 1. Fixed send_mouse() function signature that doesn't allow type differentiation
|
||||
/// 2. Lack of pointer lock API in Sciter/TIS
|
||||
/// 3. No OS cursor control (hide/show/clip) FFI bindings in Sciter UI
|
||||
pub const MOUSE_TYPE_MOVE_RELATIVE: i32 = 5;
|
||||
|
||||
/// Mask to extract the mouse event type from the mask field.
|
||||
/// The lower 3 bits contain the event type (MOUSE_TYPE_*), giving a valid range of 0-7.
|
||||
/// Currently defined types use values 0-5; values 6 and 7 are reserved for future use.
|
||||
pub const MOUSE_TYPE_MASK: i32 = 0x7;
|
||||
|
||||
pub const MOUSE_BUTTON_LEFT: i32 = 0x01;
|
||||
pub const MOUSE_BUTTON_RIGHT: i32 = 0x02;
|
||||
@@ -175,6 +188,20 @@ pub fn is_support_file_transfer_resume_num(ver: i64) -> bool {
|
||||
ver >= hbb_common::get_version_number("1.4.2")
|
||||
}
|
||||
|
||||
/// Minimum server version required for relative mouse mode support.
|
||||
/// This constant must mirror Flutter's `kMinVersionForRelativeMouseMode` in `consts.dart`.
|
||||
const MIN_VERSION_RELATIVE_MOUSE_MODE: &str = "1.4.5";
|
||||
|
||||
#[inline]
|
||||
pub fn is_support_relative_mouse_mode(ver: &str) -> bool {
|
||||
is_support_relative_mouse_mode_num(hbb_common::get_version_number(ver))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_support_relative_mouse_mode_num(ver: i64) -> bool {
|
||||
ver >= hbb_common::get_version_number(MIN_VERSION_RELATIVE_MOUSE_MODE)
|
||||
}
|
||||
|
||||
// is server process, with "--server" args
|
||||
#[inline]
|
||||
pub fn is_server() -> bool {
|
||||
@@ -2462,4 +2489,36 @@ mod tests {
|
||||
assert!(!is_public("https://rustdesk.computer.com"));
|
||||
assert!(!is_public("rustdesk.comhello.com"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mouse_event_constants_and_mask_layout() {
|
||||
use super::input::*;
|
||||
|
||||
// Verify MOUSE_TYPE constants are unique and within the mask range.
|
||||
let types = [
|
||||
MOUSE_TYPE_MOVE,
|
||||
MOUSE_TYPE_DOWN,
|
||||
MOUSE_TYPE_UP,
|
||||
MOUSE_TYPE_WHEEL,
|
||||
MOUSE_TYPE_TRACKPAD,
|
||||
MOUSE_TYPE_MOVE_RELATIVE,
|
||||
];
|
||||
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
for t in types.iter() {
|
||||
assert!(seen.insert(*t), "Duplicate mouse type: {}", t);
|
||||
assert_eq!(
|
||||
*t & MOUSE_TYPE_MASK,
|
||||
*t,
|
||||
"Mouse type {} exceeds mask {}",
|
||||
t,
|
||||
MOUSE_TYPE_MASK
|
||||
);
|
||||
}
|
||||
|
||||
// The mask layout is: lower 3 bits for type, upper bits for buttons (shifted by 3).
|
||||
let combined_mask = MOUSE_TYPE_DOWN | ((MOUSE_BUTTON_LEFT | MOUSE_BUTTON_RIGHT) << 3);
|
||||
assert_eq!(combined_mask & MOUSE_TYPE_MASK, MOUSE_TYPE_DOWN);
|
||||
assert_eq!(combined_mask >> 3, MOUSE_BUTTON_LEFT | MOUSE_BUTTON_RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user