A tiny sandboxed Dyon scripting environment for evdev input devices that lets you do e.g. xcape in Wayland
Go to file
Val Packett e3c7d6dd89
release 0.1.0
2023-10-06 02:06:29 -03:00
examples Update iteration syntax in example script 2020-02-23 16:33:46 +03:00
src Update Rust edition, use serde derive as feature 2023-10-06 02:02:04 -03:00
.gitignore Initial commit 2017-12-03 03:16:43 +03:00
.rustfmt.toml Initial commit 2017-12-03 03:16:43 +03:00
CODE_OF_CONDUCT.md Initial commit 2017-12-03 03:16:43 +03:00
Cargo.lock release 0.1.0 2023-10-06 02:06:29 -03:00
Cargo.toml release 0.1.0 2023-10-06 02:06:29 -03:00
README.md Remove weirdly grumpy intro paragraph 2023-07-17 06:26:22 +00:00
UNLICENSE Initial commit 2017-12-03 03:16:43 +03:00


unlicense Packaging status Support me on Patreon


A tiny sandboxed Dyon scripting environment for evdev input devices, allowing for xcape and xdotool style tricks independent of a windowing system.

You get a set of devices. You can get events from them, emit events into a virtual device (uinput) and print to stdout. That's it.


Something like that (with cargo):

git clone https://codeberg.org/valpackett/evscript
cd evscript
cargo build --release
install -Ss -o root -m 4755 target/release/evscript /usr/local/bin/evscript

evscript is designed for setuid root: right after opening the devices (before executing the script) it drops privileges, chroots and (on FreeBSD) sandboxes itself with Capsicum.

You can allow yourself access to /dev/input/* and /dev/uinput instead of setuid, but that would allow any random program running as you to work with inputs.


A simple script looks like this:

//! [events]
//! keys = ['ESC', 'LEFTSHIFT', '9', '0']
fn main() ~ evdevs, uinput {
    // NOTE: these are not control knobs, these are just state
    should_esc := false
    should_lshift := false
    should_rshift := false
    loop {
        evts := next_events(evdevs)
        for i {
            evt := evts[i]
            xcape(mut should_esc, evt, KEY_CAPSLOCK(), [KEY_ESC()])
            xcape(mut should_lshift, evt, KEY_LEFTSHIFT(), [KEY_LEFTSHIFT(), KEY_9()])
            xcape(mut should_rshift, evt, KEY_RIGHTSHIFT(), [KEY_LEFTSHIFT(), KEY_0()])

If you want to emit several keys use xcape_sequence instead of xcape.

xcape_sequence(mut should_lshift, evt, KEY_LEFTSHIFT(), [[KEY_LEFTSHIFT(), KEY_9()], [KEY_LEFTSHIFT(), KEY_0()], [KEY_LEFT()]])

The above line types a pair of parentheses and moves between them, when you press the left shift key.

Check out the source of the standard library in src/stdlib.dyon to see how xcape is implemented!

And you can run it like this:

evscript -f my_script.dyon -d /dev/input/event2 /dev/input/event3

For now, only an explicit list of devices is supported. There is no hotplugging mode yet. You can setup devd/udev to run evscript on each plugged device, but that would run independent instances, not one instance that sees events from all the devices.

Also, you can run it in expression mode, kinda like you would run xdotool to just press a key:

evscript -e "for i 4 { click_key_chord([KEY_LEFTCTRL(), KEY_C()]); sleep(0.3); }"

Dyon does not have semicolons, so this mode replaces ); and }; with )\n and }\n.


By participating in this project you agree to follow the Contributor Code of Conduct.


This is free and unencumbered software released into the public domain.
For more information, please refer to the UNLICENSE file or unlicense.org.