mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-04-05 13:11:28 +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:
@@ -116,12 +116,51 @@ pub fn get_focused_display(displays: Vec<DisplayInfo>) -> Option<usize> {
|
||||
|
||||
pub fn get_cursor_pos() -> Option<(i32, i32)> {
|
||||
unsafe {
|
||||
#[allow(invalid_value)]
|
||||
let mut out = mem::MaybeUninit::uninit().assume_init();
|
||||
if GetCursorPos(&mut out) == FALSE {
|
||||
let mut out = mem::MaybeUninit::<POINT>::uninit();
|
||||
if GetCursorPos(out.as_mut_ptr()) == FALSE {
|
||||
return None;
|
||||
}
|
||||
return Some((out.x, out.y));
|
||||
let out = out.assume_init();
|
||||
Some((out.x, out.y))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_cursor_pos(x: i32, y: i32) -> bool {
|
||||
unsafe {
|
||||
if SetCursorPos(x, y) == FALSE {
|
||||
let err = GetLastError();
|
||||
log::warn!("SetCursorPos failed: x={}, y={}, error_code={}", x, y, err);
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Clip cursor to a rectangle. Pass None to unclip.
|
||||
pub fn clip_cursor(rect: Option<(i32, i32, i32, i32)>) -> bool {
|
||||
unsafe {
|
||||
let result = match rect {
|
||||
Some((left, top, right, bottom)) => {
|
||||
let r = RECT {
|
||||
left,
|
||||
top,
|
||||
right,
|
||||
bottom,
|
||||
};
|
||||
ClipCursor(&r)
|
||||
}
|
||||
None => ClipCursor(std::ptr::null()),
|
||||
};
|
||||
if result == FALSE {
|
||||
let err = GetLastError();
|
||||
log::warn!(
|
||||
"ClipCursor failed: rect={:?}, error_code={}",
|
||||
rect,
|
||||
err
|
||||
);
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user