Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Simple library to listen and send events to keyboard and mouse (MacOS, Windows, Linux)

License

NotificationsYou must be signed in to change notification settings

Narsil/rdev

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CrateAPI

rdev

Simple library to listen and send eventsglobally to keyboard and mouse on macOS, Windows and Linux(x11).

You can also check outEnigo which is anothercrate which helped me write this one.

This crate is so far a pet project for me to understand the Rust ecosystem.

Listening to global events

use rdev::{listen,Event};// This will block.ifletErr(error) =listen(callback){println!("Error: {:?}", error)}fncallback(event:Event){println!("My callback {:?}", event);match event.name{Some(string) =>println!("User wrote {:?}", string),None =>(),}}

OS Caveats:

When using thelisten function, the following caveats apply:

macOS

The process running the blockinglisten function (loop) needs to be the parent process (no fork before).The process needs to be granted access to the Accessibility API (i.e. if you're running your processinside Terminal.app, then Terminal.app needs to be added inSystem Preferences > Security & Privacy > Privacy > Accessibility)If the process is not granted access to the Accessibility API, macOS will silently ignore rdev'slisten callback and will not trigger it with events. No error will be generated.

Linux

Thelisten function uses X11 APIs, and so will not work in Wayland or in the Linux kernel virtual console

Sending some events

use rdev::{simulate,Button,EventType,Key,SimulateError};use std::{thread, time};fnsend(event_type:&EventType){let delay = time::Duration::from_millis(20);matchsimulate(event_type){Ok(()) =>(),Err(SimulateError) =>{println!("We could not send {:?}", event_type);}}// Let ths OS catchup (at least MacOS)    thread::sleep(delay);}send(&EventType::KeyPress(Key::KeyS));send(&EventType::KeyRelease(Key::KeyS));send(&EventType::MouseMove{x:0.0,y:0.0});send(&EventType::MouseMove{x:400.0,y:400.0});send(&EventType::ButtonPress(Button::Left));send(&EventType::ButtonRelease(Button::Right));send(&EventType::Wheel{delta_x:0,delta_y:1,});

Main structs

Event

In order to detect what a user types, we need to plug to the OS level managementof keyboard state (modifiers like shift, CTRL, but also dead keys if they exist).

EventType corresponds to aphysical event, corresponding to QWERTY layoutEvent corresponds to an actual event that was received andEvent.name reflectswhat key was interpreted by the OS at that time, it will respect the layout.

/// When events arrive from the system we can add some information/// time is when the event was received.#[derive(Debug)]pubstructEvent{pubtime:SystemTime,pubname:Option<String>,pubevent_type:EventType,}

Be careful, Event::name, might be None, but also String::from(""), and might containnot displayable Unicode characters. We send exactly what the OS sends us, so do some sanity checkingbefore using it.Caveat: Dead keys don't function yet on Linux

EventType

In order to manage different OS, the current EventType choices is a mix and match to account for all possible events.There is a safe mechanism to detect events no matter what, which are theUnknown() variant of the enum which will contain some OS specific value.Also, not that not all keys are mapped to an OS code, so simulate might fail if youtry to send an unmapped key. Sending Unknown() variants will always work (the OS mightstill reject it).

/// In order to manage different OS, the current EventType choices is a mix&match/// to account for all possible events.#[derive(Debug)]pubenumEventType{/// The keys correspond to a standard qwerty layout, they don't correspond/// To the actual letter a user would use, that requires some layout logic to be added.KeyPress(Key),KeyRelease(Key),/// Some mouse will have more than 3 buttons, these are not defined, and different OS will/// give different Unknown code.ButtonPress(Button),ButtonRelease(Button),/// Values in pixelsMouseMove{x:f64,y:f64,},/// Note: On Linux, there is no actual delta the actual values are ignored for delta_x/// and we only look at the sign of delta_y to simulate wheelup or wheeldown.Wheel{delta_x:i64,delta_y:i64,},}

Getting the main screen size

use rdev::{display_size};let(w, h) =display_size().unwrap();assert!(w >0);assert!(h >0);

Keyboard state

We can define a dummy Keyboard, that we will use to detectwhat kind of EventType trigger some String. We get the currently usedlayout for now !Caveat : This is layout dependent. If your app needs to supportlayout switching, don't use this!Caveat: On Linux, the dead keys mechanism is not implemented.Caveat: Only shift and dead keys are implemented, Alt+Unicode code on Windows won't work.

use rdev::{Keyboard,EventType,Key,KeyboardState};letmut keyboard =Keyboard::new().unwrap();let string = keyboard.add(&EventType::KeyPress(Key::KeyS));// string == Some("s")

Grabbing global events. (Requiresunstable_grab feature)

Installing this library with theunstable_grab feature adds thegrab functionwhich hooks into the global input device event stream.By supplying this function with a callback, you can interceptall keyboard and mouse events before they are delivered to applications / window managers.In the callback, returning None ignores the event and returning the event lets it pass.There is no modification of the event possible here (yet).

Note: the use of the wordunstable here refers specifically to the fact that thegrab API is unstable and subject to change

#[cfg(feature ="unstable_grab")]use rdev::{grab,Event,EventType,Key};#[cfg(feature ="unstable_grab")]let callback = |event:Event| ->Option<Event>{ifletEventType::KeyPress(Key::CapsLock) = event.event_type{println!("Consuming and cancelling CapsLock");None// CapsLock is now effectively disabled}else{Some(event)}};// This will block.#[cfg(feature ="unstable_grab")]ifletErr(error) =grab(callback){println!("Error: {:?}", error)}

OS Caveats:

When using thelisten and/orgrab functions, the following caveats apply:

macOS

The process running the blockinggrab function (loop) needs to be the parent process (no fork before).The process needs to be granted access to the Accessibility API (i.e. if you're running your processinside Terminal.app, then Terminal.app needs to be added inSystem Preferences > Security & Privacy > Privacy > Accessibility)If the process is not granted access to the Accessibility API, thegrab call will fail with anEventTapError (at least in macOS 10.15, possibly other versions as well)

Linux

Thegrab function use theevdev library to intercept events, so they will work with both X11 and WaylandIn order for this to work, the process running thelisten orgrab loop needs to either run as root (not recommended),or run as a user who's a member of theinput group (recommended)Note: on some distros, the group name for evdev access is calledplugdev, and on some systems, both groups can exist.When in doubt, add your user to both groups if they exist.

Serialization

Event data returned by thelisten andgrab functions can be serialized and deserialized withSerde if you install this library with theserialize feature.

About

Simple library to listen and send events to keyboard and mouse (MacOS, Windows, Linux)

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp