Skip to content

Commit 5da37ca

Browse files
Final tweaks before release
1 parent 00337ce commit 5da37ca

File tree

6 files changed

+731
-73
lines changed

6 files changed

+731
-73
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "rusty-keys"
33
version = "0.0.1"
44

55
authors = ["moparisthebest <admin@moparisthebest.com>"]
6-
license = "AGPLv3"
6+
license = "AGPL-3.0"
77

88
description = "Linux keyboard mapper"
99
repository = "https://code.moparisthebest.com/moparisthebest/rusty-keys"

LICENSE.md

Lines changed: 660 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 51 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,54 @@
1-
uinput
1+
rusty-keys
22
======
3-
`/dev/uinput` high level wrapper.
3+
uinput level keyboard mapper for linux, with advanced caps lock and shift swapping behavior
4+
5+
This is the only keymapper I am aware of capable of implementing this layout:
6+
![Unix Programmer's Dvorak](https://www.moparisthebest.com/kbs/programmer-dvorak-NoSecondary-NumpadStandard-NoSwap-StandardNums-SwapAt-SwapPipe.svg)
7+
8+
The Problem
9+
-----------
10+
If you ever have mapped keys on linux, you know that there is the console keymap (loadkeys) and the X keymap (setxkbmap)
11+
also things like SDL and Virtualbox grab the input directly and respect no maps. Lastly I want to revert to QWERTY when
12+
holding ctrl so ctrl+c works just like normal, without remapping all programs to ctrl+j. Linux keymaps cannot do this either.
13+
14+
The Solution
15+
------------
16+
1. Grab a keyboard device directly so only we can read events from it.
17+
2. Create a new keyboard input device with uinput, this is identical to any other keyboard device to anything running on the box.
18+
3. Read input_events from real device, map them, send them to our created device.
19+
20+
This solution is what rusty-keys implements, it works in ttys, in X, in virtualbox even running windows or whatever,
21+
on SDL games, it will work literally everywhere, because rusty-keys just creates a regular keyboard.
22+
23+
How to run
24+
----------
25+
26+
When ran, it will read a keymap.toml file from your current working directory, refer to example and tweak to suit.
427

5-
Example
6-
-------
7-
The following example writes `hello world`.
8-
9-
```rust
10-
extern crate uinput;
11-
use uinput::event::keyboard;
12-
13-
use std::thread;
14-
use std::time::Duration;
15-
16-
fn main() {
17-
let mut device = uinput::default().unwrap()
18-
.name("test").unwrap()
19-
.event(uinput::event::Keyboard::All).unwrap()
20-
.create().unwrap();
21-
22-
thread::sleep(Duration::from_secs(1));
23-
24-
device.click(&keyboard::Key::H).unwrap();
25-
device.click(&keyboard::Key::E).unwrap();
26-
device.click(&keyboard::Key::L).unwrap();
27-
device.click(&keyboard::Key::L).unwrap();
28-
device.click(&keyboard::Key::O).unwrap();
29-
device.click(&keyboard::Key::Space).unwrap();
30-
device.click(&keyboard::Key::W).unwrap();
31-
device.click(&keyboard::Key::O).unwrap();
32-
device.click(&keyboard::Key::R).unwrap();
33-
device.click(&keyboard::Key::L).unwrap();
34-
device.click(&keyboard::Key::D).unwrap();
35-
device.click(&keyboard::Key::Enter).unwrap();
36-
37-
device.synchronize().unwrap();
38-
}
3928
```
29+
Usage: rusty-keys [options]
30+
31+
Options:
32+
-h, --help prints this help message
33+
-v, --version prints the version
34+
-d, --device DEVICE specify the keyboard input device file
35+
-c, --config FILE specify the keymap config file to use
36+
```
37+
38+
with only one keyboard attached:
39+
`rusty-keys`
40+
41+
with multiple keyboards, currently you must specify one:
42+
`rusty-keys -d /dev/input/event0`
43+
44+
find all eligible keyboard devices like:
45+
`grep -E 'Handlers|EV' /proc/bus/input/devices | grep -B1 120013 | grep -Eo event[0-9]+`
46+
47+
License
48+
-------
49+
AGPLv3 for now, message me if you have a problem with this
50+
51+
Notes
52+
-----
53+
Technically this is a re-implementation of a [previous](https://code.moparisthebest.com/moparisthebest/uinput-mapper/src/master/uinputmapper/keymapper.py) [python](https://code.moparisthebest.com/moparisthebest/uinput-mapper/src/master/keymaps/dvorak.py) [program](https://code.moparisthebest.com/moparisthebest/uinput-mapper/src/master/input-read#L151)
54+
I had been using for 3 years previously.

keymap.toml

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env python
1+
22
# pressing all of these keys along with a number key representing the index of keymaps changes the layout
33
# ie, in this case pressing both and 0 would go QWERTY, while both and 1 would go dvorak
44
switch_layout_keys = ['LEFTSHIFT','RIGHTSHIFT']
@@ -9,18 +9,9 @@ revert_default_key = 'LEFTCTRL'
99
revert_keymap_index = 0
1010

1111
# this is the default index to use when the program first starts
12-
# in this case, 2 means modified Progammer Dvorak
12+
# in this case, 2 means Unix Programmer Dvorak
1313
default_keymap_index = 2
1414

15-
# these are keys that caps_lock doesn't modify by default, but that you would like it to, affects all keymaps
16-
caps_lock_modify = """
17-
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, PSLS,PAST,PMNS,
18-
LBRC,RBRC,BSLS, P7, P8, P9,
19-
SCLN,QUOT, P4, P5, P6, PPLS,
20-
COMM,DOT, SLSH, P1, P2, P3,
21-
P0, PDOT
22-
"""
23-
2415
# these are the keymaps available, you can add as many as you want or re-order them, just be aware the mapping is
2516
# always done from the first one to all subsequent ones, so you probably want to leave QWERTY or similar up top
2617
keymaps = [
@@ -43,7 +34,7 @@ keymaps = [
4334
LSFT,SCLN,Q, J, K, X, B, M, W, V, Z, RSFT, UP, P1, P2, P3,
4435
LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT
4536
""",
46-
# Unix Dvorak Programmer Dvorak - for unix developers who are switching from dvorak
37+
# Unix Programmer Dvorak - for unix developers who are switching from dvorak
4738
# https://www.moparisthebest.com/kbs/programmer-dvorak-NoSecondary-NumpadStandard-NoSwap-StandardNums-SwapAt-SwapPipe.svg
4839
"""
4940
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK,

src/keymapper.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl KeyMaps {
7979
panic!("default_keymap_index ({}) and revert_keymap_index ({}) must be less than keymaps length ({}),", config.default_keymap_index, config.revert_keymap_index, config.keymaps.len());
8080
}
8181
let base_keymap = parse_keymap_numeric(key_map, &config.keymaps[0]);
82-
println!("base_keymap : {:?}", base_keymap);
82+
//println!("base_keymap : {:?}", base_keymap);
8383
let mut keymaps: Vec<Box<KeyMapper>> = vec!(Box::new(NOOP)); // todo: can we share the box?
8484
let mut keymap_index_keys: HashMap<u16, usize> = HashMap::new();
8585
for (x, v) in config.keymaps.iter().enumerate() {
@@ -363,7 +363,6 @@ pub struct KeymapConfig {
363363
revert_default_key: String,
364364
revert_keymap_index: usize,
365365
default_keymap_index: usize,
366-
caps_lock_modify: String,
367366
keymaps: Vec<String>
368367
}
369368

src/main.rs

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use rusty_keys::KeyMaps;
1111
use ffi::*;
1212
use libc::{c_int, input_event};
1313

14-
use std::thread;
15-
use std::time::Duration;
14+
//use std::thread;
15+
//use std::time::Duration;
1616

1717
use std::process::{exit, Command};
1818
use std::fs::File;
@@ -30,18 +30,17 @@ const EV_KEY_U16: u16 = EV_KEY as u16;
3030
#[derive(Debug)]
3131
struct Config {
3232
device_file: String,
33-
log_file: String
33+
config_file: String
3434
}
3535

3636
impl Config {
37-
fn new(device_file: String, log_file: String) -> Self {
38-
Config { device_file: device_file, log_file: log_file }
37+
fn new(device_file: String, config_file: String) -> Self {
38+
Config { device_file: device_file, config_file: config_file }
3939
}
4040
}
4141

4242
fn main() {
4343
let key_map = KeyMaps::key_map();
44-
4544
//println!("key_map: {:?}", key_map);
4645

4746
let device = rusty_keys::default().expect("1")
@@ -50,23 +49,17 @@ fn main() {
5049
//.event(uinput::event::Keyboard::All).unwrap()
5150
.create().expect("4");
5251

53-
let mut key_map = KeyMaps::from_cfg(&key_map, "keymap.toml");
54-
//println!("keymaps: {:?}", keymaps);
55-
56-
//let mut key_map = KeyMap::new();
57-
//key_map.map(KEY_A, KEY_B);
58-
59-
thread::sleep(Duration::from_secs(1));
60-
61-
//device.click(EV_KEY, KEY_H).unwrap();
62-
//device.synchronize().unwrap();
52+
//thread::sleep(Duration::from_secs(1));
6353

6454
let config = parse_args();
65-
println!("Config: {:?}", config);
55+
//println!("Config: {:?}", config);
6656

6757
let mut input_device = InputDevice::open(&config.device_file);
6858
input_device.grab();
6959

60+
let mut key_map = KeyMaps::from_cfg(&key_map, config.config_file);
61+
//println!("keymaps: {:?}", keymaps);
62+
7063
loop {
7164
let event = input_device.read_event();
7265
if event.type_ == EV_KEY_U16 {
@@ -94,8 +87,8 @@ fn parse_args() -> Config {
9487
let mut opts = Options::new();
9588
opts.optflag("h", "help", "prints this help message");
9689
opts.optflag("v", "version", "prints the version");
97-
opts.optopt("d", "device", "specify the device file", "DEVICE");
98-
opts.optopt("f", "file", "specify the file to log to", "FILE");
90+
opts.optopt("d", "device", "specify the keyboard input device file", "DEVICE");
91+
opts.optopt("c", "config", "specify the keymap config file to use", "FILE");
9992

10093
let matches = opts.parse(&args[1..]).unwrap_or_else(|e| panic!("{}", e));
10194
if matches.opt_present("h") {
@@ -104,14 +97,14 @@ fn parse_args() -> Config {
10497
}
10598

10699
if matches.opt_present("v") {
107-
println!("{}", VERSION);
100+
println!("rusty-keys {}", VERSION);
108101
exit(0);
109102
}
110103

111104
let device_file = matches.opt_str("d").unwrap_or_else(|| get_default_device());
112-
let log_file = matches.opt_str("f").unwrap_or("keys.log".to_owned());
105+
let config_file = matches.opt_str("c").unwrap_or("keymap.toml".to_owned());
113106

114-
Config::new(device_file, log_file)
107+
Config::new(device_file, config_file)
115108
}
116109

117110
fn get_default_device() -> String {

0 commit comments

Comments
 (0)