mouse-rs
mouse-rs copied to clipboard
Animation?
I know that this crate doesn't have any animation logic, however I'd like to find a way to use this lib (move mouse cursor) with animation. Is there any crates to do this?
Not the author, but just chiming in with my two cents.
If you simply want to linearly move the mouse (e.g., with constant speed and no acceleration) given some time t
, you can just use a standard lerp
(common function name for linear interpolation) over a loop. The loop would run while an elapsed
value keeps track of the target time (say, 1 second), and you run each loop based on how "smooth" you want the animation (say, 60 frames per second). The loop time would then be: t (as milliseconds) / fps
, which is about 16.67ms
.
Your lerp
might look something like:
struct PointF64 {
x: f64,
y: f64
}
impl PointF64 {
pub fn lerp(p1: Self, p2: Self, t: f64) -> Self {
let t_clamp = t.clamp(0., 1.);
Self {
(p1.x + (p2.x - p1.x) * t_clamp),
(p1.y + (p2.y - p1.y) * t_clamp),
}
}
This will give you the PointF64
to move the mouse to, given a t
in the range [0, 1]
. If you use the above, you will need to make sure you round off the x
and y
values and convert them to i32
to use with Mouse::move_to
from this library.
Then the general implementation would be (you need a given interval_time
in milliseconds and end point ep
):
- Calculate the loop time (e.g.,
loop_time = 1000ms / 60 ~= 16.67ms
) - Get the mouse start point (
sp
) - While
elapsed_time < interval_time
:- Keep track of the loop start time (
start_time
) - Get the current mouse position (
current_pos
) - Normalize/map the
elapsed_time
in the range[0, 1]
(t = elapsed_time / interval_time
) - Interpolate the next position (
next_pos = PointF64::lerp(sp, ep, t)
) - Check if the
current_pos != next_pos
(otherwise you can end up firing off a ton of events) -- if they are not equal, move the mouse tonext_pos
- Sleep for remainder of loop time (
sleep(loop_time - start_time.elapsed())
)
- Keep track of the loop start time (
Note on sleeping for the last step: I found the the standard library thread::sleep
function was not accurate enough for what I was trying to do on Windows. The crate spin_sleep
solves that problem cross-platform which is really nice. Basically just a drop in replacement for thread::sleep
.
For reference, you can check out my implementation (just from a toy project, definitely take the details with a grain of salt). This one eases the movement in and out from point to point: https://github.com/bwpge/mouse-jiggler/blob/8609a1914dd25ec10b3df5ddf4716e0ec134c853/src/mouse.rs#L95-L134
If you want to get more clever than this, such as rounding off the movements to look like the mouse is waving around, you might want to look into Bezier Curves (think of the "pen" tool in Photoshop or GIMP where you can drag around anchors to make curves). I also recommend this article which has a clever way on implementing continuous or composite bezier curves (this eliminates the jagged edges when combining curves).
@AltF02 I can submit a PR for a (simple linear) animate function if you'd like, I'm just not sure if that functionality is within the scope for this crate. I would probably gate it behind a feature animate
or something since I believe it would need at least spin_sleep
, as well as possibly chrono
or time
.
I'm not sure, I personally planned to create an alternative https://crates.io/crates/enigo with mouse-rs under the hood at some point. But unfortunately life got in the way. I think a hypothetical library like that would be a great fit for something like this.
I personally think its out of scope, but I am more than happy to provide a note to a possible external library that implements this feature.