Check out my blog at usagi.io!
shiro / map2 Goto Github PK
View Code? Open in Web Editor NEWLinux input remapping for your keyboard, mouse and more!
License: MIT License
Linux input remapping for your keyboard, mouse and more!
License: MIT License
Check out my blog at usagi.io!
with this one simple change, this program can become a viable alternative to sxhkd.
to compare, sxhkd can do what this program can, by utilizing xdotool
Since I found a way to add the needed udev rule on my system, I figured I'd share it here.
Create file in /etc/udev/rules.d/
, for example 01-uinput-permission.rules
, with the following content:
SUBSYSTEM=="misc", KERNEL=="uinput", MODE="0660", GROUP="uinput"
Create /etc/modules-load.d/uinput.conf
with:
uinput
(trick found here)
and
reboot
NOTE: I also happened to create the uinput
usergroup, and adding my user to it beforehand, which could've helped as well.
I was testing the window change events on my machine (a fairly standard Arch setup) but, for some reason, I encountered the UNSUPPORTED_PLATFORM error. Upon further investigation, I got to this line:
Line 32 in 0c1e78a
info.stdout
ends up as "x11\n"
, and that messes up the test.Traceback on cargo build --release
:
Compiling map2 v0.1.0 (/home/pp/git/map2)
error[E0554]: `#![feature]` may not be used on the stable release channel
--> src/lib.rs:1:1
|
1 | #![feature(type_ascription)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0554]: `#![feature]` may not be used on the stable release channel
--> src/lib.rs:2:1
|
2 | #![feature(async_closure)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0554]: `#![feature]` may not be used on the stable release channel
--> src/lib.rs:3:1
|
3 | #![feature(unboxed_closures)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0554]: `#![feature]` may not be used on the stable release channel
--> src/lib.rs:4:1
|
4 | #![feature(trait_alias)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0554]: `#![feature]` may not be used on the stable release channel
--> src/lib.rs:5:1
|
5 | #![feature(label_break_value)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0554]: `#![feature]` may not be used on the stable release channel
--> src/lib.rs:6:1
|
6 | #![feature(destructuring_assignment)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0554]: `#![feature]` may not be used on the stable release channel
--> src/lib.rs:7:1
|
7 | #![feature(seek_convenience)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused imports: `parse_key_action_with_mods`, `parse_key_sequence`
--> src/runtime/evaluation.rs:7:30
|
7 | use crate::parsing::parser::{parse_key_sequence, parse_key_action_with_mods};
| ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
warning: unused import: `evdev_rs::enums::int_to_ev_key`
--> src/runtime/evaluation.rs:8:5
|
8 | use evdev_rs::enums::int_to_ev_key;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused import: `evaluation::*`
--> src/runtime/mod.rs:4:5
|
4 | use evaluation::*;
| ^^^^^^^^^^^^^
warning: unused imports: `VerboseError`, `context`
--> src/parsing/mod.rs:12:18
|
12 | use nom::error::{context, VerboseError, ParseError};
| ^^^^^^^ ^^^^^^^^^^^^
warning: unused import: `crate::runtime::evaluation::*`
--> src/parsing/mod.rs:36:5
|
36 | use crate::runtime::evaluation::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused import: `nom::error::convert_error`
--> src/parsing/parser.rs:2:5
|
2 | use nom::error::convert_error;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused import: `InputIter`
--> src/parsing/custom_combinators.rs:1:40
|
1 | use nom::{Compare, CompareResult, Err, InputIter, InputLength, InputTake, Parser, Slice, Offset};
| ^^^^^^^^^
warning: unused import: `nom::combinator::map_res`
--> src/parsing/key_action.rs:2:5
|
2 | use nom::combinator::map_res;
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused import: `nom::combinator::consumed`
--> src/parsing/variable.rs:2:5
|
2 | use nom::combinator::consumed;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unnecessary parentheses around `if` condition
--> src/parsing/error.rs:36:19
|
36 | } else if (other.input.input_len() > self.input.input_len()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses
|
= note: `#[warn(unused_parens)]` on by default
warning: unused import: `tokio::sync::oneshot::Sender`
--> src/device/virtual_input_device.rs:11:5
|
11 | use tokio::sync::oneshot::Sender;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused import: `crate::device::virt_device`
--> src/device/virtual_input_device.rs:15:5
|
15 | use crate::device::virt_device;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: variable does not need to be mutable
--> src/runtime/builtin_functions.rs:172:17
|
172 | let mut child_process = cmd.output().await
| ----^^^^^^^^^^^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` on by default
warning: unreachable expression
--> src/device/virtual_input_device.rs:141:13
|
124 | / loop {
125 | | match watch_rx.recv() {
126 | | Ok(event) => {
127 | | use FsWatchEvent::*;
... |
139 | | }
140 | | }
| |_____________- any code following this expression is unreachable
141 | Ok(())
| ^^^^^^ unreachable expression
|
= note: `#[warn(unreachable_code)]` on by default
warning: unreachable expression
--> src/device/virtual_input_device.rs:177:9
|
159 | / loop {
160 | | let fs_event = fs_event_rx.recv().await.unwrap();
161 | | match fs_event {
162 | | FsWatchEvent::ADD(path) => {
... |
175 | | }
176 | | }
| |_________- any code following this expression is unreachable
177 | Ok::<(), anyhow::Error>(())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable expression
warning: unreachable expression
--> src/device/virtual_output_device.rs:24:9
|
16 | / loop {
17 | | let msg = reader_rx.recv().await;
18 | | let ev: InputEvent = match msg {
19 | | Some(v) => v,
... |
22 | | input_device.write_event(&ev)?;
23 | | }
| |_________- any code following this expression is unreachable
24 | Ok(())
| ^^^^^^ unreachable expression
warning: unused import: `futures::StreamExt`
--> src/parsing/mod.rs:6:5
|
6 | use futures::StreamExt;
| ^^^^^^^^^^^^^^^^^^
error: aborting due to 7 previous errors; 17 warnings emitted
For more information about this error, try `rustc --explain E0554`.
error: could not compile `map2`.
To learn more, run the command again with --verbose.
warning: build failed, waiting for other jobs to finish...
error: build failed
HI
I don't find clear info about this supporting mouse scroll & touchpad
if support please get doc & also an example
Thx
// =================
// APASTRON KEYBINDS
// =================
sleep(2000); // sleep 2s
print("the active window class is: " + active_window_class());
// Main File
on_window_change(||{
if(active_window_class() == "steam_app_1264850"){
print("Apastron mappings loaded: " + active_window_class());
// maps 'esdf' to 'wasd'
e::w;
s::a;
d::s;
f::d;
c::KEY_CAPSLOCK;
v::BTN_THUMB;
BTN_1::z;
BTN_2::BTN_BACK;
BTN_3::BTN_FORWARD;
a::KEY_LEFTSHIFT;
g::b;
}else{
print("Apastron mappings reverted: " + active_window_class());
// maps 'esdf' back to 'esdf'
e::e;
s::s;
d::d;
f::f;
c::c;
v::v;
BTN_1::BTN_1;
BTN_2::BTN_2;
BTN_3::BTN_3;
a::a;
g::g;
}else if({send_modifier("{shift end}")}){
print("exiting apastron.m2 ");
execute("exit(0)");
}
});
By hotstrings I mean what AutoHotkey means, i.e. being able to type abbreviations and the script would replace it with the full form (like FBI -> Federal Bureau of Investigations).
Does map2 support that? If so - could you, please, provide an example?
cat q.m2
:
a::b;
RUST_BACKTRACE=1 ./target/release/map2 q.m2
:
thread 'tokio-runtime-worker' panicked at 'called `Result::unwrap()` on an `Err` value: Permission denied (os error 13)', /home/pp/git/map2/src/device/virtual_input_device.rs:110:76
stack backtrace:
0: rust_begin_unwind
at /build/rustc-n7HJ8w/rustc-1.47.0+dfsg1+llvm/library/std/src/panicking.rs:475
1: core::panicking::panic_fmt
at /build/rustc-n7HJ8w/rustc-1.47.0+dfsg1+llvm/library/core/src/panicking.rs:85
2: core::result::unwrap_failed
at /build/rustc-n7HJ8w/rustc-1.47.0+dfsg1+llvm/library/core/src/result.rs:1220
3: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
4: tokio::runtime::task::core::Core<T,S>::poll
5: <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
6: tokio::runtime::task::harness::Harness<T,S>::poll
7: std::thread::local::LocalKey<T>::with
8: tokio::runtime::thread_pool::worker::Context::run_task
9: tokio::runtime::thread_pool::worker::Context::run
10: tokio::macros::scoped_tls::ScopedKey<T>::set
11: tokio::runtime::thread_pool::worker::run
12: tokio::runtime::task::core::Core<T,S>::poll
13: <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
14: tokio::runtime::task::harness::Harness<T,S>::poll
15: tokio::runtime::blocking::pool::Inner::run
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
issue: i can't get it to work at all; seems like it doesn't like the file descriptors. I saw issue #3 but it wasn't any help.
system: Fedora 34 Cinnamon (and yes, I tried it with SELinux disabled too)
kernel: 5.15.12-100
install type: tried both manual install from releases (/usr/bin/map2 with chmod 755) and building with cargo.
map2 version: 1.0.6 for releases page / source for cargo (map2 --version
gives map2 1.0
in both cases)
keyboard/mouse: logitech k400 wireless htpc keyboard via logitech receiver
script: just trying to get the simple example.m2 from the README working for now: a::b;
file descriptors: honestly, I was a bit confused about what is supposed to go in here. will give full details below.
This part was the most confusing for me. The README only says:
To describe which devices should be grabbed it is necessary to provide a list of file descriptor paths, regular expressions are also supported.
...
In order to find out which file descriptor corresponds to which physical device one should examine /dev/input/by-id/ and /dev/input/by-path/
But doesn't actually describe how to identify what the correct file descriptor is (e.g. not sure if it's supposed to be obvious or it is purely a trial-and-error process).
Anyway, I had:
$ ls -acl /dev/input/by-id /dev/input/by-path | grep -Pvi 'Headset|spkr'
/dev/input/by-id:
total 0
lrwxrwxrwx. 1 root root 9 Jan 8 19:58 usb-Logitech_USB_Receiver-if02-event-mouse -> ../event4
lrwxrwxrwx. 1 root root 9 Jan 8 19:58 usb-Logitech_USB_Receiver-if02-mouse -> ../mouse1
lrwxrwxrwx. 1 root root 9 Jan 8 19:58 usb-MOSART_Semi._2.4G_Wireless_Mouse-event-if00 -> ../event7
lrwxrwxrwx. 1 root root 9 Jan 8 19:58 usb-MOSART_Semi._2.4G_Wireless_Mouse-event-mouse -> ../event6
lrwxrwxrwx. 1 root root 9 Jan 8 19:58 usb-MOSART_Semi._2.4G_Wireless_Mouse-mouse -> ../mouse0
/dev/input/by-path:
total 0
lrwxrwxrwx. 1 root root 9 Jan 8 19:58 pci-0000:00:12.0-usb-0:2:1.3-event -> ../event3
lrwxrwxrwx. 1 root root 9 Jan 8 19:58 pci-0000:00:13.0-usb-0:4:1.2-event-mouse -> ../event4
lrwxrwxrwx. 1 root root 9 Jan 8 19:58 pci-0000:00:13.0-usb-0:4:1.2-mouse -> ../mouse1
lrwxrwxrwx. 1 root root 9 Jan 8 19:58 pci-0000:00:13.2-usb-0:5.2:1.0-event -> ../event7
lrwxrwxrwx. 1 root root 9 Jan 8 19:58 pci-0000:00:13.2-usb-0:5.2:1.0-event-mouse -> ../event6
lrwxrwxrwx. 1 root root 9 Jan 8 19:58 pci-0000:00:13.2-usb-0:5.2:1.0-mouse -> ../mouse0
Since the example in the README showed 2 entries, I assume that I also need 2 entries: one from /dev/input/by-id
and one from /dev/input/by-path
. I also made the assumption that I wanted one of the "usb-Logitech_USB_Receiver" ones and that I should probably pair similar events (e.g. the file under /dev/input/by-id
that points to ../mouse1 and the file under /dev/input/by-path
that points to ../mouse1)... but all guesswork.
Since I had 2 candidates, I made 2 files and figured I just try one and if it didn't work, then try the other.
/dev/input/by-id/usb-Logitech_USB_Receiver-if02-mouse
/dev/input/by-path/pci-0000:00:13.0-usb-0:4:1.2-mouse
/dev/input/by-id/usb-Logitech_USB_Receiver-if02-event-mouse
/dev/input/by-path/pci-0000:00:13.0-usb-0:4:1.2-event-mouse
Attempting first as regular user then with sudo, using first the precompiled version from releases page then with version built from source with caro.
$ cd /tmp/map2
$ ls -acl
total 1.4M
drwxr-x---. 3 fd fd 60 Jan 9 19:37 map2-1.0.6-x86_64/
-rw-rw----. 1 fd fd 120 Jan 9 19:02 devices-event4.list
-rw-rw----. 1 fd fd 108 Jan 9 19:02 devices-mouse1.list
-rw-rw----. 1 fd fd 25 Jan 9 19:01 example.m2
-rw-r--r--. 1 fd fd 1.4M Jan 9 19:38 map2-1.0.6-x86_64.tar.gz
$ sudo -i
# setenforce 0
# getenforce
Permissive
# cd /tmp/map2/map2-1.0.6-x86_64
# find . -type f
./usr/bin/map2
./usr/share/man/man1/map2.1.gz
# cp -a -t /usr/bin ./usr/bin/map2
# cp -a -t /usr/share/man/man1 ./usr/share/man/man1/map2.1.gz
# chmod 755 /usr/bin/map2
# exit
$ map2 --version
map2 1.0
$ map2 -d devices-event4.list example.m2
thread 'tokio-runtime-worker' panicked at 'failed to open fd '/dev/input/by-path/pci-0000:00:13.0-usb-0:4:1.2-event-mouse': Os { code: 13, kind: PermissionDenied, message: "Permission denied" }', /home/shiro/project/map2/src/device/virtual_input_device.rs:88:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
$ map2 -d devices-mouse1.list example.m2
thread 'tokio-runtime-worker' panicked at 'failed to open fd '/dev/input/by-path/pci-0000:00:13.0-usb-0:4:1.2-mouse': Os { code: 13, kind: PermissionDenied, message: "Permission denied" }', /home/shiro/project/map2/src/device/virtual_input_device.rs:88:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
$ sudo map2 -d devices-event4.list example.m2
failed to grab device '/dev/input/by-id/usb-Logitech_USB_Receiver-if02-event-mouse': Device or resource busy (os error 16)
$ sudo map2 -d devices-mouse1.list example.m2
thread 'tokio-runtime-worker' panicked at 'failed to open fd '/dev/input/by-path/pci-0000:00:13.0-usb-0:4:1.2-mouse': Os { code: 25, kind: Other, message: "Inappropriate ioctl for device" }', /home/shiro/project/map2/src/device/virtual_input_device.rs:91:56
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
From this, I think that my devices-event4.list is the correct file descriptor to use for my logitech k400 but still can't get it to work.
I tried the same thing with the cargo build but got the same error message.
# dnf install -y ncurses ncurses-base ncurses-static ncurses-libs ncurses-devel ncurses-c++-libs \
libevdev libevdev-devel xorg-x11-drv-evdev xorg-x11-drv-evdev-devel libevdev-utils
# exit
$ mkdir /tmp/map2
$ git clone https://github.com/shiro/map2 map2_src
$ cd map2_src/
$ cargo build --release
$ cd target/release/
$ ./map2 --version
map2 1.0
$ ./map2 -d ../../../devices-mouse1.list ../../../example.m2
thread 'tokio-runtime-worker' panicked at 'failed to open fd '/dev/input/by-path/pci-0000:00:13.0-usb-0:4:1.2-mouse': Os { code: 13, kind: PermissionDenied, message: "Permission denied" }', /tmp/map2/map2/src/device/virtual_input_device.rs:88:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
$ sudo ./map2 -d ../../../devices-mouse1.list ../../../example.m2
thread 'tokio-runtime-worker' panicked at 'failed to open fd '/dev/input/by-path/pci-0000:00:13.0-usb-0:4:1.2-mouse': Os { code: 25, kind: Uncategorized, message: "Inappropriate ioctl for device" }', /tmp/map2/map2/src/device/virtual_input_device.rs:91:56
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
$ ./map2 -d ../../../devices-event4.list ../../../example.m2
thread 'tokio-runtime-worker' panicked at 'failed to open fd '/dev/input/by-path/pci-0000:00:13.0-usb-0:4:1.2-event-mouse': Os { code: 13, kind: PermissionDenied, message: "Permission denied" }', /tmp/map2/map2/src/device/virtual_input_device.rs:88:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
$ sudo ./map2 -d ../../../devices-event4.list ../../../example.m2
failed to grab device '/dev/input/by-id/usb-Logitech_USB_Receiver-if02-event-mouse': Device or resource busy (os error 16)
I've closed several processes like Solaar that I thought might potentially be responsible but no luck..
Any ideas?
Is it possible to emulate any controller with mouse and keyboard?
Looks very interesting, but it suffers from the common "requires a very recent GLIBC" issue. If you could release binaries that are made on an older machine, it would not affect people with a newer GLIBC, but it would extend your reach. I am on the latest Ubuntu-family LTS (20.04), but last month I was still running 18.04 and I ran into this issue a lot...
Debug output:
map2: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.33' not found (required by map2)
map2: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by map2)
I've been trying to remap CAPSLOCK to Super_L via your method,
{capslock down}::{
caps_down = true;
key_pressed = false;
send("{ctrl down}");
};
{capslock up}::{
caps_down = false;
send("{ctrl up}");
if (key_pressed == false){
send("{esc}");
}
};
where I tried replacing ctrl
with win
, super
, hyper
, Super_L
, and 0xffeb
. No success.
Would there be a way to achieve this by default, or should I be looking into modifying the source code itself?
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.