obv-mikhail / inputbot Goto Github PK
View Code? Open in Web Editor NEWRust library for creating global hotkeys, and simulating inputs
License: MIT License
Rust library for creating global hotkeys, and simulating inputs
License: MIT License
Hi!
Thanks for making this lib :)
I am running into an issue where if I a bind to, say, AKey
, using AKey::bind
the input is always intercepted. I saw a similar thread with the opposite problem where the input was not being intercepted so I wasn't sure if that was ever changed to intercept the input by default? I am using Linux w/ X11.
To be clear:
fn main() {
AKey.bind(|| {
println!("a has been pressed");
});
handle_input_events();
}
This very simple example will print a has been pressed
in the terminal but then my a
key no longer works for typing anything because it seems that the program is preventing the default key action.
As a side note, would it be possible to have an API where we could decide whether to intercept the key or not?
AKey.bind(|event| {
if ... {
event.intercept();
} else {
// do something else
}
});
no variant or associated item named bind_all
found for enum KeybdKey
in the current scope
variant or associated item not found in KeybdKey
rustcE0599
Cannot bind to right keys
right keys in linux have 0xe0 prepended to them. I cant seem to get is_pressed() to address the bitmap appropriately for scancodes that have a sequence greater than one.
at least the following keys are missing from the enumeration:
right ctrl
numpad enter (KP_Enter vs Return in xmodmap -pke)
I'm working on it but got stuck and thought it worth posting thanks.
RUST_BACKTRACE=full sudo --preserve-env=RUST_BACKTRACE target/debug/Clicker
thread 'main' panicked at 'libinput returned invalid 'libinput_event_type'', /home/.../input-0.6.0/src/event.rs:108:18
This error is generated when I scroll my mouse, it seems that there is a bug in input-0.6.0, I update input to 0.7.1 and the bug solved.
(I also edited line 201 of mod.rs
to make rustc happy.)
let keyboard_key_event = if let KeyboardEvent::Key(keyboard_key_event) = keyboard_event { keyboard_key_event } else { todo!() };
besides, there are 6 warnings after update:
warning: unreachable pattern
--> inputbot-0.5.1/src/linux/inputs.rs:180:9
|
180 | 0x52 => Some(Numpad0Key),
| ^^^^
|
= note: `#[warn(unreachable_patterns)]` on by default
warning: unreachable pattern
--> inputbot-0.5.1/src/linux/inputs.rs:182:9
|
182 | 0x50 => Some(Numpad2Key),
| ^^^^
warning: unreachable pattern
--> inputbot-0.5.1/src/linux/inputs.rs:184:9
|
184 | 0x4b => Some(Numpad4Key),
| ^^^^
warning: unreachable pattern
--> inputbot-0.5.1/src/linux/inputs.rs:186:9
|
186 | 0x4d => Some(Numpad6Key),
| ^^^^
warning: unreachable pattern
--> inputbot-0.5.1/src/linux/inputs.rs:187:9
|
187 | 0x47 => Some(Numpad7Key),
| ^^^^
warning: unreachable pattern
--> inputbot-0.5.1/src/linux/inputs.rs:188:9
|
188 | 0x48 => Some(Numpad8Key),
| ^^^^
warning: `inputbot` (lib) generated 6 warnings
I have no idea of those code, since they do not bother my program.
on Ubuntu 20 I cant get MouseCursor::move_rel to move relative however this is exactly what happens with move_abs.
Hi, first of all thanks for your work on this. I've starting to mess a bit with Rust and was trying to simulate the MEDIA KEY PLAY/PAUSE press on Windows. I might be messing something up but this is the code I'm trying to use as an example:
use inputbot::{*};
fn main() {
KeybdKey::OtherKey(0xB3).press();
}
Running this code seems to cause the "g" key to be pressed instead of VK_MEDIA_PLAY_PAUSE.
I've noticed this behaviour on similar crates so this might be an issue of the windows api.
Thanks
Platform: Windows 10
If my screen dimensions are relevant: 2560x1440
I have three monitors, these tests were done on my farthest left one, which is the one with the taskbar, which is on the left side of the screen.
I'm trying to move the mouse, and I assumed MouseCursor.move_abs()
was ideal because I have absolute coordinates from the winapi. In the simplest form, I tried to do the following:
let left = 486;
let top = 347;
MouseCursor.move_abs(left, top);
Which is inaccurate by 285x2 pixels. At (1044, 350) it's off by 558x3 which seems like it scales or something. (0,0) works, and I can move the cursor to the correct screen coordinate by doing a move_abs
to (0,0) and then a move_rel
to my coordinates like the following:
let left = 486;
let top = 347;
MouseCursor.move_abs(0, 0);
MouseCursor.move_rel(left, top);
I can work with this, although it seems unexpected.
Is this a bug or am I missing a detail on move_abs
?
Hey!
I have been using InputBot for a month or so now and I really love it! I just switch to Linux and the in the build the keypresses cause no action. (I run it with sudo)
It worked just fine on windows and I get no compile errors, what could the problem be?
Code exampel:
if F5Key.is_pressed() {
self.feedbackmenu = true;
}
I then read that variable to open a window with egui.
/Albin Sjögren
How do I fix this code?
use inputbot::{KeybdKey::*, *};
fn main() {
let mut test = false;
println!("press f6");
F6Key.bind(move || test = !test);
handle_input_events();
}
It gives me this error
error[E0594]: cannot assign to `test`, as it is a captured variable in a `Fn` closure
--> src\main.rs:6:24
|
6 | F6Key.bind(move || test = !test);
| ^^^^^^^^^^^^ cannot assign
Due to the way symbols are sent a "uppercase" "0" in the default keyboard layout equals to ")" but in Portuguese layout for example it equals to "=". Also I've found a bug, not sure if it is because of the keyboard layout but when running the example in the README the program wouldn't stop typing, because the "!" character is just an upper-cased 1 so the bind calls itself.
Try to simulate a win+shift+s combo with a simpler key bind. Didn't see LWIN in the key list. Please consider add the Windows key if it's not too much trouble. Thank you!
This is a nice crate!
But it seems that some keys are missing, like Backslash,, LBracket, RBracket, Grave, Dot, Slash, PageUp, PageDown etc.
It would be useful to be able to bind all 104 keys :)
I saw some PRs about support macos being merged. But I don't see the macos branch being merged into the mainline. Does there have any problem to support macos?
My little program build on Rust 1.64.0:
fn main(){
Numpad0Key.press();
}
When I Running it:
thread 'main' panicked at 'cannot transmute_copy if U is larger than T', /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52\library\core\src\mem\mod.rs:1057:5
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library\std\src\panicking.rs:584
1: core::panicking::panic_fmt
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library\core\src\panicking.rs:142
2: core::mem::transmute_copy<winapi::um::winuser::KEYBDINPUT,winapi::um::winuser::INPUT_u>
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52\library\core\src\mem\mod.rs:1057
3: inputbot::windows::send_keybd_input
at C:\Users\aisin\.cargo\git\checkouts\inputbot-ca044018c1f51f7c\b91aec3\src\windows\mod.rs:231
4: enum$<inputbot::public::KeybdKey>::press
at C:\Users\aisin\.cargo\git\checkouts\inputbot-ca044018c1f51f7c\b91aec3\src\windows\mod.rs:28
5: remote_numpad_server::main
at .\src\main.rs:20
6: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52\library\core\src\ops\function.rs:248
Seem like because Rust 1.64.0 add a assertion on transmute_copy
: Add assertion that transmute_copy
's U
is not larger than T
Error: thread '' panicked at 'cannot transmute_copy if Dst is larger than Src', /rustc/69f9c33d71c871fc16ac445211281c6e7a340943\library\core\src\mem\mod.rs:1056:5
I'm using the latest version (0.5.1)
I was testing with the mouse and the error doesn't exists, but it always happens when I use the keyboard.
Code:
use inputbot::{
handle_input_events,
KeybdKey::{Numpad1Key, XKey},
};
use std::{thread::sleep, time::Duration};
fn main() {
Numpad1Key.bind(|| {
while Numpad1Key.is_pressed() {
XKey.press();
sleep(Duration::from_millis(17));
XKey.release();
}
});
handle_input_events();
}
I tried to detect pressing the Alt keys but it doesn't work.
I even tried the code from the example to detect all the keys pressing:
KeybdKey::bind_all(|event| {
match inputbot::from_keybd_key(event) {
Some(c) => println!("{c}"),
None => println!("Unregistered Key"),
};
});
This works for all keys except Alt.
Windows 10.
I cant seem to get OtherKey() to work with the enumeration. Ive tried the hex code returned from xev and the uint returned from showkey. Is there further documentation or a working example?
Thanks.
I guess this crate is used for automated input, but can I use it to capture global input? Thanks!
Hey! First off, thanks for the awesome lib. Today I made a program to let me use my phone as a mouse - it works! mousepage on crates.io.
Now I'm looking to get scrolling to work, but looks like the relevant functions are unimplemented! MouseWheel.scroll_ver and MouseWheel.scroll_hor.
When running the example in the README and pressing 1
, I get this error:
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: Nix(Sys(ENODEV))', /home/****/.cargo/git/checkouts/inputbot-ca044018c1f51f7c/cff7a97/src/linux/mod.rs:44:14
I'm currently using XMonad with Arch Linux. I'm using the develop
branch of InputBot.
idk if this is realistic to implement (especially cross-plattform), but i'd really need the option to actually "intercept" the keypress in a way that the original key doesn't come through (like for example ahk does it).
At the moment when i bind to a key, the original keypress still writes letters and such, this should be preventable
First of all thank you for the efforts you put into this. I am trying to write an application that will send a key sequence when the F2key
is pressed. However this string is not known during compile time and I generate it at run time. For this I am using the lazy_static
macro to initialize the string during run time. Here's what my code looks like:
lazy_static! {
pub static ref MY_STRING: String = some_fn().to_string();
}
fn main() {
println!("{}", MY_STRING.as_str());
F2Key.bind(|| KeySequence(MY_STRING.as_str()).send());
handle_input_events();
}
The println
line works fine for this, but the KeySequence
line does not. I have verified that the binding works well if I just pass it a string literal, however I do not get any output when I pass the static MY_STRING
in this way.
The binding is probably working fine, as the program stops and wait instead of just exiting. Other bindings also function. However, it seems that nothing is getting passed to the send()
method when ran this way. Any ideas why this might be happening? Thank you.
Edit: I'm running this on a RHEL-8 machine.
It appears that there is no LICENSE on the project. By default, this means we have no permission to use, modify, etc. Do you mind picking a license?
You can read more here: https://choosealicense.com/no-permission/
And to help pick one: https://choosealicense.com/
My system info:
Ubuntu 21.10
Wayland session
Library installed from master
Rust nightly 1.60
As described in the issue title, mouse movement is not working. I have a fix for it and gonna submit a PR soon.
The problem is in the current implementation there is no device locking and unlocking happening
pub fn move_rel(x: i32, y: i32) {
SEND_DISPLAY.with(|display| unsafe {
XWarpPointer(display, 0, 0, 0, 0, 0, 0, x, y);
});
}
The working fix is
pub fn move_rel(x: i32, y: i32) {
let mut device = FAKE_DEVICE.lock().unwrap();
device.position(&Position::X, x).unwrap();
device.position(&Position::Y, y).unwrap();
SEND_DISPLAY.with(|display| unsafe {
XWarpPointer(display, 0, 0, 0, 0, 0, 0, x, y);
});
device.synchronize().unwrap();
}
The same should be done for move_abs
but it still appears not to work. Upon further investigation on how this method is implemented with xlib
I believe it's not gonna work on Wayland
at all. It seems that XRootWindow
or XDefaultScreen
is specific for X11 and not implemented for Wayland. As mentioned here #4
Should InputBot support this?
use inputbot::{KeySequence};
fn main() {
KeySequence("Hello, world!").send();
}
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target\debug\office_owl.exe`
thread 'main' panicked at 'cannot transmute_copy if Dst is larger than Src', /rustc/69f9c33d71c871fc16ac445211281c6e7a340943\library\core\src\mem\mod.rs:1056:5
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library\std\src\panicking.rs:575
1: core::panicking::panic_fmt
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library\core\src\panicking.rs:65
2: core::mem::transmute_copywinapi::um::winuser::KEYBDINPUT,winapi::um::winuser::INPUT_u
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943\library\core\src\mem\mod.rs:1056
3: inputbot::windows::send_keybd_input
at C:\Users\Fahim.cargo\registry\src\github.com-1ecc6299db9ec823\inputbot-0.5.1\src\windows\mod.rs:215
4: enum2$inputbot::public::KeybdKey::press
at C:\Users\Fahim.cargo\registry\src\github.com-1ecc6299db9ec823\inputbot-0.5.1\src\windows\mod.rs:29
5: inputbot::public::KeySequence::send
at C:\Users\Fahim.cargo\registry\src\github.com-1ecc6299db9ec823\inputbot-0.5.1\src\public.rs:217
6: office_owl::main
at .\src\main.rs:4
7: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943\library\core\src\ops\function.rs:251
note: Some details are omitted, run with RUST_BACKTRACE=full
for a verbose backtrace.
error: process didn't exit successfully: target\debug\office_owl.exe
(exit code: 101)
Process finished with exit code 101
Here is the code example
use inputbot::KeySequence;
fn main() {
KeySequence("Hello, world!").send()
}
Command:
sleep 2 && cargo run
Switch to other terminal
Output in the second terminal:
lo, world!
This is on linux Hyprland.
Some of the enumerations are not accessible.
For example: this means certain actions such as Numpad7Key.is_toggled()
work but HomeKey.is_toggled() doesnt.
I have patched this on my branch specifically for another project but have not been able to create an upstream fix yet nor do I plan to at this time.
Hey I wanted to know if this crate take control on mouse or it’s really simulates the key ?
I've been tinkering trying to get this to work for a while, and I can't find a good approach. I'm wanting a way to block_bind a particular key, but still have the is_pressed() method recognize the key is held down "in real life" even though it isn't being propagated onward.
// Do not propagate the Capslock key onward at all
CapsLockKey.block_bind(|| ());
LKey.bind(|| {
//This check will always return false due to the block_bind
if CapsLockKey.is_pressed() { }
});
The only way I've managed to get it working is to create a second "fake" keyboard and selectively emit synthetic keyboard events on it, then not emit ANY events on the main keyboard. Is there a cleaner way?
Hi!
Cool crate you've written. Thanks!
The compiler complains (rightfully so I guess) that the the match
in linux/inputs.rs:130, in function:
pub fn scan_code_to_key(scan_code: u32) -> Option<KeybdKey>
has unreachable patterns.
This is because 0x47, 0x48, 0x4b, 0x4d and 0x50 are used more than once and match has no way to distinguish between them.
These are numpad keys with double functions, depending on the num-lock state? I am not sure how to fix this.
How do I run this on windows? I want to configure the click on a player within a program. I don't know anything about programming.
Not sure what will be used for the back-end. Probably libinput.
Status Update:
Currently, when a key is bound multiple times, the last binding operation overrides the previous ones.
When a key or mouse event is bound multiple times, InputBot dispatches the event to all callback functions, in the order in which they were registered.
Note: this would be a breaking change.
After thinking about it, I found the current API, with KeydbKey:unbind(&self)
, would make a rather coarse API, requiring to unregister all callbacks at once.
Provide a new interface which handles dispatch.
This is the command,
cargo build --lib --target wasm32-unknown-unknown
This is part of the error log which is repeating 4 times,
error[E0599]: no method named `release` found for enum `public::KeybdKey` in the current scope
--> /home/test/.cargo/registry/src/github.com-1ecc6299db9ec823/inputbot-0.5.0/src/public.rs:223:41
|
10 | pub enum KeybdKey {
| ----------------- method `release` not found for this
...
223 | KeybdKey::LShiftKey.release();
| ^^^^^^^ method not found in `public::KeybdKey`
Just a polite request, could you limit the readme examples to things that are in your latest release? bind_all
is not in 0.5.1, so the basic examples didn't 'just work' and some troubleshooting was required to discover why.
In the windows API, there is a way to get some form of Keyboard Identification. Having that sort of information is available, it would make it easy to have a second keyboard connected to a pc that can be used as a macro board or whatnot.
Here's an old Article and Code of how its done in C#.
https://www.codeproject.com/Articles/17123/Using-Raw-Input-from-C-to-handle-multiple-keyboard
In the scan_code
and other functions
0x47 => Some(HomeKey),
0x4b => Some(LeftKey),
0x4d => Some(RightKey),
0x48 => Some(UpKey),
0x50 => Some(DownKey),
0x52 => Some(InsertKey),
0x53 => Some(DeleteKey),
0x52 => Some(Numpad0Key),
0x50 => Some(Numpad2Key),
0x4b => Some(Numpad4Key),
0x4d => Some(Numpad6Key),
0x47 => Some(Numpad7Key),
0x48 => Some(Numpad8Key),
Gonna investigate further and create a PR
Event handlers should be assignable to multiple keys pressed in a sequence.
Hey, the crate has not been published for more than a year, I am stuck because to publish another crate, you have to use dependencies from crates.io (git dependencies are removed)
Especially since new keys were added in c391001
Can you please do a publish? Thanks a lot!
Sorry if this is more of a help request than an actual issue.
Is there really no way to stop listening for events?
Shouldn´t there be a way to lets say inputbot::stop_handle_input_events();
?
At the moment I do something like this:
let t = thread::spawn(move || {
inputbot::MouseButton::LeftButton.bind(move || {
let pos = inputbot::MouseCursor::pos();
if let Ok(element) = automation.element_from_point(Point::new(pos.0, pos.1)) {
state.lock().unwrap().pick_mode = PickMode::Selected(element.get_hwnd());
inputbot::MouseButton::LeftButton.unbind();
}
});
inputbot::handle_input_events();
});
// wait until the user has picked an element
while app_state.lock().unwrap().pick_mode == PickMode::Pick {
thread::sleep(Duration::from_millis(100));
}
// End the thread? how?
drop(t);
So I unbind what I can, and drop the thread. I do however assume that the thread lives on in the background (!)
I think I could have just one thread living in the background for the duration of my program, and do some rx/tx stuff instead so I can reuse the same thread., but I would still expect it to be possible to simply stop "handle_input_events" at some point.
So to me (I'm still new at this), the lack of this functionality is somewhat startling. But it could of course just mean I'm going about things the wrong way, or that I've missed something obvious.
Any clarification in the matter would be highly appreciated, thanks!
Any chance that the sudo
requirement could be eliminated?
I'll try and work on implementing a solution compatible with MacOS over the next few months, and I'll post any updates / concerns over on this issue.
My current plan is to create some rust bindings around a C file that would call apple's native api for event handling.
Hello,
I tested the program on linux and in worked. Compiled and runned on windows and get following error
thread '' panicked at 'cannot transmute_copy if Dst is larger than Src', /rustc/eb26296b556cef10fb713a38f3d16b9886080f26\library\core\src\mem\mod.rs:1056:5
when trying to execute
KeySequence("b").send();
or
inputbot::KeybdKey::BKey.press();
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.