Implement keymap

This commit is contained in:
Takashi Kokubun 2021-12-19 20:05:59 -08:00
parent f5695d3bc2
commit c57dbee606
No known key found for this signature in database
GPG Key ID: 6FFC433B12EE23DD
9 changed files with 113 additions and 42 deletions

View File

@ -1,8 +1,8 @@
modmap:
- name: Global
remap:
a: b
# modmap:
# - name: Global
# remap:
# a: b
keymap:
- name: Global
remap:
C-i: C-h
C-i: C-u

View File

@ -1,4 +1,4 @@
use crate::config::keypress::{parse_keypress, KeyPress};
use crate::config::key_press::{parse_key_press, KeyPress};
use std::collections::HashMap;
use crate::config::actions::Actions;
@ -31,8 +31,8 @@ impl<'de> Deserialize<'de> for Action {
where
E: de::Error,
{
let keypress = parse_keypress(value).map_err(de::Error::custom)?;
Ok(Action::KeyPress(keypress))
let key_press = parse_key_press(value).map_err(de::Error::custom)?;
Ok(Action::KeyPress(key_press))
}
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
@ -44,12 +44,12 @@ impl<'de> Deserialize<'de> for Action {
Some("remap") => {
let mut action: HashMap<KeyPress, Vec<Action>> = HashMap::new();
let remap = map.next_value::<HashMap<KeyPress, Actions>>()?;
for (keypress, actions) in remap.into_iter() {
for (key_press, actions) in remap.into_iter() {
let actions = match actions {
Actions::Action(action) => vec![action],
Actions::Actions(actions) => actions,
};
action.insert(keypress, actions);
action.insert(key_press, actions);
}
Action::Remap(action)
}

View File

@ -1,5 +1,5 @@
use crate::config::action::Action;
use crate::config::keypress::parse_keypress;
use crate::config::key_press::parse_key_press;
use serde::de;
use serde::de::{value, MapAccess, SeqAccess, Visitor};
use serde::{Deserialize, Deserializer};
@ -29,8 +29,8 @@ impl<'de> Deserialize<'de> for Actions {
where
E: de::Error,
{
let keypress = parse_keypress(value).map_err(de::Error::custom)?;
Ok(Actions::Action(Action::KeyPress(keypress)))
let key_press = parse_key_press(value).map_err(de::Error::custom)?;
Ok(Actions::Action(Action::KeyPress(key_press)))
}
fn visit_seq<S>(self, seq: S) -> Result<Self::Value, S::Error>

View File

@ -40,7 +40,7 @@ impl<'de> Deserialize<'de> for KeyPress {
where
E: de::Error,
{
parse_keypress(value).map_err(de::Error::custom)
parse_key_press(value).map_err(de::Error::custom)
}
}
@ -48,7 +48,7 @@ impl<'de> Deserialize<'de> for KeyPress {
}
}
pub fn parse_keypress(input: &str) -> Result<KeyPress, Box<dyn error::Error>> {
pub fn parse_key_press(input: &str) -> Result<KeyPress, Box<dyn error::Error>> {
let keys: Vec<&str> = input.split("-").collect();
if let Some((key, modifiers)) = keys.split_last() {
let mut shift = false;
@ -75,7 +75,7 @@ pub fn parse_keypress(input: &str) -> Result<KeyPress, Box<dyn error::Error>> {
windows,
})
} else {
Err(format!("empty keypress: {}", input).into())
Err(format!("empty key_press: {}", input).into())
}
}

View File

@ -1,6 +1,6 @@
use crate::config::action::Action;
use crate::config::actions::Actions;
use crate::config::keypress::KeyPress;
use crate::config::key_press::KeyPress;
use crate::config::wm_class::WMClass;
use serde::de::{MapAccess, Visitor};
use serde::{Deserialize, Deserializer};
@ -36,12 +36,12 @@ where
{
let mut keymap = HashMap::new();
while let Some(keypress) = map.next_key::<KeyPress>()? {
while let Some(key_press) = map.next_key::<KeyPress>()? {
let actions = match map.next_value::<Actions>()? {
Actions::Action(action) => vec![action],
Actions::Actions(actions) => actions,
};
keymap.insert(keypress, actions);
keymap.insert(key_press, actions);
}
Ok(keymap)

View File

@ -1,8 +1,8 @@
mod action;
pub mod action;
mod actions;
mod key;
pub mod key_press;
mod keymap;
pub mod keypress;
mod modmap;
mod wm_class;

View File

@ -1,14 +1,14 @@
use crate::config::action::Action;
use crate::config::key_press::{KeyPress, Modifier};
use crate::Config;
use evdev::uinput::VirtualDevice;
use evdev::{EventType, InputEvent, Key};
use std::error::Error;
use lazy_static::lazy_static;
use crate::Config;
use crate::config::keypress::Modifier;
use std::collections::HashMap;
use std::error::Error;
pub struct EventHandler {
pub config: Config,
pub device: VirtualDevice,
device: VirtualDevice,
shift: bool,
control: bool,
alt: bool,
@ -16,9 +16,8 @@ pub struct EventHandler {
}
impl EventHandler {
pub fn new(config: Config, device: VirtualDevice) -> EventHandler {
pub fn new(device: VirtualDevice) -> EventHandler {
EventHandler {
config,
device,
shift: false,
control: false,
@ -28,28 +27,95 @@ impl EventHandler {
}
// Handle EventType::KEY
pub fn on_event(&mut self, event: InputEvent) -> Result<(), Box<dyn Error>> {
pub fn on_event(&mut self, event: InputEvent, config: &Config) -> Result<(), Box<dyn Error>> {
let mut key = Key::new(event.code());
// println!("=> {}: {:?}", event.value(), &key);
// Perform modmap
for modmap in &self.config.modmap {
// Apply modmap
for modmap in &config.modmap {
if let Some(modmap_key) = modmap.remap.get(&key) {
key = modmap_key.clone();
break;
}
}
// Perform keymap
// Apply keymap
if let Some(modifier) = MODIFIER_KEYS.get(&key.code()) {
self.update_modifier(modifier, event.value());
} else if let Some(actions) = self.find_keymap(config, &key, event.value()) {
for action in actions {
self.dispatch_action(action)?;
}
return Ok(());
}
self.device.emit(&[InputEvent::new(EventType::KEY, key.code(), event.value())])?;
self.send_key(&key, event.value())?;
Ok(())
}
pub fn send_event(&mut self, event: InputEvent) -> Result<(), Box<dyn Error>> {
self.device.emit(&[event])?;
pub fn send_event(&mut self, event: InputEvent) -> std::io::Result<()> {
// if event.event_type() == EventType::KEY { println!("{}: {:?}", event.value(), Key::new(event.code())); }
self.device.emit(&[event])
}
fn send_key(&mut self, key: &Key, value: i32) -> std::io::Result<()> {
let event = InputEvent::new(EventType::KEY, key.code(), value);
self.send_event(event)
}
fn find_keymap<'a>(
&self,
config: &'a Config,
key: &Key,
value: i32,
) -> Option<&'a Vec<Action>> {
if !is_pressed(value) {
return None;
}
let key_press = KeyPress {
key: key.clone(),
shift: self.shift,
control: self.control,
alt: self.alt,
windows: self.windows,
};
for keymap in &config.keymap {
if let Some(actions) = keymap.remap.get(&key_press) {
return Some(actions);
}
}
None
}
fn dispatch_action(&mut self, action: &Action) -> Result<(), Box<dyn Error>> {
match action {
Action::KeyPress(key_press) => {
self.send_modifier(self.shift, key_press.shift, &SHIFT_KEY)?;
self.send_modifier(self.control, key_press.control, &CONTROL_KEY)?;
self.send_modifier(self.alt, key_press.alt, &ALT_KEY)?;
self.send_modifier(self.windows, key_press.windows, &WINDOWS_KEY)?;
self.send_key(&key_press.key, PRESS)?;
self.send_key(&key_press.key, RELEASE)?;
self.send_modifier(key_press.windows, self.windows, &WINDOWS_KEY)?;
self.send_modifier(key_press.alt, self.alt, &ALT_KEY)?;
self.send_modifier(key_press.control, self.control, &CONTROL_KEY)?;
self.send_modifier(key_press.shift, self.shift, &SHIFT_KEY)?;
}
Action::Remap(_remap) => {}
}
Ok(())
}
fn send_modifier(&mut self, from: bool, to: bool, key: &Key) -> Result<(), Box<dyn Error>> {
if !from && to {
self.send_key(key, PRESS)?;
}
if from && !to {
self.send_key(key, RELEASE)?;
}
Ok(())
}
@ -68,7 +134,7 @@ fn is_pressed(value: i32) -> bool {
}
// InputEvent#value
// static RELEASE: i32 = 0;
static RELEASE: i32 = 0;
static PRESS: i32 = 1;
static REPEAT: i32 = 2;
@ -87,4 +153,9 @@ lazy_static! {
(Key::KEY_LEFTMETA.code(), Modifier::Windows),
(Key::KEY_RIGHTMETA.code(), Modifier::Windows),
].into_iter().collect();
static ref SHIFT_KEY: Key = Key::new(Key::KEY_LEFTSHIFT.code());
static ref CONTROL_KEY: Key = Key::new(Key::KEY_LEFTCTRL.code());
static ref ALT_KEY: Key = Key::new(Key::KEY_LEFTALT.code());
static ref WINDOWS_KEY: Key = Key::new(Key::KEY_LEFTMETA.code());
}

View File

@ -1,8 +1,8 @@
extern crate evdev;
extern crate nix;
use crate::event_handler::EventHandler;
use crate::output::build_device;
use crate::event_handler::{EventHandler};
use crate::Config;
use evdev::{Device, EventType, Key};
use nix::sys::select::select;
@ -13,7 +13,7 @@ use std::fs::read_dir;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::AsRawFd;
pub fn event_loop(mut input_devices: Vec<Device>, config: Config) -> Result<(), Box<dyn Error>> {
pub fn event_loop(mut input_devices: Vec<Device>, config: &Config) -> Result<(), Box<dyn Error>> {
for device in &mut input_devices {
device
.grab()
@ -22,14 +22,14 @@ pub fn event_loop(mut input_devices: Vec<Device>, config: Config) -> Result<(),
let output_device =
build_device().map_err(|e| format!("Failed to build an output device: {}", e))?;
let mut handler = EventHandler::new(config, output_device);
let mut handler = EventHandler::new(output_device);
loop {
let readable_fds = select_readable(&input_devices)?;
for input_device in &mut input_devices {
if readable_fds.contains(input_device.as_raw_fd()) {
for event in input_device.fetch_events()? {
if event.event_type() == EventType::KEY {
handler.on_event(event)?;
handler.on_event(event, config)?;
} else {
handler.send_event(event)?;
}

View File

@ -7,9 +7,9 @@ use std::process::exit;
extern crate getopts;
mod config;
mod event_handler;
mod input;
mod output;
mod event_handler;
fn usage(program: &str, opts: Options) -> String {
let brief = format!("Usage: {} CONFIG [options]", program);
@ -53,7 +53,7 @@ fn main() {
Err(e) => abort(&format!("Failed to select devices: {}", e)),
};
if let Err(e) = event_loop(input_devices, config) {
if let Err(e) = event_loop(input_devices, &config) {
abort(&format!("Error: {}", e));
}
}