diff --git a/Cargo.lock b/Cargo.lock index 96c4819..1e9de9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,6 +66,22 @@ version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "input" version = "0.6.0" @@ -133,6 +149,12 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + [[package]] name = "memoffset" version = "0.6.5" @@ -142,6 +164,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "nix" version = "0.10.0" @@ -169,6 +197,16 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "once_cell" version = "1.17.1" @@ -180,6 +218,9 @@ name = "osc-triggers" version = "0.1.0" dependencies = [ "inputbot", + "rosc", + "serde", + "toml", ] [[package]] @@ -188,6 +229,108 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "proc-macro2" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rosc" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859cb80d4adaa48cb01555ccb87463ff96f9d25bce39c83b00a26b1a5c816365" +dependencies = [ + "byteorder", + "nom", +] + +[[package]] +name = "serde" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + +[[package]] +name = "syn" +version = "2.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "toml" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "udev" version = "0.6.3" @@ -222,6 +365,12 @@ dependencies = [ "libc", ] +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + [[package]] name = "void" version = "1.0.2" @@ -250,6 +399,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winnow" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +dependencies = [ + "memchr", +] + [[package]] name = "x11" version = "2.21.0" diff --git a/Cargo.toml b/Cargo.toml index 1b1e1db..3c7e74b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,6 @@ edition = "2021" [dependencies] inputbot = "0.5.1" +rosc = "0.10.0" +serde = { version = "1.0.160", features = ["derive"] } +toml = "0.7.3" diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..bb813e7 --- /dev/null +++ b/config.toml @@ -0,0 +1,6 @@ +[[mapping]] +event = "/avatars/parameters/MuteSelf" +key = "F24" + +[server] +port = 9090 \ No newline at end of file diff --git a/flake.nix b/flake.nix index 9c15913..7d759b2 100644 --- a/flake.nix +++ b/flake.nix @@ -42,6 +42,9 @@ buildInputs = with pkgs; [ # Add additional build inputs here pkg-config + xorg.libX11 + xorg.libXtst + libinput ] ++ lib.optionals pkgs.stdenv.isDarwin [ # Additional darwin specific inputs can be set here pkgs.libiconv diff --git a/src/main.rs b/src/main.rs index 2a778e4..3760208 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,127 @@ -fn main() { +use std::{net::{SocketAddrV4, UdpSocket}, str::FromStr}; +use rosc::OscPacket; +use toml; +use serde::Deserialize; +use inputbot::{KeybdKey, KeybdKey::*}; + +// Configuration struct with mapping of OSC addresses to keyboard keys, and a general server configuration. +#[derive(Deserialize)] +struct Config { + server: ServerConfig, + // Mappings is called mapping in config + #[serde(rename = "mapping")] + mappings: Vec, +} +#[derive(Deserialize)] +struct EventKeyMapping { + event: String, + key: String, +} +#[derive(Deserialize)] +struct ServerConfig { + port: u16, +} + +fn main() { + let config = match load_config() { + Ok(c) => c, + Err(e) => { + println!("Error loading config file: {}", e); + return; + } + }; + + let mut event_key_map = std::collections::HashMap::new(); + for mapping in config.mappings { + // Convert the key string to a KeybdKey + let key = match to_fkey(&mapping.key) { + Some(k) => k, + None => { + println!("Invalid key: {}", mapping.key); + continue; + } + }; + event_key_map.insert(mapping.event, key); + } + + println!("Starting OSC server on port {}...", config.server.port); + let addr = match SocketAddrV4::from_str(format!("127.0.0.1:{}", config.server.port).as_str()) { + Ok(addr) => addr, + Err(_) => panic!("Unable to match address"), + }; + let sock = UdpSocket::bind(addr).unwrap(); + println!("Listening to {}", addr); + + let mut buf = [0u8; rosc::decoder::MTU]; + + loop { + match sock.recv_from(&mut buf) { + Ok((size, addr)) => { + println!("Received packet with size {} from: {}", size, addr); + let (_, packet) = rosc::decoder::decode_udp(&buf[..size]).unwrap(); + handle_packet(packet, &event_key_map); + } + Err(e) => { + println!("Error receiving from socket: {}", e); + break; + } + } + } +} + +fn load_config() -> Result { + let config_file = std::fs::read_to_string("config.toml").map_err(|e| e.to_string())?; + let config: Config = toml::from_str(&config_file).map_err(|e| e.to_string())?; + Ok(config) +} + +fn handle_packet(packet: OscPacket, mappings: &std::collections::HashMap) { + match packet { + OscPacket::Message(msg) => { + // Match event to key + let key = match mappings.get(&msg.addr) { + Some(k) => k, + None => { + return; + } + }; + // Press key + key.press(); + } + OscPacket::Bundle(bundle) => { + println!("OSC Bundle: {:?}", bundle); + } + } +} + +// Translate "F1", "F2", "F3" etc to corresponding KeybdKey. +fn to_fkey(key: &String) -> Option { + match key.as_str() { + "F1" => Some(F1Key), + "F2" => Some(F2Key), + "F3" => Some(F3Key), + "F4" => Some(F4Key), + "F5" => Some(F5Key), + "F6" => Some(F6Key), + "F7" => Some(F7Key), + "F8" => Some(F8Key), + "F9" => Some(F9Key), + "F10" => Some(F10Key), + "F11" => Some(F11Key), + "F12" => Some(F12Key), + "F13" => Some(F13Key), + "F14" => Some(F14Key), + "F15" => Some(F15Key), + "F16" => Some(F16Key), + "F17" => Some(F17Key), + "F18" => Some(F18Key), + "F19" => Some(F19Key), + "F20" => Some(F20Key), + "F21" => Some(F21Key), + "F22" => Some(F22Key), + "F23" => Some(F23Key), + "F24" => Some(F24Key), + _ => None, + } }