diff --git a/src/config.rs b/src/config.rs index 77cad1c6..7357397e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -8,6 +8,8 @@ use std::{error::Error, fs}; use toml; use crate::client::Position; +use crate::scancode; +use crate::scancode::Linux::{KeyLeftAlt, KeyLeftCtrl, KeyLeftMeta, KeyLeftShift}; pub const DEFAULT_PORT: u16 = 4242; @@ -15,6 +17,7 @@ pub const DEFAULT_PORT: u16 = 4242; pub struct ConfigToml { pub port: Option, pub frontend: Option, + pub release_bind: Option>, pub left: Option, pub right: Option, pub top: Option, @@ -70,6 +73,7 @@ pub struct Config { pub port: u16, pub clients: Vec<(TomlClient, Position)>, pub daemon: bool, + pub release_bind: Vec, } pub struct ConfigClient { @@ -80,6 +84,9 @@ pub struct ConfigClient { pub active: bool, } +const DEFAULT_RELEASE_KEYS: [scancode::Linux; 4] = + [KeyLeftCtrl, KeyLeftShift, KeyLeftMeta, KeyLeftAlt]; + impl Config { pub fn new() -> Result { let args = CliArgs::parse(); @@ -138,6 +145,13 @@ impl Config { }, }; + log::debug!("{config_toml:?}"); + let release_bind = config_toml + .as_ref() + .map(|c| c.release_bind.clone()) + .flatten() + .unwrap_or(Vec::from_iter(DEFAULT_RELEASE_KEYS.iter().cloned())); + let mut clients: Vec<(TomlClient, Position)> = vec![]; if let Some(config_toml) = config_toml { @@ -162,6 +176,7 @@ impl Config { frontend, clients, port, + release_bind, }) } diff --git a/src/main.rs b/src/main.rs index 95052c6e..2cfc7e78 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,6 +29,7 @@ pub fn run() -> Result<()> { // parse config file + cli args let config = Config::new()?; log::debug!("{config:?}"); + log::info!("release bind: {:?}", config.release_bind); if config.daemon { // if daemon is specified we run the service diff --git a/src/scancode.rs b/src/scancode.rs index 6c868edf..254fa8d8 100644 --- a/src/scancode.rs +++ b/src/scancode.rs @@ -1,3 +1,5 @@ +use serde::{Deserialize, Serialize}; + /* * https://learn.microsoft.com/en-us/windows/win32/inputdev/about-keyboard-input */ @@ -165,7 +167,7 @@ pub enum Windows { * https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h */ #[repr(u32)] -#[derive(Debug, Clone, Copy)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, Hash, PartialEq)] #[allow(dead_code)] pub enum Linux { KeyReserved = 0, @@ -210,7 +212,7 @@ pub enum Linux { KeySemicolon = 39, KeyApostrophe = 40, KeyGrave = 41, - KeyLeftshift = 42, + KeyLeftShift = 42, KeyBackslash = 43, KeyZ = 44, KeyX = 45, @@ -224,7 +226,7 @@ pub enum Linux { KeySlash = 53, KeyRightShift = 54, KeyKpAsterisk = 55, - KeyLeftalt = 56, + KeyLeftAlt = 56, KeySpace = 57, KeyCapsLock = 58, KeyF1 = 59, @@ -294,7 +296,7 @@ pub enum Linux { // KEY_HANGUEL = KeyHangeul, KeyHanja = 123, KeyYen = 124, - KeyLeftmeta = 125, + KeyLeftMeta = 125, KeyRightmeta = 126, KeyCompose = 127, KeyStop = 128, /* AC Stop */ @@ -485,7 +487,7 @@ impl TryFrom for Windows { Linux::KeySemicolon => Ok(Self::KeySemiColon), Linux::KeyApostrophe => Ok(Self::KeyApostrophe), Linux::KeyGrave => Ok(Self::KeyGrave), - Linux::KeyLeftshift => Ok(Self::KeyLeftShift), + Linux::KeyLeftShift => Ok(Self::KeyLeftShift), Linux::KeyBackslash => Ok(Self::KeyBackslash), Linux::KeyZ => Ok(Self::KeyZ), Linux::KeyX => Ok(Self::KeyX), @@ -499,7 +501,7 @@ impl TryFrom for Windows { Linux::KeySlash => Ok(Self::KeySlash), Linux::KeyRightShift => Ok(Self::KeyRightShift), Linux::KeyKpAsterisk => Ok(Self::KeypadStar), - Linux::KeyLeftalt => Ok(Self::KeyLeftAlt), + Linux::KeyLeftAlt => Ok(Self::KeyLeftAlt), Linux::KeySpace => Ok(Self::KeySpace), Linux::KeyCapsLock => Ok(Self::KeyCapsLock), Linux::KeyF1 => Ok(Self::KeyF1), @@ -567,7 +569,7 @@ impl TryFrom for Windows { Linux::KeyHangeul => Ok(Self::KeyInternational1), // TODO unsure Linux::KeyHanja => Ok(Self::KeyInternational2), // TODO unsure Linux::KeyYen => Ok(Self::KeyInternational3), // TODO unsure - Linux::KeyLeftmeta => Ok(Self::KeyLeftGUI), + Linux::KeyLeftMeta => Ok(Self::KeyLeftGUI), Linux::KeyRightmeta => Ok(Self::KeyRightGUI), Linux::KeyCompose => Ok(Self::KeyApplication), Linux::KeyStop => Ok(Self::ACStop), diff --git a/src/server.rs b/src/server.rs index d12fa8a6..8c2c0e13 100644 --- a/src/server.rs +++ b/src/server.rs @@ -40,6 +40,7 @@ pub struct Server { client_manager: Rc>, port: Rc>, state: Rc>, + release_bind: Vec, } impl Server { @@ -57,11 +58,13 @@ impl Server { config_client.active, ); } + let release_bind = config.release_bind.clone(); Self { active_client, client_manager, port, state, + release_bind, } } @@ -86,7 +89,7 @@ impl Server { // event producer let (mut producer_task, producer_channel) = - producer_task::new(producer, self.clone(), sender_tx.clone(), timer_tx.clone()); + producer_task::new(producer, self.clone(), sender_tx.clone(), timer_tx.clone(), self.release_bind.clone()); // event consumer let (mut consumer_task, consumer_channel) = consumer_task::new( diff --git a/src/server/producer_task.rs b/src/server/producer_task.rs index 76b2f84c..1fb49b82 100644 --- a/src/server/producer_task.rs +++ b/src/server/producer_task.rs @@ -1,6 +1,6 @@ use anyhow::{anyhow, Result}; use futures::StreamExt; -use std::net::SocketAddr; +use std::{collections::HashSet, net::SocketAddr}; use tokio::{sync::mpsc::Sender, task::JoinHandle}; @@ -8,6 +8,7 @@ use crate::{ client::{ClientEvent, ClientHandle}, event::{Event, KeyboardEvent}, producer::EventProducer, + scancode, server::State, }; @@ -28,14 +29,16 @@ pub fn new( server: Server, sender_tx: Sender<(Event, SocketAddr)>, timer_tx: Sender<()>, + release_bind: Vec, ) -> (JoinHandle>, Sender) { let (tx, mut rx) = tokio::sync::mpsc::channel(32); let task = tokio::task::spawn_local(async move { + let mut pressed_keys = HashSet::new(); loop { tokio::select! { event = producer.next() => { let event = event.ok_or(anyhow!("event producer closed"))??; - handle_producer_event(&server, &mut producer, &sender_tx, &timer_tx, event).await?; + handle_producer_event(&server, &mut producer, &sender_tx, &timer_tx, event, &mut pressed_keys, &release_bind).await?; } e = rx.recv() => { log::debug!("producer notify rx: {e:?}"); @@ -59,7 +62,15 @@ pub fn new( (task, tx) } -const RELEASE_MODIFIERDS: u32 = 77; // ctrl+shift+super+alt +fn update_pressed_keys(pressed_keys: &mut HashSet, key: u32, state: u8) { + if let Ok(scancode) = scancode::Linux::try_from(key) { + log::debug!("key: {key}, state: {state}, scancode: {scancode:?}"); + match state { + 1 => pressed_keys.insert(scancode), + _ => pressed_keys.remove(&scancode), + }; + } +} async fn handle_producer_event( server: &Server, @@ -67,12 +78,18 @@ async fn handle_producer_event( sender_tx: &Sender<(Event, SocketAddr)>, timer_tx: &Sender<()>, event: (ClientHandle, Event), + pressed_keys: &mut HashSet, + release_bind: &[scancode::Linux], ) -> Result<()> { let (c, mut e) = event; log::trace!("({c}) {e:?}"); - if let Event::Keyboard(KeyboardEvent::Modifiers { mods_depressed, .. }) = e { - if mods_depressed == RELEASE_MODIFIERDS { + if let Event::Keyboard(KeyboardEvent::Key { key, state, .. }) = e { + update_pressed_keys(pressed_keys, key, state); + log::debug!("{pressed_keys:?}"); + if release_bind.iter().all(|k| pressed_keys.contains(k)) { + pressed_keys.clear(); + log::info!("releasing pointer"); producer.release()?; server.state.replace(State::Receiving); log::trace!("STATE ===> Receiving");