diff --git a/examples/a_to_b.py b/examples/a_to_b.py index 30d192b..6c8e885 100644 --- a/examples/a_to_b.py +++ b/examples/a_to_b.py @@ -6,4 +6,4 @@ map2.link([reader, mapper, writer]) -mapper.map("a", "b") \ No newline at end of file +mapper.map("a", "b") diff --git a/examples/hello_world.py b/examples/hello_world.py index a2b7e80..bb38ffa 100644 --- a/examples/hello_world.py +++ b/examples/hello_world.py @@ -14,4 +14,4 @@ reader.send("Hello world!") # keep running for 1sec so the event can be processed -time.sleep(1) \ No newline at end of file +time.sleep(1) diff --git a/examples/tests/_setup_integration_tests/setup_integration_tests.rs b/examples/tests/_setup_integration_tests/setup_integration_tests.rs index bf01d12..287b6b0 100644 --- a/examples/tests/_setup_integration_tests/setup_integration_tests.rs +++ b/examples/tests/_setup_integration_tests/setup_integration_tests.rs @@ -1,7 +1,7 @@ use std::io::Write; -use map2::*; use map2::python::*; +use map2::*; #[pyo3_asyncio::tokio::main] async fn main() -> pyo3::PyResult<()> { @@ -10,7 +10,8 @@ async fn main() -> pyo3::PyResult<()> { // .arg("--") // .arg("--cfg").arg("test") // .arg("--cfg").arg("integration") - .arg("--features").arg("integration") + .arg("--features") + .arg("integration") .output()?; if !cmd.status.success() { @@ -29,8 +30,11 @@ mod integration_tests { pub fn writer_read(py: Python, module: &PyModule, name: &str) -> Option { let target = module.getattr(name).unwrap().to_object(py); - target.call_method0(py, "__test__read_ev").unwrap() - .extract::>(py).unwrap() + target + .call_method0(py, "__test__read_ev") + .unwrap() + .extract::>(py) + .unwrap() .and_then(|x| serde_json::from_str(&x).unwrap()) } @@ -46,7 +50,9 @@ pub fn reader_send(py: Python, module: &PyModule, name: &str, ev: &EvdevInputEve let target = module.getattr(name).unwrap().to_object(py); let ev = serde_json::to_string(ev).unwrap(); - target.call_method(py, "__test__write_ev", (ev, ), None).unwrap(); + target + .call_method(py, "__test__write_ev", (ev,), None) + .unwrap(); } pub fn reader_send_all(py: Python, module: &PyModule, name: &str, ev_list: &Vec) { @@ -54,10 +60,14 @@ pub fn reader_send_all(py: Python, module: &PyModule, name: &str, ev_list: &Vec< for ev in ev_list.iter() { let ev = serde_json::to_string(ev).unwrap(); - target.call_method(py, "__test__write_ev", (ev, ), None).unwrap(); + target + .call_method(py, "__test__write_ev", (ev,), None) + .unwrap(); } } pub fn keys(input: &str) -> Vec { - parse_key_sequence(input, Some(&Default::default())).unwrap().to_input_ev() -} \ No newline at end of file + parse_key_sequence(input, Some(&Default::default())) + .unwrap() + .to_input_ev() +} diff --git a/src/key_defs.rs b/src/key_defs.rs index 5ffd925..d48cecb 100644 --- a/src/key_defs.rs +++ b/src/key_defs.rs @@ -1,11 +1,18 @@ -use evdev_rs::enums::{EV_SYN, EventCode}; +use evdev_rs::enums::{EventCode, EV_SYN}; use evdev_rs::TimeVal; use crate::*; -pub const INPUT_EV_DUMMY_TIME: TimeVal = TimeVal { tv_sec: 0, tv_usec: 0 }; +pub const INPUT_EV_DUMMY_TIME: TimeVal = TimeVal { + tv_sec: 0, + tv_usec: 0, +}; -pub static SYN_REPORT: EvdevInputEvent = EvdevInputEvent { event_code: EventCode::EV_SYN(EV_SYN::SYN_REPORT), value: 0, time: INPUT_EV_DUMMY_TIME }; +pub static SYN_REPORT: EvdevInputEvent = EvdevInputEvent { + event_code: EventCode::EV_SYN(EV_SYN::SYN_REPORT), + value: 0, + time: INPUT_EV_DUMMY_TIME, +}; pub static ALL_KEYS: &'static [evdev_rs::enums::EV_KEY] = &[ KEY_RESERVED, @@ -691,19 +698,31 @@ lazy_static! { m.insert("KEYPAD_9", (KEY_KP9.into(), KeyModifierFlags::new())); m.insert("LEFT_ALT", (KEY_LEFTALT.into(), KeyModifierFlags::new())); m.insert("LEFT_CTRL", (KEY_RIGHTCTRL.into(), KeyModifierFlags::new())); - m.insert("LEFT_SHIFT", (KEY_LEFTSHIFT.into(), KeyModifierFlags::new())); + m.insert( + "LEFT_SHIFT", + (KEY_LEFTSHIFT.into(), KeyModifierFlags::new()), + ); m.insert("META", (KEY_LEFTMETA.into(), KeyModifierFlags::new())); m.insert("PAGE_DOWN", (KEY_PAGEDOWN.into(), KeyModifierFlags::new())); m.insert("PAGE_UP", (KEY_PAGEUP.into(), KeyModifierFlags::new())); m.insert("RIGHT_ALT", (KEY_RIGHTALT.into(), KeyModifierFlags::new())); - m.insert("RIGHT_BRACE", (KEY_RIGHTBRACE.into(), KeyModifierFlags::new())); - m.insert("LEFT_BRACE", (KEY_LEFTBRACE.into(), KeyModifierFlags::new())); - m.insert("RIGHT_CTRL", (KEY_RIGHTCTRL.into(), KeyModifierFlags::new())); - m.insert("RIGHT_SHIFT", (KEY_RIGHTSHIFT.into(), KeyModifierFlags::new())); + m.insert( + "RIGHT_BRACE", + (KEY_RIGHTBRACE.into(), KeyModifierFlags::new()), + ); + m.insert( + "LEFT_BRACE", + (KEY_LEFTBRACE.into(), KeyModifierFlags::new()), + ); + m.insert( + "RIGHT_CTRL", + (KEY_RIGHTCTRL.into(), KeyModifierFlags::new()), + ); + m.insert( + "RIGHT_SHIFT", + (KEY_RIGHTSHIFT.into(), KeyModifierFlags::new()), + ); m.insert("SHIFT", (KEY_LEFTSHIFT.into(), KeyModifierFlags::new())); m }; } - - - diff --git a/src/lib.rs b/src/lib.rs index 8778d61..2365dfe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,6 @@ #![feature(fn_traits)] #![feature(type_alias_impl_trait)] - #![recursion_limit = "256"] - #![allow(warnings)] extern crate core; @@ -10,19 +8,19 @@ extern crate core; extern crate lazy_static; extern crate regex; -use std::{fs, io}; use std::borrow::BorrowMut; +use std::{fs, io}; // #[macro_use] // use subscriber::linkable; use std::hash::{DefaultHasher, Hash, Hasher}; use std::ops::{Deref, DerefMut}; -use std::sync::{Arc, mpsc, Mutex, RwLock, Weak}; +use std::sync::{mpsc, Arc, Mutex, RwLock, Weak}; use std::thread; use std::time::Duration; +pub use evdev_rs::enums::EV_ABS::*; pub use evdev_rs::enums::EV_KEY::*; pub use evdev_rs::enums::EV_REL::*; -pub use evdev_rs::enums::EV_ABS::*; pub use key_primitives::Key; pub use parsing::*; @@ -48,32 +46,31 @@ pub use crate::key_defs::*; use crate::key_primitives::*; use crate::state::*; -pub mod key_defs; -pub mod state; -pub mod key_primitives; -pub mod parsing; +pub mod capabilities; pub mod device; -pub mod event_handlers; -pub mod logging; -pub mod event_loop; -pub mod event; -pub mod subscriber; pub mod encoding; -pub mod xkb; -pub mod xkb_transformer_registry; pub mod error; +pub mod event; +pub mod event_handlers; +pub mod event_loop; pub mod global; +pub mod key_defs; +pub mod key_primitives; +pub mod logging; +pub mod parsing; pub mod platform; +pub mod state; +pub mod subscriber; pub mod subscriber_map; -pub mod capabilities; +pub mod xkb; +pub mod xkb_transformer_registry; #[cfg(feature = "integration")] pub mod testing; - +pub mod mapper; pub mod python; pub mod reader; -pub mod mapper; -pub mod writer; pub mod virtual_writer; -pub mod window; \ No newline at end of file +pub mod window; +pub mod writer; diff --git a/src/mapper/mapper.rs b/src/mapper/mapper.rs index acdc88e..aa02010 100644 --- a/src/mapper/mapper.rs +++ b/src/mapper/mapper.rs @@ -1,18 +1,17 @@ -use crate::*; use crate::event_loop::{args_to_py, PythonArgument}; -use crate::mapper::{RuntimeAction, RuntimeKeyAction}; use crate::mapper::mapping_functions::*; +use crate::mapper::{RuntimeAction, RuntimeKeyAction}; use crate::python::*; use crate::subscriber::{SubscribeEvent, Subscriber}; use crate::xkb::XKBTransformer; use crate::xkb_transformer_registry::{TransformerParams, XKB_TRANSFORMER_REGISTRY}; +use crate::*; #[derive(Debug)] pub enum ControlMessage { AddMapping(KeyActionWithMods, RuntimeAction), } - #[derive(Debug, Clone)] enum PythonReturn { String(String), @@ -27,11 +26,12 @@ fn run_python_handler( subscriber: Option<&(u64, Subscriber)>, ) { let ret = Python::with_gil(|py| -> Result<()> { - let asyncio = py.import("asyncio") + let asyncio = py + .import("asyncio") .expect("python runtime error: failed to import 'asyncio', is it installed?"); let is_async_callback: bool = asyncio - .call_method1("iscoroutinefunction", (handler.as_ref(py), )) + .call_method1("iscoroutinefunction", (handler.as_ref(py),)) .expect("python runtime error: 'iscoroutinefunction' lookup failed") .extract() .expect("python runtime error: 'iscoroutinefunction' call failed"); @@ -41,10 +41,13 @@ fn run_python_handler( Ok(()) } else { let args = args_to_py(py, args.unwrap_or(vec![])); - let ret = handler.call(py, args, None) + let ret = handler + .call(py, args, None) .map_err(|err| anyhow!("{}", err)) .and_then(|ret| { - if ret.is_none(py) { return Ok(None); } + if ret.is_none(py) { + return Ok(None); + } if let Ok(ret) = ret.extract::(py) { return Ok(Some(PythonReturn::String(ret))); @@ -62,7 +65,8 @@ fn run_python_handler( if let Some((path_hash, subscriber)) = subscriber { for action in seq.to_key_actions() { - let _ = subscriber.send((*path_hash, InputEvent::Raw(action.to_input_ev()))); + let _ = subscriber + .send((*path_hash, InputEvent::Raw(action.to_input_ev()))); } } } @@ -83,7 +87,6 @@ fn run_python_handler( } } - #[derive(Default)] struct Inner { id: Arc, @@ -103,11 +106,17 @@ impl Inner { let subscriber_map = self.subscriber_map.read().unwrap(); let subscriber = subscriber_map.get(&path_hash); - let ev = match &raw_ev { InputEvent::Raw(ev) => ev }; + let ev = match &raw_ev { + InputEvent::Raw(ev) => ev, + }; match ev { // key event - EvdevInputEvent { event_code: EventCode::EV_KEY(key), value, .. } => { + EvdevInputEvent { + event_code: EventCode::EV_KEY(key), + value, + .. + } => { let mut from_modifiers = KeyModifierFlags::new(); from_modifiers.ctrl = state.modifiers.is_ctrl(); from_modifiers.alt = state.modifiers.is_alt(); @@ -116,7 +125,9 @@ impl Inner { from_modifiers.meta = state.modifiers.is_meta(); let from_key_action = KeyActionWithMods { - key: Key { event_code: ev.event_code }, + key: Key { + event_code: ev.event_code, + }, value: ev.value, modifiers: from_modifiers, }; @@ -126,7 +137,9 @@ impl Inner { RuntimeAction::ActionSequence(seq) => { let (path_hash, subscriber) = match subscriber { Some(x) => x, - None => { return; } + None => { + return; + } }; for action in seq { @@ -136,11 +149,21 @@ impl Inner { let _ = subscriber.send((*path_hash, InputEvent::Raw(ev))); } - RuntimeKeyAction::ReleaseRestoreModifiers(from_flags, to_flags, to_type) => { - let new_events = release_restore_modifiers(&state.modifiers, from_flags, to_flags, to_type); + RuntimeKeyAction::ReleaseRestoreModifiers( + from_flags, + to_flags, + to_type, + ) => { + let new_events = release_restore_modifiers( + &state.modifiers, + from_flags, + to_flags, + to_type, + ); // events.append(&mut new_events); for ev in new_events { - let _ = subscriber.send((*path_hash, InputEvent::Raw(ev))); + let _ = + subscriber.send((*path_hash, InputEvent::Raw(ev))); } } } @@ -149,19 +172,18 @@ impl Inner { RuntimeAction::PythonCallback(from_modifiers, handler) => { if let Some((path_hash, subscriber)) = subscriber { // always release all trigger mods before running the callback - let new_events = release_restore_modifiers(&state.modifiers, from_modifiers, &KeyModifierFlags::new(), &TYPE_UP); + let new_events = release_restore_modifiers( + &state.modifiers, + from_modifiers, + &KeyModifierFlags::new(), + &TYPE_UP, + ); for ev in new_events { let _ = subscriber.send((*path_hash, InputEvent::Raw(ev))); } } - run_python_handler( - &handler, - None, - ev, - &self.transformer, - subscriber, - ); + run_python_handler(&handler, None, ev, &self.transformer, subscriber); } RuntimeAction::NOP => {} } @@ -169,12 +191,17 @@ impl Inner { return; } - let was_modifier = event_handlers::update_modifiers(&mut state.modifiers, &KeyAction::from_input_ev(&ev)); + let was_modifier = event_handlers::update_modifiers( + &mut state.modifiers, + &KeyAction::from_input_ev(&ev), + ); // don't trigger the fallback handler with modifier keys if !was_modifier { if let Some(handler) = self.fallback_handler.read().unwrap().as_ref() { - let name = self.transformer.raw_to_utf(key, &*state.modifiers) + let name = self + .transformer + .raw_to_utf(key, &*state.modifiers) .unwrap_or_else(|| format!("{key:?}").to_string()); let value = match *value { @@ -182,49 +209,41 @@ impl Inner { 1 => "down", 2 => "repeat", _ => unreachable!(), - }.to_string(); + } + .to_string(); - let args = vec![ - PythonArgument::String(name), - PythonArgument::String(value), - ]; + let args = + vec![PythonArgument::String(name), PythonArgument::String(value)]; - run_python_handler( - &handler, - Some(args), - ev, - &self.transformer, - subscriber, - ); + run_python_handler(&handler, Some(args), ev, &self.transformer, subscriber); return; } } } // rel/abs event - EvdevInputEvent { event_code, value, .. } - if matches!(event_code, EventCode::EV_REL(..)) || matches!(event_code, EventCode::EV_ABS(..)) - => { + EvdevInputEvent { + event_code, value, .. + } if matches!(event_code, EventCode::EV_REL(..)) + || matches!(event_code, EventCode::EV_ABS(..)) => + { let (key, handler) = match event_code { - EventCode::EV_REL(key) => (format!("{key:?}").to_string(), self.relative_handler.read().unwrap()), - EventCode::EV_ABS(key) => (format!("{key:?}").to_string(), self.absolute_handler.read().unwrap()), - _ => unreachable!() + EventCode::EV_REL(key) => ( + format!("{key:?}").to_string(), + self.relative_handler.read().unwrap(), + ), + EventCode::EV_ABS(key) => ( + format!("{key:?}").to_string(), + self.absolute_handler.read().unwrap(), + ), + _ => unreachable!(), }; if let Some(handler) = handler.as_ref() { let name = format!("{key:?}"); // remove prefix REL_ / ABS_ let name = name[4..name.len()].to_string(); - let args = vec![ - PythonArgument::String(name), - PythonArgument::Number(*value), - ]; - run_python_handler( - &handler, - Some(args), - ev, - &self.transformer, - subscriber, - ); + let args = vec![PythonArgument::String(name), PythonArgument::Number(*value)]; + run_python_handler(&handler, Some(args), ev, &self.transformer, subscriber); return; } } @@ -237,7 +256,6 @@ impl Inner { } } - #[pyclass] pub struct Mapper { pub id: Arc, @@ -254,7 +272,7 @@ impl Mapper { pub fn new(kwargs: Option<&PyDict>) -> PyResult { let options: HashMap<&str, &PyAny> = match kwargs { Some(py_dict) => py_dict.extract().unwrap(), - None => HashMap::new() + None => HashMap::new(), }; let kbd_model = options.get("model").and_then(|x| x.extract().ok()); @@ -262,7 +280,12 @@ impl Mapper { let kbd_variant = options.get("variant").and_then(|x| x.extract().ok()); let kbd_options = options.get("options").and_then(|x| x.extract().ok()); let transformer = XKB_TRANSFORMER_REGISTRY - .get(&TransformerParams::new(kbd_model, kbd_layout, kbd_variant, kbd_options)) + .get(&TransformerParams::new( + kbd_model, + kbd_layout, + kbd_variant, + kbd_options, + )) .map_err(err_to_py)?; let subscriber_map: Arc> = Arc::new(RwLock::new(HashMap::new())); @@ -297,20 +320,21 @@ impl Mapper { }) } - pub fn map(&mut self, py: Python, from: String, to: PyObject) -> PyResult<()> { - let from = parse_key_action_with_mods(&from, Some(&self.transformer)) - .map_err(|err| PyRuntimeError::new_err(format!( + let from = parse_key_action_with_mods(&from, Some(&self.transformer)).map_err(|err| { + PyRuntimeError::new_err(format!( "mapping error on the 'from' side:\n{}", ApplicationError::KeyParse(err.to_string()), - )))?; + )) + })?; if let Ok(to) = to.extract::(py) { - let to = parse_key_sequence(&to, Some(&self.transformer)) - .map_err(|err| PyRuntimeError::new_err(format!( + let to = parse_key_sequence(&to, Some(&self.transformer)).map_err(|err| { + PyRuntimeError::new_err(format!( "mapping error on the 'to' side:\n{}", ApplicationError::KeySequenceParse(err.to_string()), - )))?; + )) + })?; self._map_key(from, to)?; return Ok(()); @@ -327,17 +351,19 @@ impl Mapper { } pub fn map_key(&mut self, from: String, to: String) -> PyResult<()> { - let from = parse_key_action_with_mods(&from, Some(&self.transformer)) - .map_err(|err| PyRuntimeError::new_err(format!( + let from = parse_key_action_with_mods(&from, Some(&self.transformer)).map_err(|err| { + PyRuntimeError::new_err(format!( "mapping error on the 'from' side:\n{}", ApplicationError::KeyParse(err.to_string()), - )))?; + )) + })?; - let to = parse_key_action_with_mods(&to, Some(&self.transformer)) - .map_err(|err| PyRuntimeError::new_err(format!( + let to = parse_key_action_with_mods(&to, Some(&self.transformer)).map_err(|err| { + PyRuntimeError::new_err(format!( "mapping error on the 'to' side:\n{}", ApplicationError::KeyParse(err.to_string()), - )))?; + )) + })?; self._map_key(from, vec![to])?; Ok(()) @@ -368,20 +394,29 @@ impl Mapper { } pub fn nop(&mut self, from: String) -> PyResult<()> { - let from = parse_key_action_with_mods(&from, Some(&self.transformer)) - .map_err(|err| PyRuntimeError::new_err(format!( + let from = parse_key_action_with_mods(&from, Some(&self.transformer)).map_err(|err| { + PyRuntimeError::new_err(format!( "mapping error on the 'from' side:\n{}", ApplicationError::KeyParse(err.to_string()), - )))?; + )) + })?; match from { ParsedKeyAction::KeyAction(from) => { - self.inner.mappings.write().unwrap().insert(from, RuntimeAction::NOP); + self.inner + .mappings + .write() + .unwrap() + .insert(from, RuntimeAction::NOP); } ParsedKeyAction::KeyClickAction(from) => { for value in 0..=2 { let from = KeyActionWithMods::new(from.key, value, from.modifiers); - self.inner.mappings.write().unwrap().insert(from, RuntimeAction::NOP); + self.inner + .mappings + .write() + .unwrap() + .insert(from, RuntimeAction::NOP); } } ParsedKeyAction::Action(_) => { @@ -392,7 +427,10 @@ impl Mapper { Ok(()) } - pub fn snapshot(&self, existing: Option<&KeyMapperSnapshot>) -> PyResult> { + pub fn snapshot( + &self, + existing: Option<&KeyMapperSnapshot>, + ) -> PyResult> { if let Some(existing) = existing { *self.inner.mappings.write().unwrap() = existing.mappings.clone(); *self.inner.fallback_handler.write().unwrap() = existing.fallback_handler.clone(); @@ -416,7 +454,9 @@ impl Mapper { let target = match add_event_subscription(target) { Some(target) => target, - None => { return Err(ApplicationError::InvalidLinkTarget.into()); } + None => { + return Err(ApplicationError::InvalidLinkTarget.into()); + } }; let mut h = DefaultHasher::new(); @@ -428,7 +468,10 @@ impl Mapper { path.hash(&mut h); let next_path_hash = h.finish(); - self.subscriber_map.write().unwrap().insert(path_hash, (next_path_hash, target)); + self.subscriber_map + .write() + .unwrap() + .insert(path_hash, (next_path_hash, target)); Ok(()) } @@ -439,21 +482,27 @@ impl Mapper { fn _map_callback(&mut self, from: ParsedKeyAction, to: PyObject) -> PyResult<()> { match from { ParsedKeyAction::KeyAction(from) => { - self.inner.mappings.write().unwrap().insert(from, RuntimeAction::PythonCallback(from.modifiers, to)); + self.inner + .mappings + .write() + .unwrap() + .insert(from, RuntimeAction::PythonCallback(from.modifiers, to)); } ParsedKeyAction::KeyClickAction(from) => { self.inner.mappings.write().unwrap().insert( from.to_key_action(1), RuntimeAction::PythonCallback(from.modifiers, to), ); - self.inner.mappings.write().unwrap().insert( - from.to_key_action(0), - RuntimeAction::NOP, - ); - self.inner.mappings.write().unwrap().insert( - from.to_key_action(2), - RuntimeAction::NOP, - ); + self.inner + .mappings + .write() + .unwrap() + .insert(from.to_key_action(0), RuntimeAction::NOP); + self.inner + .mappings + .write() + .unwrap() + .insert(from.to_key_action(2), RuntimeAction::NOP); } ParsedKeyAction::Action(_) => { return Err(ApplicationError::NonButton.into()); @@ -472,17 +521,32 @@ impl Mapper { // key action to click ParsedKeyAction::KeyClickAction(to) => { let mapping = map_action_to_click(&from, &to); - self.inner.mappings.write().unwrap().insert(mapping.0, mapping.1); + self.inner + .mappings + .write() + .unwrap() + .insert(mapping.0, mapping.1); } // key action to key action ParsedKeyAction::KeyAction(to) => { let mapping = map_action_to_action(&from, &to); - self.inner.mappings.write().unwrap().insert(mapping.0, mapping.1); + self.inner + .mappings + .write() + .unwrap() + .insert(mapping.0, mapping.1); } // key action to action ParsedKeyAction::Action(to) => { - let mapping = map_action_to_action(&from, &to.to_key_action_with_mods(Default::default())); - self.inner.mappings.write().unwrap().insert(mapping.0, mapping.1); + let mapping = map_action_to_action( + &from, + &to.to_key_action_with_mods(Default::default()), + ); + self.inner + .mappings + .write() + .unwrap() + .insert(mapping.0, mapping.1); } } return Ok(()); @@ -490,7 +554,11 @@ impl Mapper { // action to seq let mapping = map_action_to_seq(from, to); - self.inner.mappings.write().unwrap().insert(mapping.0, mapping.1); + self.inner + .mappings + .write() + .unwrap() + .insert(mapping.0, mapping.1); } ParsedKeyAction::KeyClickAction(from) => { if to.len() == 1 { @@ -537,11 +605,10 @@ impl Mapper { } } - #[pyclass] pub struct KeyMapperSnapshot { mappings: Mappings, fallback_handler: Option, relative_handler: Option, absolute_handler: Option, -} \ No newline at end of file +} diff --git a/src/parsing/error.rs b/src/parsing/error.rs index 101a375..f2bb928 100644 --- a/src/parsing/error.rs +++ b/src/parsing/error.rs @@ -8,27 +8,41 @@ use super::*; pub type ParseResult = IResult>; pub fn make_generic_nom_err_new(input: I) -> NomErr> { - NomErr::Error(CustomError { input, expected: vec![] }) + NomErr::Error(CustomError { + input, + expected: vec![], + }) } pub fn make_generic_nom_err_options(input: I, options: Vec) -> NomErr> { - NomErr::Error(CustomError { input, expected: options }) + NomErr::Error(CustomError { + input, + expected: options, + }) } - #[derive(Debug, PartialEq)] pub struct CustomError { pub input: I, pub expected: Vec, } -impl ParseError for CustomError where I: InputLength { +impl ParseError for CustomError +where + I: InputLength, +{ fn from_error_kind(input: I, _: ErrorKind) -> Self { - CustomError { input, expected: vec![] } + CustomError { + input, + expected: vec![], + } } fn from_char(input: I, ch: char) -> Self { - CustomError { input, expected: vec![ch.to_string()] } + CustomError { + input, + expected: vec![ch.to_string()], + } } fn or(mut self, mut other: Self) -> Self { @@ -41,23 +55,29 @@ impl ParseError for CustomError where I: InputLength { other } - fn append(_: I, _: ErrorKind, other: Self) -> Self { other } + fn append(_: I, _: ErrorKind, other: Self) -> Self { + other + } } impl FromExternalError for CustomError { fn from_external_error(input: I, _: ErrorKind, _: E) -> Self { - Self { input, expected: vec![] } + Self { + input, + expected: vec![], + } } } - pub trait FromTagError: Sized { fn from_tag(input: I, tag: String) -> Self; } impl FromTagError for CustomError { fn from_tag(input: Input, tag: String) -> Self { - Self { input, expected: vec![format!("'{}'", tag)] } + Self { + input, + expected: vec![format!("'{}'", tag)], + } } } - diff --git a/src/reader.rs b/src/reader.rs index 42bd2a2..ecf0613 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -1,13 +1,12 @@ -use std::hash::{Hash, Hasher}; use ::oneshot; +use std::hash::{Hash, Hasher}; -use crate::*; -use crate::python::*; use crate::event::InputEvent; -use crate::subscriber::{Subscriber, add_event_subscription}; +use crate::python::*; +use crate::subscriber::{add_event_subscription, Subscriber}; use crate::xkb::XKBTransformer; use crate::xkb_transformer_registry::{TransformerParams, XKB_TRANSFORMER_REGISTRY}; - +use crate::*; #[pyclass] pub struct Reader { @@ -20,7 +19,6 @@ pub struct Reader { reader_thread_handle: Option>>, } - #[pymethods] impl Reader { #[new] @@ -28,13 +26,16 @@ impl Reader { pub fn new(kwargs: Option<&PyDict>) -> PyResult { let options: HashMap<&str, &PyAny> = match kwargs { Some(options) => options.extract()?, - None => HashMap::new() + None => HashMap::new(), }; let patterns: Vec<&str> = match options.get("patterns") { - Some(patterns) => patterns.extract() + Some(patterns) => patterns + .extract() .map_err(|_| PyRuntimeError::new_err("'patterns' must be of type 'string[]?'"))?, - None => { vec![] } + None => { + vec![] + } }; let kbd_model = options.get("model").and_then(|x| x.extract().ok()); @@ -42,11 +43,16 @@ impl Reader { let kbd_variant = options.get("variant").and_then(|x| x.extract().ok()); let kbd_options = options.get("options").and_then(|x| x.extract().ok()); let transformer = XKB_TRANSFORMER_REGISTRY - .get(&TransformerParams::new(kbd_model, kbd_layout, kbd_variant, kbd_options)) + .get(&TransformerParams::new( + kbd_model, + kbd_layout, + kbd_variant, + kbd_options, + )) .map_err(|err| PyRuntimeError::new_err(err.to_string()))?; #[cfg(not(feature = "integration"))] - let (reader_exit_tx, reader_exit_rx) = oneshot::channel(); + let (reader_exit_tx, reader_exit_rx) = oneshot::channel(); let subscriber: Arc> = Arc::new(ArcSwapOption::new(None)); let _subscriber = subscriber.clone(); @@ -54,7 +60,7 @@ impl Reader { let id = Arc::new(Uuid::new_v4()); #[cfg(not(feature = "integration"))] - let reader_thread_handle = if !patterns.is_empty() { + let reader_thread_handle = if !patterns.is_empty() { let mut h = DefaultHasher::new(); vec![id.clone()].hash(&mut h); let path_hash = h.finish(); @@ -66,7 +72,9 @@ impl Reader { }); Some(grab_udev_inputs(&patterns, handler, reader_exit_rx).map_err(err_to_py)?) - } else { None }; + } else { + None + }; Ok(Self { id, @@ -81,9 +89,7 @@ impl Reader { pub fn send(&mut self, val: String) -> PyResult<()> { let actions = parse_key_sequence(val.as_str(), Some(&self.transformer)) - .map_err(|err| - ApplicationError::KeySequenceParse(err.to_string()).into_py() - )? + .map_err(|err| ApplicationError::KeySequenceParse(err.to_string()).into_py())? .to_key_actions(); let mut h = DefaultHasher::new(); @@ -124,9 +130,11 @@ impl Reader { let target = match add_event_subscription(target) { Some(target) => target, - None => { return Err(PyRuntimeError::new_err("unsupported link target")); } + None => { + return Err(PyRuntimeError::new_err("unsupported link target")); + } }; self.subscriber.store(Some(Arc::new(target))); Ok(()) } -} \ No newline at end of file +} diff --git a/src/virtual_writer.rs b/src/virtual_writer.rs index 0a3bb5f..fe1b2ba 100644 --- a/src/virtual_writer.rs +++ b/src/virtual_writer.rs @@ -5,14 +5,14 @@ use std::os::fd::AsFd; use anyhow::{anyhow, Result}; use itertools::Itertools; -use pyo3::{pyclass, pymethods, PyResult}; use pyo3::types::PyDict; +use pyo3::{pyclass, pymethods, PyResult}; use tempfile::tempfile; use unicode_segmentation::UnicodeSegmentation; -use wayland_client::{Connection, EventQueue, Proxy}; -use wayland_client::{Dispatch, protocol::wl_registry, QueueHandle}; -use wayland_client::globals::{GlobalListContents, registry_queue_init}; +use wayland_client::globals::{registry_queue_init, GlobalListContents}; use wayland_client::protocol::wl_seat; +use wayland_client::{protocol::wl_registry, Dispatch, QueueHandle}; +use wayland_client::{Connection, EventQueue, Proxy}; use wayland_protocols_misc::zwp_virtual_keyboard_v1::client::zwp_virtual_keyboard_manager_v1; use wayland_protocols_misc::zwp_virtual_keyboard_v1::client::zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1; use wayland_protocols_misc::zwp_virtual_keyboard_v1::client::zwp_virtual_keyboard_v1; @@ -33,9 +33,7 @@ impl VirtualWriter { #[pyo3(signature = (**kwargs))] pub fn new(kwargs: Option<&PyDict>) -> PyResult { let keyboard = VirtualKeyboard::new().unwrap(); - Ok(Self { - keyboard, - }) + Ok(Self { keyboard }) } pub fn send(&mut self, val: String) { @@ -59,7 +57,8 @@ impl Dispatch for AppData { data: &GlobalListContents, conn: &Connection, qhandle: &QueueHandle, - ) {} + ) { + } } impl Dispatch for AppData { @@ -70,7 +69,8 @@ impl Dispatch for AppData { data: &(), conn: &Connection, qhandle: &QueueHandle, - ) {} + ) { + } } impl Dispatch for AppData { @@ -81,10 +81,10 @@ impl Dispatch data: &(), conn: &Connection, qhandle: &QueueHandle, - ) {} + ) { + } } - impl Dispatch for AppData { fn event( state: &mut AppData, @@ -93,7 +93,8 @@ impl Dispatch for AppData { data: &(), conn: &Connection, qhandle: &QueueHandle, - ) {} + ) { + } } struct VirtualKeyboard { @@ -111,8 +112,10 @@ impl VirtualKeyboard { event_queue.roundtrip(&mut AppData).unwrap(); let seat: WlSeat = globals.bind(&event_queue.handle(), 7..=8, ()).unwrap(); - let keybaord_manager: ZwpVirtualKeyboardManagerV1 = globals.bind(&event_queue.handle(), 1..=1, ()).unwrap(); - let mut keyboard = keybaord_manager.create_virtual_keyboard(&seat, &event_queue.handle(), ()); + let keybaord_manager: ZwpVirtualKeyboardManagerV1 = + globals.bind(&event_queue.handle(), 1..=1, ()).unwrap(); + let mut keyboard = + keybaord_manager.create_virtual_keyboard(&seat, &event_queue.handle(), ()); event_queue.roundtrip(&mut AppData).unwrap(); @@ -152,12 +155,14 @@ impl VirtualKeyboard { } } - struct KeymapEntry { keysym: Keysym, } -fn init_virtual_keyboard_v2(keyboard: &ZwpVirtualKeyboardV1, keymap: &HashMap) -> Result<()> { +fn init_virtual_keyboard_v2( + keyboard: &ZwpVirtualKeyboardV1, + keymap: &HashMap, +) -> Result<()> { let mut keymap_file = tempfile().map_err(|_| anyhow!("unable to create temporary file"))?; keymap_file.write_all("xkb_keymap {\n".as_bytes())?; @@ -172,7 +177,8 @@ fn init_virtual_keyboard_v2(keyboard: &ZwpVirtualKeyboardV1, keymap: &HashMap WindowHandler { - Box::new(|exit_rx: oneshot::Receiver<()>, - subscription_rx: mpsc::Receiver| -> Result<()> { - let subscriptions = Arc::new(Mutex::new(HashMap::new())); + Box::new( + |exit_rx: oneshot::Receiver<()>, + subscription_rx: mpsc::Receiver| + -> Result<()> { + let subscriptions = Arc::new(Mutex::new(HashMap::new())); - let prev_hook = std::panic::take_hook(); - std::panic::set_hook(Box::new(|_info| {})); + let prev_hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(|_info| {})); - let mut event_listener = catch_unwind(|| EventListener::new()) - .map_err(|err| anyhow!( + let mut event_listener = catch_unwind(|| EventListener::new()).map_err(|err| { + anyhow!( "hyprland connection error: {}", - err.downcast::().unwrap_or(Box::new("unknown".to_string()) - )))?; + err.downcast::() + .unwrap_or(Box::new("unknown".to_string())) + ) + })?; - std::panic::set_hook(prev_hook); + std::panic::set_hook(prev_hook); - event_listener.add_active_window_change_handler(move |info, _| { - if exit_rx.try_recv().is_ok() { return; } - - while let Ok(msg) = subscription_rx.try_recv() { - match msg { - WindowControlMessage::Subscribe(id, callback) => { subscriptions.lock().unwrap().insert(id, callback); } - WindowControlMessage::Unsubscribe(id) => { subscriptions.lock().unwrap().remove(&id); } + event_listener.add_active_window_change_handler(move |info, _| { + if exit_rx.try_recv().is_ok() { + return; } - } - if let Some(info) = info { - let val = ActiveWindowInfo { - class: info.window_class.clone(), - instance: "".to_string(), - name: info.window_title.clone(), - }; + // let msg = subscription_rx.recv().unwrap(); + // match msg { + // WindowControlMessage::Subscribe(id, callback) => { + // subscriptions.lock().unwrap().insert(id, callback.clone()); + + // let class = Client::get_active().expect("a").expect("b").class.clone(); + // Python::with_gil(|py| { + // let is_callable = callback.as_ref(py).is_callable(); //if !is_callable { continue; } - Python::with_gil(|py| { - for callback in subscriptions.lock().unwrap().values() { - let is_callable = callback.as_ref(py).is_callable(); - if !is_callable { continue; } + // let ret = callback.call(py, (class,), None); - let ret = callback.call(py, (val.class.clone(), ), None); + // if let Err(err) = ret { + // eprintln!("{err}"); + // std::process::exit(1); + // } + // }); + // } + // WindowControlMessage::Unsubscribe(id) => {} + // } - if let Err(err) = ret { - eprintln!("{err}"); - std::process::exit(1); + while let Ok(msg) = subscription_rx.try_recv() { + match msg { + WindowControlMessage::Subscribe(id, callback) => { + subscriptions.lock().unwrap().insert(id, callback); + } + WindowControlMessage::Unsubscribe(id) => { + subscriptions.lock().unwrap().remove(&id); } } - }); - } - }); - event_listener.start_listener()?; - Ok(()) - }) -} \ No newline at end of file + } + + if let Some(info) = info { + let val = ActiveWindowInfo { + class: info.window_class.clone(), + instance: "".to_string(), + name: info.window_title.clone(), + }; + + Python::with_gil(|py| { + for callback in subscriptions.lock().unwrap().values() { + let is_callable = callback.as_ref(py).is_callable(); + if !is_callable { + continue; + } + + let ret = callback.call(py, (val.class.clone(),), None); + + if let Err(err) = ret { + eprintln!("{err}"); + std::process::exit(1); + } + } + }); + } + }); + event_listener.start_listener()?; + Ok(()) + }, + ) +} diff --git a/src/writer.rs b/src/writer.rs index e220c2f..f134329 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1,20 +1,19 @@ #[cfg(not(feature = "integration"))] +use evdev_rs::enums::EventType::EV_SYN; +use pythonize::depythonize; +#[cfg(not(feature = "integration"))] use std::sync::mpsc; #[cfg(not(feature = "integration"))] use std::sync::mpsc::TryRecvError; -#[cfg(not(feature = "integration"))] -use evdev_rs::enums::EventType::EV_SYN; -use pythonize::depythonize; use python::*; -use crate::*; -use crate::device::*; use crate::device::virt_device::DeviceCapabilities; +use crate::device::*; use crate::subscriber::{SubscribeEvent, Subscriber}; use crate::xkb::XKBTransformer; use crate::xkb_transformer_registry::{TransformerParams, XKB_TRANSFORMER_REGISTRY}; - +use crate::*; #[pyclass] pub struct Writer { @@ -32,42 +31,50 @@ impl Writer { pub fn new(kwargs: Option<&PyDict>) -> PyResult { let options: HashMap<&str, &PyAny> = match kwargs { Some(py_dict) => py_dict.extract()?, - None => HashMap::new() + None => HashMap::new(), }; let device_name = match options.get("name") { - Some(option) => option.extract::() + Some(option) => option + .extract::() .map_err(|_| PyRuntimeError::new_err("'name' must be a string"))?, - None => "Virtual map2 output".to_string() + None => "Virtual map2 output".to_string(), }; let mut capabilities = DeviceCapabilities::new(); if let Some(_capabilities) = options.get("capabilities") { - let _capabilities: capabilities::Capabilities = depythonize(_capabilities) - .map_err(|_| PyRuntimeError::new_err("object 'capabilities' did not match the schema"))?; + let _capabilities: capabilities::Capabilities = + depythonize(_capabilities).map_err(|_| { + PyRuntimeError::new_err("object 'capabilities' did not match the schema") + })?; - if _capabilities.keys { capabilities.enable_all_keyboard(); } - if _capabilities.buttons { capabilities.enable_all_buttons(); } - if _capabilities.rel { capabilities.enable_all_rel(); } + if _capabilities.keys { + capabilities.enable_all_keyboard(); + } + if _capabilities.buttons { + capabilities.enable_all_buttons(); + } + if _capabilities.rel { + capabilities.enable_all_rel(); + } match _capabilities.abs { - capabilities::Abs::Bool(x) if x => { capabilities.enable_all_abs() } + capabilities::Abs::Bool(x) if x => capabilities.enable_all_abs(), capabilities::Abs::Specification(x) => { for (key, value) in x.iter() { let tag = parse_abs_tag(key) .map_err(|_| PyRuntimeError::new_err("invalid key '{key}'"))?; if let Some(abs_info) = match value { - &capabilities::AbsSpec::Bool(x) if x => - Some(capabilities::AbsInfo { - value: 128, - minimum: 0, - maximum: 255, - fuzz: 0, - flat: 0, - resolution: 0, - }), + &capabilities::AbsSpec::Bool(x) if x => Some(capabilities::AbsInfo { + value: 128, + minimum: 0, + maximum: 255, + fuzz: 0, + flat: 0, + resolution: 0, + }), capabilities::AbsSpec::AbsInfo(x) => Some(x.clone()), - _ => None + _ => None, } { capabilities.enable_abs(tag, abs_info.into_evdev()); } @@ -83,18 +90,19 @@ impl Writer { let device_init_policy = match options.get("clone_from") { Some(_existing_dev_fd) => { - let existing_dev_fd = _existing_dev_fd.extract::() - .map_err(|_| PyRuntimeError::new_err("the 'clone_from' option must be a string"))?; + let existing_dev_fd = _existing_dev_fd.extract::().map_err(|_| { + PyRuntimeError::new_err("the 'clone_from' option must be a string") + })?; if options.get("capabilities").is_some() { - return Err(PyRuntimeError::new_err("expected only one of: 'clone_from', 'capabilities'")); + return Err(PyRuntimeError::new_err( + "expected only one of: 'clone_from', 'capabilities'", + )); } virtual_output_device::DeviceInitPolicy::CloneExistingDevice(existing_dev_fd) } - None => { - virtual_output_device::DeviceInitPolicy::NewDevice(device_name, capabilities) - } + None => virtual_output_device::DeviceInitPolicy::NewDevice(device_name, capabilities), }; let kbd_model = options.get("model").and_then(|x| x.extract().ok()); @@ -102,7 +110,12 @@ impl Writer { let kbd_variant = options.get("variant").and_then(|x| x.extract().ok()); let kbd_options = options.get("options").and_then(|x| x.extract().ok()); let transformer = XKB_TRANSFORMER_REGISTRY - .get(&TransformerParams::new(kbd_model, kbd_layout, kbd_variant, kbd_options)) + .get(&TransformerParams::new( + kbd_model, + kbd_layout, + kbd_variant, + kbd_options, + )) .map_err(|err| PyRuntimeError::new_err(err.to_string()))?; let (ev_tx, mut ev_rx) = tokio::sync::mpsc::unbounded_channel::(); @@ -111,21 +124,25 @@ impl Writer { #[cfg(not(feature = "integration"))] { // grab udev device - let mut output_device = virtual_output_device::init_virtual_output_device(&device_init_policy) - .map_err(|err| PyRuntimeError::new_err(err.to_string()))?; + let mut output_device = + virtual_output_device::init_virtual_output_device(&device_init_policy) + .map_err(|err| PyRuntimeError::new_err(err.to_string()))?; get_runtime().spawn(async move { loop { loop { let (_, ev) = ev_rx.recv().await.unwrap(); - if let Ok(()) = exit_rx.try_recv() { return; } + if let Ok(()) = exit_rx.try_recv() { + return; + } - let ev = match &ev { InputEvent::Raw(ev) => ev }; + let ev = match &ev { + InputEvent::Raw(ev) => ev, + }; let mut syn = SYN_REPORT.clone(); syn.time.tv_sec = ev.time.tv_sec; syn.time.tv_usec = ev.time.tv_usec; - #[cfg(not(feature = "integration"))] { let _ = output_device.send(&ev); @@ -154,9 +171,7 @@ impl Writer { pub fn send(&mut self, val: String) -> PyResult<()> { let actions = parse_key_sequence(val.as_str(), Some(&self.transformer)) - .map_err(|err| - ApplicationError::KeySequenceParse(err.to_string()).into_py() - )? + .map_err(|err| ApplicationError::KeySequenceParse(err.to_string()).into_py())? .to_key_actions(); for action in actions { @@ -169,10 +184,12 @@ impl Writer { pub fn __test__read_ev(&mut self) -> PyResult> { match self.ev_rx.try_recv().ok() { Some((_, ev)) => { - let ev = match ev { InputEvent::Raw(ev) => { ev } }; + let ev = match ev { + InputEvent::Raw(ev) => ev, + }; Ok(Some(serde_json::to_string(&ev).unwrap())) } - None => { Ok(None) } + None => Ok(None), } } } diff --git a/src/xkb.rs b/src/xkb.rs index 9d7f862..8295a08 100644 --- a/src/xkb.rs +++ b/src/xkb.rs @@ -1,15 +1,15 @@ use std::collections::hash_map::Entry; use std::collections::HashMap; -use evdev_rs::enums::{EV_KEY, EventCode, int_to_ev_key}; +use evdev_rs::enums::{int_to_ev_key, EventCode, EV_KEY}; use itertools::Itertools; use xkbcommon::xkb; use xkbcommon::xkb::Keycode; use xkeysym::Keysym; +use crate::xkb_transformer_registry::TransformerParams; use crate::*; use crate::{encoding, Key}; -use crate::xkb_transformer_registry::TransformerParams; #[derive(Clone)] pub struct XKBTransformer { @@ -18,7 +18,12 @@ pub struct XKBTransformer { } impl XKBTransformer { - pub fn new(model: &str, layout: &str, variant: Option<&str>, options: Option) -> Result { + pub fn new( + model: &str, + layout: &str, + variant: Option<&str>, + options: Option, + ) -> Result { let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS); let keymap = xkb::Keymap::new_from_names( &context, @@ -29,7 +34,8 @@ impl XKBTransformer { options, // Some("terminate:ctrl_alt_bksp".to_string()), // options xkb::COMPILE_NO_FLAGS, - ).ok_or_else(|| anyhow!("failed to initialize XKB keyboard"))?; + ) + .ok_or_else(|| anyhow!("failed to initialize XKB keyboard"))?; let mut xkb_state = xkb::State::new(&keymap); let mut utf_to_raw_map: HashMap> = HashMap::new(); @@ -45,10 +51,14 @@ impl XKBTransformer { keymap.key_for_each(|_, code| { let from_keysym = parse_keycode(&xkb_state, code); - if from_keysym.raw() == 0 { return; } + if from_keysym.raw() == 0 { + return; + } // backspace corrupts state, skip it - if code.raw() == 22 { return; } + if code.raw() == 22 { + return; + } for mods in mods.iter().powerset() { let mut from = vec![code.raw()]; @@ -59,11 +69,19 @@ impl XKBTransformer { } let to_keysym = parse_keycode(&xkb_state, code); - if to_keysym.raw() == 0 { return; } + if to_keysym.raw() == 0 { + return; + } match utf_to_raw_map.entry(to_keysym) { - Entry::Occupied(mut entry) => { if from.len() < entry.get().len() { entry.insert(from); }; } - Entry::Vacant(entry) => { entry.insert(from); } + Entry::Occupied(mut entry) => { + if from.len() < entry.get().len() { + entry.insert(from); + }; + } + Entry::Vacant(entry) => { + entry.insert(from); + } } if let Some(ev_key) = int_to_ev_key(code.raw() - 8) { @@ -72,16 +90,26 @@ impl XKBTransformer { for &(name, _) in mods.iter() { match *name { - "LEFT_SHIFT" => { state.left_shift = true; } - "RIGHT_SHIFT" => { state.right_shift = true; } - "LEFT_ALT" => { state.left_alt = true; } - "RIGHT_ALT" => { state.right_alt = true; } + "LEFT_SHIFT" => { + state.left_shift = true; + } + "RIGHT_SHIFT" => { + state.right_shift = true; + } + "LEFT_ALT" => { + state.left_alt = true; + } + "RIGHT_ALT" => { + state.right_alt = true; + } _ => {} } } match raw_to_utf_map.entry((ev_key, state)) { - Entry::Vacant(entry) => { entry.insert(name.to_string()); } + Entry::Vacant(entry) => { + entry.insert(name.to_string()); + } _ => {} } } @@ -109,20 +137,34 @@ impl XKBTransformer { let keysym = encoding::xkb_utf32_to_keysym(encoded); - self.utf_to_raw_map.get(&keysym).and_then(|keysyms| { - keysyms.iter() - .map(|&x| - int_to_ev_key(x - 8) - .and_then(|x| Some(Key { event_code: EventCode::EV_KEY(x) })) - ) - .collect::>>() - }).ok_or_else(|| anyhow!("failed to convert utf to raw")) + self.utf_to_raw_map + .get(&keysym) + .and_then(|keysyms| { + keysyms + .iter() + .map(|&x| { + int_to_ev_key(x - 8).and_then(|x| { + Some(Key { + event_code: EventCode::EV_KEY(x), + }) + }) + }) + .collect::>>() + }) + .ok_or_else(|| anyhow!("failed to convert utf to raw")) } pub fn raw_to_utf(&self, key: &EV_KEY, state: &KeyModifierState) -> Option { - self.raw_to_utf_map.get(&(*key, *state)) + self.raw_to_utf_map + .get(&(*key, *state)) .cloned() - .and_then(|x| if x.chars().next() == Some('\0') { None } else { Some(x) }) + .and_then(|x| { + if x.chars().next() == Some('\0') { + None + } else { + Some(x) + } + }) } } @@ -134,7 +176,8 @@ impl Default for XKBTransformer { ¶ms.layout, params.variant.as_deref(), params.options.clone(), - ).unwrap() + ) + .unwrap() } } @@ -145,4 +188,4 @@ fn parse_keycode(state: &xkb::State, keycode: Keycode) -> Keysym { } else { encoding::xkb_utf32_to_keysym(ucs) } -} \ No newline at end of file +}