New Hotkey struct; compiling

main
Tait Hoyem 2 years ago
parent 4b80557af0
commit 56a94b2dee

@ -50,16 +50,16 @@ impl fmt::Display for Error {
}
}
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Hotkey {
pub mode: String,
pub keysym: evdev::Key,
pub mode: Option<String>,
pub keysym: rdev::Key,
pub modifiers: Vec<Modifier>,
pub command: String,
pub consume: bool,
}
#[derive(Debug, PartialEq, Copy, Clone)]
#[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)]
// TODO: make the commented-out modifiers available
pub enum Modifier {
Super,
@ -78,7 +78,7 @@ pub enum Modifier {
}
impl Hotkey {
pub fn new(mode: String, keysym: evdev::Key, modifiers: Vec<Modifier>, command: String, consume: bool) -> Self {
pub fn new(mode: Option<String>, keysym: rdev::Key, modifiers: Vec<Modifier>, command: String, consume: bool) -> Self {
Hotkey { mode, keysym, modifiers, command, consume }
}
}
@ -96,108 +96,113 @@ fn load_file_contents(path: path::PathBuf) -> Result<String, Error> {
}
fn parse_contents(contents: String) -> Result<Vec<Hotkey>, Error> {
let key_to_evdev_key: HashMap<&str, evdev::Key> = HashMap::from([
("q", evdev::Key::KEY_Q),
("w", evdev::Key::KEY_W),
("e", evdev::Key::KEY_E),
("r", evdev::Key::KEY_R),
("t", evdev::Key::KEY_T),
("y", evdev::Key::KEY_Y),
("u", evdev::Key::KEY_U),
("i", evdev::Key::KEY_I),
("o", evdev::Key::KEY_O),
("p", evdev::Key::KEY_P),
("a", evdev::Key::KEY_A),
("s", evdev::Key::KEY_S),
("d", evdev::Key::KEY_D),
("f", evdev::Key::KEY_F),
("g", evdev::Key::KEY_G),
("h", evdev::Key::KEY_H),
("j", evdev::Key::KEY_J),
("k", evdev::Key::KEY_K),
("l", evdev::Key::KEY_L),
("z", evdev::Key::KEY_Z),
("x", evdev::Key::KEY_X),
("c", evdev::Key::KEY_C),
("v", evdev::Key::KEY_V),
("b", evdev::Key::KEY_B),
("n", evdev::Key::KEY_N),
("m", evdev::Key::KEY_M),
("1", evdev::Key::KEY_1),
("2", evdev::Key::KEY_2),
("3", evdev::Key::KEY_3),
("4", evdev::Key::KEY_4),
("5", evdev::Key::KEY_5),
("6", evdev::Key::KEY_6),
("7", evdev::Key::KEY_7),
("8", evdev::Key::KEY_8),
("9", evdev::Key::KEY_9),
("0", evdev::Key::KEY_0),
("escape", evdev::Key::KEY_ESC),
("delete", evdev::Key::KEY_DELETE),
("backspace", evdev::Key::KEY_BACKSPACE),
("return", evdev::Key::KEY_ENTER),
("enter", evdev::Key::KEY_ENTER),
("tab", evdev::Key::KEY_TAB),
("space", evdev::Key::KEY_SPACE),
("minus", evdev::Key::KEY_MINUS),
("-", evdev::Key::KEY_MINUS),
("equal", evdev::Key::KEY_EQUAL),
("=", evdev::Key::KEY_EQUAL),
("grave", evdev::Key::KEY_GRAVE),
("`", evdev::Key::KEY_GRAVE),
("print", evdev::Key::KEY_SYSRQ),
("volumeup", evdev::Key::KEY_VOLUMEUP),
("xf86audioraisevolume", evdev::Key::KEY_VOLUMEUP),
("volumedown", evdev::Key::KEY_VOLUMEDOWN),
("xf86audiolowervolume", evdev::Key::KEY_VOLUMEDOWN),
("mute", evdev::Key::KEY_MUTE),
("xf86audiomute", evdev::Key::KEY_MUTE),
("brightnessup", evdev::Key::KEY_BRIGHTNESSUP),
("brightnessdown", evdev::Key::KEY_BRIGHTNESSDOWN),
(",", evdev::Key::KEY_COMMA),
("comma", evdev::Key::KEY_COMMA),
(".", evdev::Key::KEY_DOT),
("dot", evdev::Key::KEY_DOT),
("/", evdev::Key::KEY_SLASH),
("slash", evdev::Key::KEY_SLASH),
("backslash", evdev::Key::KEY_BACKSLASH),
("leftbrace", evdev::Key::KEY_LEFTBRACE),
("[", evdev::Key::KEY_LEFTBRACE),
("rightbrace", evdev::Key::KEY_RIGHTBRACE),
("]", evdev::Key::KEY_RIGHTBRACE),
(";", evdev::Key::KEY_SEMICOLON),
("semicolon", evdev::Key::KEY_SEMICOLON),
("'", evdev::Key::KEY_APOSTROPHE),
("apostrophe", evdev::Key::KEY_APOSTROPHE),
("left", evdev::Key::KEY_LEFT),
("right", evdev::Key::KEY_RIGHT),
("up", evdev::Key::KEY_UP),
("down", evdev::Key::KEY_DOWN),
("f1", evdev::Key::KEY_F1),
("f2", evdev::Key::KEY_F2),
("f3", evdev::Key::KEY_F3),
("f4", evdev::Key::KEY_F4),
("f5", evdev::Key::KEY_F5),
("f6", evdev::Key::KEY_F6),
("f7", evdev::Key::KEY_F7),
("f8", evdev::Key::KEY_F8),
("f9", evdev::Key::KEY_F9),
("f10", evdev::Key::KEY_F10),
("f11", evdev::Key::KEY_F11),
("f12", evdev::Key::KEY_F12),
("f13", evdev::Key::KEY_F13),
("f14", evdev::Key::KEY_F14),
("f15", evdev::Key::KEY_F15),
("f16", evdev::Key::KEY_F16),
("f17", evdev::Key::KEY_F17),
("f18", evdev::Key::KEY_F18),
("f19", evdev::Key::KEY_F19),
("f20", evdev::Key::KEY_F20),
("f21", evdev::Key::KEY_F21),
("f22", evdev::Key::KEY_F22),
("f23", evdev::Key::KEY_F23),
("f24", evdev::Key::KEY_F24),
let key_to_evdev_key: HashMap<&str, rdev::Key> = HashMap::from([
("q", rdev::Key::KeyQ),
("w", rdev::Key::KeyW),
("e", rdev::Key::KeyE),
("r", rdev::Key::KeyR),
("t", rdev::Key::KeyT),
("y", rdev::Key::KeyY),
("u", rdev::Key::KeyU),
("i", rdev::Key::KeyI),
("o", rdev::Key::KeyO),
("p", rdev::Key::KeyP),
("a", rdev::Key::KeyA),
("s", rdev::Key::KeyS),
("d", rdev::Key::KeyD),
("f", rdev::Key::KeyF),
("g", rdev::Key::KeyG),
("h", rdev::Key::KeyH),
("j", rdev::Key::KeyJ),
("k", rdev::Key::KeyK),
("l", rdev::Key::KeyL),
("z", rdev::Key::KeyZ),
("x", rdev::Key::KeyX),
("c", rdev::Key::KeyC),
("v", rdev::Key::KeyV),
("b", rdev::Key::KeyB),
("n", rdev::Key::KeyN),
("m", rdev::Key::KeyM),
("1", rdev::Key::Num1),
("2", rdev::Key::Num2),
("3", rdev::Key::Num3),
("4", rdev::Key::Num4),
("5", rdev::Key::Num5),
("6", rdev::Key::Num6),
("7", rdev::Key::Num7),
("8", rdev::Key::Num8),
("9", rdev::Key::Num9),
("0", rdev::Key::Num0),
("escape", rdev::Key::Escape),
("delete", rdev::Key::Delete),
("backspace", rdev::Key::Backspace),
("return", rdev::Key::Return),
("enter", rdev::Key::Return),
("tab", rdev::Key::Tab),
("space", rdev::Key::Space),
("minus", rdev::Key::Minus),
("-", rdev::Key::Minus),
("equal", rdev::Key::Equal),
("=", rdev::Key::Equal),
("grave", rdev::Key::BackQuote),
("`", rdev::Key::BackQuote),
("print", rdev::Key::PrintScreen),
/*
("volumeup", rdev::Key::KEY_VOLUMEUP),
("xf86audioraisevolume", rdev::Key::KEY_VOLUMEUP),
("volumedown", rdev::Key::KEY_VOLUMEDOWN),
("xf86audiolowervolume", rdev::Key::KEY_VOLUMEDOWN),
("mute", rdev::Key::KEY_MUTE),
("xf86audiomute", rdev::Key::KEY_MUTE),
("brightnessup", rdev::Key::KEY_BRIGHTNESSUP),
("brightnessdown", rdev::Key::KEY_BRIGHTNESSDOWN),
TODO: find ways to accept xf86 keys
*/
(",", rdev::Key::Comma),
("comma", rdev::Key::Comma),
(".", rdev::Key::Dot),
("dot", rdev::Key::Dot),
("/", rdev::Key::Slash),
("slash", rdev::Key::Slash),
("backslash", rdev::Key::IntlBackslash),
("leftbrace", rdev::Key::LeftBracket),
("[", rdev::Key::LeftBracket),
("rightbrace", rdev::Key::RightBracket),
("]", rdev::Key::RightBracket),
(";", rdev::Key::SemiColon),
("semicolon", rdev::Key::SemiColon),
("'", rdev::Key::Quote),
("apostrophe", rdev::Key::Quote),
("left", rdev::Key::LeftArrow),
("right", rdev::Key::RightArrow),
("up", rdev::Key::UpArrow),
("down", rdev::Key::DownArrow),
("f1", rdev::Key::F1),
("f2", rdev::Key::F2),
("f3", rdev::Key::F3),
("f4", rdev::Key::F4),
("f5", rdev::Key::F5),
("f6", rdev::Key::F6),
("f7", rdev::Key::F7),
("f8", rdev::Key::F8),
("f9", rdev::Key::F9),
("f10", rdev::Key::F10),
("f11", rdev::Key::F11),
("f12", rdev::Key::F12),
/*
("f13", rdev::Key::F13),
("f14", rdev::Key::F14),
("f15", rdev::Key::F15),
("f16", rdev::Key::F16),
("f17", rdev::Key::F17),
("f18", rdev::Key::F18),
("f19", rdev::Key::F19),
("f20", rdev::Key::F20),
("f21", rdev::Key::F21),
("f22", rdev::Key::F22),
("f23", rdev::Key::F23),
("f24", rdev::Key::F24),
*/
]);
let mod_to_mod_enum: HashMap<&str, Modifier> = HashMap::from([
@ -306,9 +311,9 @@ fn parse_contents(contents: String) -> Result<Vec<Hotkey>, Error> {
fn parse_keybind(
line: &str,
line_nr: u32,
key_to_evdev_key: &HashMap<&str, evdev::Key>,
key_to_evdev_key: &HashMap<&str, rdev::Key>,
mod_to_mod_enum: &HashMap<&str, Modifier>,
) -> Result<(String, evdev::Key, Vec<Modifier>, bool), Error> {
) -> Result<(Option<String>, rdev::Key, Vec<Modifier>, bool), Error> {
let line = line.split('#').next().unwrap();
let tokens: Vec<String> =
line.split('+').map(|s| s.trim().to_lowercase()).filter(|s| s != "_").collect();
@ -343,15 +348,19 @@ fn parse_keybind(
.map(|s| s.to_string())
.collect::<Vec<String>>()
.len() == 1 { true } else { false };
let mode = tokens
let mode = match tokens
.iter()
.filter(|s| s.starts_with("[") && s.ends_with("]"))
.map(|s| s.replace(&['[', ']'][..], ""))
.collect::<Vec<String>>()
.get(0)
.unwrap_or(&"".to_string())
.to_string();
let mod_index = if mode.is_empty() { 0 } else { 1 };
.get(0) {
Some(z) => Some(z.to_string()),
None => {
log::trace!("No mode specified");
None
}
};
let mod_index = if mode.is_some() { 1 } else { 0 };
let modifiers: Vec<Modifier> = tokens[mod_index..(tokens.len() - 1)]
.iter()

@ -1,10 +1,24 @@
use clap::{arg, App};
use evdev::{AttributeSet, Device, Key};
use rdev::{
Event,
EventType::{
KeyPress,
KeyRelease,
},
Key,
};
use nix::unistd::{Group, Uid};
use once_cell::sync::OnceCell;
use std::{
thread,
sync::Mutex,
sync::{
Mutex,
mpsc::{
sync_channel,
SyncSender,
Receiver
},
},
collections::HashMap,
env, fs,
io::prelude::*,
@ -26,8 +40,8 @@ pub struct LastHotkey {
ran_at: SystemTime,
}
static MODE_SOCK: &str = "/tmp/odilia-mode.sock";
static STATE_MODE: OnceCell<Mutex<String>> = OnceCell::new();
static MODE_SOCK: &str = "/tmp/odilia-mode.sock";
fn listen_for_mode_change() -> std::io::Result<()> {
log::trace!("Mode change listener started!");
@ -118,20 +132,6 @@ pub fn key_listener() {
exit(1);
}
log::trace!("Attempting to find all keyboard file descriptors.");
let mut keyboard_devices: Vec<Device> = Vec::new();
for (_, device) in evdev::enumerate().enumerate() {
if check_keyboard(&device) {
keyboard_devices.push(device);
}
}
if keyboard_devices.is_empty() {
log::error!("No valid keyboard device was detected!");
exit(1);
}
log::debug!("{} Keyboard device(s) detected.", keyboard_devices.len());
let hotkeys = match config::load(config_file_path) {
Err(e) => {
log::error!("Config Error: {}", e);
@ -145,34 +145,24 @@ pub fn key_listener() {
}
let modifiers_map: HashMap<Key, config::Modifier> = HashMap::from([
(Key::KEY_LEFTMETA, config::Modifier::Super),
(Key::KEY_RIGHTMETA, config::Modifier::Super),
(Key::KEY_LEFTMETA, config::Modifier::Super),
(Key::KEY_RIGHTMETA, config::Modifier::Super),
(Key::KEY_LEFTALT, config::Modifier::Alt),
(Key::KEY_RIGHTALT, config::Modifier::Alt),
(Key::KEY_LEFTCTRL, config::Modifier::Control),
(Key::KEY_RIGHTCTRL, config::Modifier::Control),
(Key::KEY_LEFTSHIFT, config::Modifier::Shift),
(Key::KEY_RIGHTSHIFT, config::Modifier::Shift),
(Key::MetaLeft, config::Modifier::Super),
(Key::MetaRight, config::Modifier::Super),
(Key::Alt, config::Modifier::Alt),
(Key::AltGr, config::Modifier::Alt),
(Key::ControlLeft, config::Modifier::Control),
(Key::ControlRight, config::Modifier::Control),
(Key::ShiftLeft, config::Modifier::Shift),
(Key::ShiftRight, config::Modifier::Shift),
]);
let repeat_cooldown_duration: u128;
if args.is_present("cooldown") {
repeat_cooldown_duration = args.value_of("cooldown").unwrap().parse::<u128>().unwrap();
} else {
repeat_cooldown_duration = 250;
}
let mut key_states: Vec<AttributeSet<Key>> = Vec::new();
let mut possible_hotkeys: Vec<config::Hotkey> = Vec::new();
let default_test_modifier: Vec<config::Modifier> = vec![config::Modifier::Super];
let mut last_hotkey = LastHotkey {
// just a dummy last_hotkey so I don't need to mess with Option<T>. TODO: Change this to Option<T>
hotkey: config::Hotkey::new(
"".to_string(),
evdev::Key::KEY_A,
Some("".to_string()),
Key::KeyA,
default_test_modifier,
String::from("notify-send \"it works\""),
false,
@ -181,97 +171,9 @@ pub fn key_listener() {
};
loop {
for device in &keyboard_devices {
key_states.push(device.get_key_state().unwrap());
}
// check if a hotkey in hotkeys is pressed
for state in &key_states {
for hotkey in &hotkeys {
if hotkey.modifiers.len() < state.iter().count() {
possible_hotkeys.push(hotkey.clone());
} else {
continue;
}
}
if possible_hotkeys.is_empty() {
continue;
}
let mut state_modifiers: Vec<config::Modifier> = Vec::new();
let mut state_keysyms: Vec<evdev::Key> = Vec::new();
let state_mode: String = match STATE_MODE.get() {
Some(mm) => {
match mm.lock() {
Ok(m) => m.to_string(),
Err(e) => {
log::error!("Could not lock state_mode within main event loop.");
"".to_string()
},
}
}
None => {
log::error!("Could not get STATE_MODE in main event loop.");
"".to_string()
}
};
for key in state.iter() {
if let Some(modifier) = modifiers_map.get(&key) {
state_modifiers.push(*modifier);
} else {
state_keysyms.push(key);
}
}
log::debug!("state_modifiers: {:#?}", state_modifiers);
log::debug!("state_keysyms: {:#?}", state_keysyms);
log::debug!("state_mode: {:#?}", state_mode);
log::debug!("hotkey: {:#?}", possible_hotkeys);
for hotkey in &possible_hotkeys {
// this should check if state_modifiers and hotkey.modifiers have the same elements
if state_modifiers.iter().all(|x| hotkey.modifiers.contains(x))
&& state_modifiers.len() == hotkey.modifiers.len()
&& state_keysyms.contains(&hotkey.keysym)
&& state_mode == hotkey.mode
{
if last_hotkey.hotkey == hotkey.clone() {
let time_since_ran_at =
match SystemTime::now().duration_since(last_hotkey.ran_at) {
Ok(n) => n.as_millis(),
Err(e) => {
log::error!("Error: {:#?}", e);
exit(1);
}
};
if time_since_ran_at <= repeat_cooldown_duration {
log::error!(
"In cooldown: {:#?} \nTime Remaining: {:#?}ms",
hotkey,
repeat_cooldown_duration - time_since_ran_at
);
continue;
} else {
last_hotkey =
LastHotkey { hotkey: hotkey.clone(), ran_at: SystemTime::now() };
}
} else {
last_hotkey =
LastHotkey { hotkey: hotkey.clone(), ran_at: SystemTime::now() };
}
log::info!("Hotkey pressed: {:#?}", hotkey);
if let Err(e) = sock_send(&hotkey.command) {
log::error!("Failed to send command over IPC.");
log::error!("Is swhks running?");
log::error!("{:#?}", e)
}
}
}
}
key_states.clear();
possible_hotkeys.clear();
sleep(Duration::from_millis(10)); // without this, swhkd will start to chew through your cpu.
// TODO
}
}
pub fn main() {
@ -279,6 +181,7 @@ pub fn main() {
let key_handler = thread::spawn(|| {
key_listener();
});
/*
let mode_updater = thread::spawn(|| {
let res = listen_for_mode_change();
match res {
@ -286,8 +189,9 @@ pub fn main() {
Err(e) => log::error!("Error setting up mode socket: {}", e),
}
});
*/
log::trace!("Threads set up");
mode_updater.join().unwrap();
//mode_updater.join().unwrap();
key_handler.join().unwrap();
}
@ -309,16 +213,6 @@ pub fn permission_check() {
}
}
pub fn check_keyboard(device: &Device) -> bool {
if device.supported_keys().map_or(false, |keys| keys.contains(Key::KEY_ENTER)) {
log::debug!("{} is a keyboard.", device.name().unwrap(),);
true
} else {
log::trace!("{} is not a keyboard.", device.name().unwrap(),);
false
}
}
pub fn set_flags() -> App<'static> {
let app = App::new("swhkd")
.version(env!("CARGO_PKG_VERSION"))

Loading…
Cancel
Save