Skip to content

Commit

Permalink
win: Added setting to chose if the mouse speed and acceleration shoul…
Browse files Browse the repository at this point in the history
…d influence relative mouse moves
  • Loading branch information
pentamassiv committed Nov 19, 2024
1 parent 91dc725 commit 4713ea7
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- macOS: Fallback to ASCII-capable keyboard layout for handling non-standard input sources
- macOS: Check if the application has the necessary permissions. If they are missing, `enigo` will ask the user to grant them. You can change this default behavior with the `Settings` when constructing an `Enigo` struct.
- all: Added `Token::Location` and `Token::MainDisplay` mostly for debugging purposes. They allow you to check if your expectations are correct
- win: Added a setting to take the mouse speed and acceleration level into account for relative mouse movement or reliably move the mouse to the expected location.

## Fixed
- macOS: No more sleeps!! (Only when the `Enigo` struct is dropped) ([#105](https://github.com/enigo-rs/enigo/issues/105))
Expand Down
9 changes: 9 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ impl Error for NewConError {}

/// Settings for creating the Enigo struct and it's behavior
#[allow(dead_code)] // It is not dead code on other platforms
#[allow(clippy::struct_excessive_bools)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Settings {
Expand Down Expand Up @@ -460,6 +461,13 @@ pub struct Settings {
/// The default is true. If the Shift key for example is pressed,
/// following simulated input will not be capitalized.
pub independent_of_keyboard_state: bool,
/// If this is set to true, the relative mouse motion will be subject to the
/// settings for mouse speed and acceleration level. An end user sets
/// these values using the Mouse application in Control Panel. An
/// application obtains and sets these values with the
/// `windows::Win32::UI::WindowsAndMessaging::SystemParametersInfoA`
/// function. The default value is false.
pub windows_subject_to_mouse_speed_and_acceleration_level: bool,
}

impl Default for Settings {
Expand All @@ -474,6 +482,7 @@ impl Default for Settings {
release_keys_when_dropped: true,
open_prompt_to_get_permissions: true,
independent_of_keyboard_state: true,
windows_subject_to_mouse_speed_and_acceleration_level: false,
}
}
}
Expand Down
36 changes: 35 additions & 1 deletion src/win/win_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub struct Enigo {
held: (Vec<Key>, Vec<ScanCode>), // Currently held keys
release_keys_when_dropped: bool,
dw_extra_info: usize,
windows_subject_to_mouse_speed_and_acceleration_level: bool,
}

fn send_input(input: &[INPUT]) -> InputResult<()> {
Expand Down Expand Up @@ -169,9 +170,39 @@ impl Mouse for Enigo {
let y = y as i64;
let x = (x * 65535 + w / 2 * x.signum()) / w;
let y = (y * 65535 + h / 2 * y.signum()) / h;
// TODO: Check if we should use MOUSEEVENTF_VIRTUALDESK too
(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, x as i32, y as i32)
} else {
} else if self.windows_subject_to_mouse_speed_and_acceleration_level {
// Quote from documentation (http://web.archive.org/web/20241118235853/https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mouse_event):
// Relative mouse motion is subject to the settings for mouse speed and
// acceleration level. An end user sets these values using the Mouse application
// in Control Panel. An application obtains and sets these values with the
// SystemParametersInfo function.
//
// The system applies two tests to the specified relative mouse motion when
// applying acceleration. If the specified distance along either the x or y axis
// is greater than the first mouse threshold value, and the mouse acceleration
// level is not zero, the operating system doubles the distance. If the
// specified distance along either the x- or y-axis is greater than the second
// mouse threshold value, and the mouse acceleration level is equal to two, the
// operating system doubles the distance that resulted from applying the first
// threshold test. It is thus possible for the operating system to multiply
// relatively-specified mouse motion along the x- or y-axis by up to four times.
//
// Once acceleration has been applied, the system scales the resultant value by
// the desired mouse speed. Mouse speed can range from 1 (slowest) to 20
// (fastest) and represents how much the pointer moves based on the distance the
// mouse moves. The default value is 10, which results in no additional
// modification to the mouse motion.
debug!("\x1b[93mRelative mouse move is subject to mouse speed and acceleration level\x1b[0m");
(MOUSEEVENTF_MOVE, x, y)
} else {
// Instead of moving the mouse by a relative amount, we calculate the resulting
// location and move it to the absolute location so it is not subject to mouse
// speed and acceleration levels
debug!("\x1b[93mRelative mouse move is NOT subject to mouse speed and acceleration level\x1b[0m");
let (current_x, current_y) = self.location()?;
return self.move_mouse(current_x + x, current_y + y, Coordinate::Abs);
};
let input = mouse_event(flags, 0, x, y, self.dw_extra_info);
send_input(&[input])
Expand Down Expand Up @@ -344,6 +375,7 @@ impl Enigo {
let Settings {
windows_dw_extra_info: dw_extra_info,
release_keys_when_dropped,
windows_subject_to_mouse_speed_and_acceleration_level,
..
} = settings;

Expand All @@ -355,6 +387,8 @@ impl Enigo {
held,
release_keys_when_dropped: *release_keys_when_dropped,
dw_extra_info: dw_extra_info.unwrap_or(crate::EVENT_MARKER as usize),
windows_subject_to_mouse_speed_and_acceleration_level:
*windows_subject_to_mouse_speed_and_acceleration_level,
})
}

Expand Down

0 comments on commit 4713ea7

Please sign in to comment.