Skip to content

Commit

Permalink
We now eat keybind keys, but causes a temp bug when grabbing
Browse files Browse the repository at this point in the history
  • Loading branch information
AethanFoot committed Mar 9, 2024
1 parent c2520e8 commit 00b41ed
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 26 deletions.
25 changes: 19 additions & 6 deletions lefthk-core/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
use thiserror::Error;

macro_rules! log_on_error {
macro_rules! r#return {
($a: expr) => {
match $a {
Ok(value) => value,
Err(err) => {
tracing::error!("{}", LeftError::from(err));
return;
}
}
};
}

macro_rules! log {
($a: expr) => {
match $a {
Ok(value) => value,
Expand All @@ -9,7 +21,7 @@ macro_rules! log_on_error {
};
}

macro_rules! exit_on_error {
macro_rules! exit {
($a: expr) => {
match $a {
Ok(value) => value,
Expand All @@ -21,8 +33,9 @@ macro_rules! exit_on_error {
};
}

pub(crate) use exit_on_error;
pub(crate) use log_on_error;
pub(crate) use exit;
pub(crate) use log;
pub(crate) use r#return;

pub type Result<T> = std::result::Result<T, LeftError>;
pub type Error = std::result::Result<(), LeftError>;
Expand All @@ -48,6 +61,6 @@ pub enum LeftError {
NoConfigFound,
#[error("No value set for execution.")]
ValueNotFound,
#[error("X failed status error.")]
XFailedStatus,
#[error("UInput device could not be found.")]
UInputNotFound,
}
49 changes: 38 additions & 11 deletions lefthk-core/src/evdev.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use evdev_rs::{Device, DeviceWrapper, InputEvent, ReadFlag, ReadStatus};
use evdev_rs::{Device, DeviceWrapper, InputEvent, ReadFlag, ReadStatus, UInputDevice};
use std::future::poll_fn;
use std::os::fd::AsRawFd;
use std::path::PathBuf;
Expand All @@ -9,12 +9,13 @@ use crate::errors::{self, LeftError};

#[derive(Debug)]
pub enum Task {
KeyboardEvent(InputEvent),
KeyboardEvent((PathBuf, InputEvent)),
KeyboardAdded(PathBuf),
KeyboardRemoved(PathBuf),
}

pub struct EvDev {
pub devices: HashMap<PathBuf, UInputDevice>,
pub task_receiver: mpsc::Receiver<Task>,
task_transmitter: mpsc::Sender<Task>,
task_guards: HashMap<PathBuf, oneshot::Receiver<()>>,
Expand All @@ -23,48 +24,55 @@ pub struct EvDev {

impl Default for EvDev {
fn default() -> Self {
let devices: HashMap<PathBuf, UInputDevice> = HashMap::new();

let (task_transmitter, task_receiver) = mpsc::channel(128);

let keyboard_watcher = KeyboardWatcher::new(task_transmitter.clone());

let task_guards: HashMap<PathBuf, oneshot::Receiver<()>> = HashMap::new();

let devices = find_keyboards();

let mut evdev = EvDev {
devices,
task_receiver,
task_transmitter,
task_guards,
_keyboard_watcher: keyboard_watcher,
};
match devices {

match find_keyboards() {
Some(devices) => {
for device in devices {
evdev.add_device(device);
}
}
None => tracing::warn!("No devices found on intialization."),
}

evdev
}
}

impl EvDev {
pub fn add_device(&mut self, path: PathBuf) {
tracing::info!("Adding device with path: {:?}", path);
if let Some(device) = device_with_path(path.clone()) {
if let Some(mut device) = device_with_path(path.clone()) {
device.set_name(&format!("LeftHK virtual input for {:?}", path));
let uinput = errors::r#return!(UInputDevice::create_from_device(&device));
errors::r#return!(device.grab(evdev_rs::GrabMode::Grab));

let (mut guard, task_guard) = oneshot::channel();
let transmitter = self.task_transmitter.clone();
const SERVER: mio::Token = mio::Token(0);
let fd = device.file().as_raw_fd();
let mut poll = errors::exit_on_error!(mio::Poll::new());
let mut poll = errors::exit!(mio::Poll::new());
let mut events = mio::Events::with_capacity(1);
errors::exit_on_error!(poll.registry().register(
errors::exit!(poll.registry().register(
&mut mio::unix::SourceFd(&fd),
SERVER,
mio::Interest::READABLE,
));

let p = path.clone();
tokio::task::spawn(async move {
while !guard.is_closed() {
if let Err(err) = poll.poll(&mut events, None) {
Expand All @@ -73,9 +81,12 @@ impl EvDev {
}

while device.has_event_pending() {
match device.next_event(ReadFlag::NORMAL | ReadFlag::BLOCKING) {
match device.next_event(ReadFlag::NORMAL) {
Ok((ReadStatus::Success, event)) => {
transmitter.send(Task::KeyboardEvent(event)).await.unwrap();
transmitter
.send(Task::KeyboardEvent((p.clone(), event)))
.await
.unwrap();
}
Err(_) => {
poll_fn(|cx| guard.poll_closed(cx)).await;
Expand All @@ -86,13 +97,17 @@ impl EvDev {
}
}
tracing::info!("Device loop has closed.");
errors::r#return!(device.grab(evdev_rs::GrabMode::Ungrab));
});

self.devices.insert(path.clone(), uinput);
self.task_guards.insert(path, task_guard);
}
}
pub fn remove_device(&mut self, path: PathBuf) {
tracing::info!("Removing device with path: {:?}", path);
self.task_guards.remove(&path);
self.devices.remove(&path);
}
}

Expand Down Expand Up @@ -160,6 +175,18 @@ impl KeyboardWatcher {

for e in socket.iter() {
let device = e.device();
// for property in device.properties() {
// tracing::info!("Property: {:?}, {:?}", property.name(), property.value());
// }
if device
.property_value("NAME")
.unwrap_or(OsStr::new(""))
.to_str()
.unwrap_or("")
.contains("LeftHK")
{
continue;
}
let is_keyboard = device
.property_value("ID_INPUT_KEYBOARD")
.unwrap_or(OsStr::new("0"))
Expand Down
50 changes: 41 additions & 9 deletions lefthk-core/src/worker/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
pub mod context;

use std::path::PathBuf;

use crate::child::Children;
use crate::config::{command, Keybind};
use crate::errors::{self, LeftError};
Expand Down Expand Up @@ -42,6 +44,8 @@ pub struct Worker {

keys_pressed: Vec<EV_KEY>,
mods_pressed: Vec<MOD_MASK>,
eaten_keys: Vec<EV_KEY>,
eaten_mods: Vec<MOD_MASK>,

pub evdev: EvDev,
pub children: Children,
Expand All @@ -59,6 +63,8 @@ impl Worker {
base_directory,
keys_pressed: Vec::new(),
mods_pressed: Vec::new(),
eaten_keys: Vec::new(),
eaten_mods: Vec::new(),
evdev: EvDev::default(),
children: Children::default(),
chord_ctx: context::Chord::new(),
Expand All @@ -78,8 +84,8 @@ impl Worker {
}
Some(task) = self.evdev.task_receiver.recv() => {
match task {
Task::KeyboardEvent(event) => {
self.handle_event(&event);
Task::KeyboardEvent((path, event)) => {
self.handle_event(path, &event);
}
Task::KeyboardAdded(path) => {
self.evdev.add_device(path);
Expand All @@ -90,7 +96,7 @@ impl Worker {
}
}
Some(command) = pipe.get_next_command() => {
errors::log_on_error!(command.execute(&mut self));
errors::log!(command.execute(&mut self));
}
};
}
Expand All @@ -100,21 +106,30 @@ impl Worker {

async fn get_pipe(&self) -> Pipe {
let pipe_name = Pipe::pipe_name();
let pipe_file = errors::exit_on_error!(self.base_directory.place_runtime_file(pipe_name));
errors::exit_on_error!(Pipe::new(pipe_file).await)
let pipe_file = errors::exit!(self.base_directory.place_runtime_file(pipe_name));
errors::exit!(Pipe::new(pipe_file).await)
}

fn handle_event(&mut self, event: &InputEvent) {
fn handle_event(&mut self, path: PathBuf, event: &InputEvent) {
let r#type = KeyEventType::from(event.value);
let mut eaten = false;
match r#type {
KeyEventType::Release => {
if let EventCode::EV_KEY(key) = event.event_code {
if is_modifier(&key) {
if let Ok(modifier) = key.try_into() {
self.mods_pressed.retain(|&m| m != modifier);
if self.eaten_mods.contains(&modifier) {
eaten = true;
self.eaten_mods.retain(|&m| m != modifier);
}
}
} else if let Some(index) = self.keys_pressed.iter().position(|&k| k == key) {
self.keys_pressed.remove(index);
if self.eaten_keys.contains(&key) {
eaten = true;
self.eaten_keys.retain(|&k| k != key);
}
}
}
}
Expand All @@ -136,16 +151,33 @@ impl Worker {
}
if new_key {
if let Some(keybind) = self.check_for_keybind() {
eaten = true;
self.keys_pressed
.iter()
.for_each(|&key| self.eaten_keys.push(key));
self.mods_pressed
.iter()
.for_each(|&key| self.eaten_mods.push(key));
if let Ok(command) = command::denormalize(&keybind.command) {
let _ = command.execute(self);
} else {
errors::log_on_error!(Err(LeftError::CommandNotFound));
errors::log!(Err(LeftError::CommandNotFound));
}
}
}
}
KeyEventType::Repeat => {}
KeyEventType::Unknown => {}
KeyEventType::Repeat | KeyEventType::Unknown => {}
}
if !eaten {
self.pass_event(path, event);
}
}

fn pass_event(&self, path: PathBuf, event: &InputEvent) {
// println!("Passing event: {:?}", event);
match self.evdev.devices.get(&path) {
Some(device) => errors::log!(device.write_event(event)),
None => errors::log!(Err(LeftError::UInputNotFound)),
}
}

Expand Down

0 comments on commit 00b41ed

Please sign in to comment.