2023-04-23 17:45:20 +01:00
|
|
|
extern crate inputbot;
|
|
|
|
|
2023-04-24 10:42:48 +01:00
|
|
|
use std::{
|
|
|
|
net::{SocketAddrV4, UdpSocket},
|
|
|
|
str::FromStr,
|
|
|
|
};
|
2023-04-23 17:17:50 +01:00
|
|
|
|
2023-04-24 10:42:48 +01:00
|
|
|
use inputbot::{get_keybd_key, KeybdKey, KeybdKey::*};
|
2023-04-23 17:17:50 +01:00
|
|
|
use rosc::OscPacket;
|
2023-04-23 17:45:20 +01:00
|
|
|
use serde::{Deserialize, Serialize};
|
2023-04-24 10:42:48 +01:00
|
|
|
use std::collections::HashMap;
|
|
|
|
use toml;
|
2023-04-23 17:17:50 +01:00
|
|
|
|
|
|
|
// Configuration struct with mapping of OSC addresses to keyboard keys, and a general server configuration.
|
2023-04-23 17:45:20 +01:00
|
|
|
#[derive(Deserialize, Serialize)]
|
2023-04-23 17:17:50 +01:00
|
|
|
struct Config {
|
2023-04-24 10:42:48 +01:00
|
|
|
server: ServerConfig,
|
|
|
|
// Mappings is called mapping in config for ease of use.
|
|
|
|
#[serde(rename = "mapping")]
|
|
|
|
mappings: Vec<EventKeyMapping>,
|
2023-04-23 17:17:50 +01:00
|
|
|
}
|
2023-04-23 17:45:20 +01:00
|
|
|
#[derive(Deserialize, Serialize)]
|
2023-04-23 17:17:50 +01:00
|
|
|
struct EventKeyMapping {
|
2023-04-24 10:42:48 +01:00
|
|
|
event: String,
|
|
|
|
key: String,
|
2023-04-23 17:17:50 +01:00
|
|
|
}
|
2023-04-23 17:45:20 +01:00
|
|
|
#[derive(Deserialize, Serialize)]
|
2023-04-23 17:17:50 +01:00
|
|
|
struct ServerConfig {
|
2023-04-24 10:42:48 +01:00
|
|
|
port: u16,
|
2023-04-23 17:17:50 +01:00
|
|
|
}
|
|
|
|
|
2023-04-23 13:20:07 +01:00
|
|
|
fn main() {
|
2023-04-24 10:42:48 +01:00
|
|
|
let config = match load_config() {
|
|
|
|
Ok(c) => c,
|
|
|
|
Err(e) => {
|
|
|
|
println!("Error loading config file: {}", e);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut event_key_map = HashMap::new();
|
|
|
|
for mapping in config.mappings {
|
|
|
|
// Convert the key string to a KeybdKey. First try to convert it to an F key, then to a normal key by matching the char.
|
|
|
|
let key = match to_fkey(&mapping.key) {
|
|
|
|
Some(k) => k,
|
|
|
|
None => match mapping.key.chars().next() {
|
|
|
|
Some(c) => get_keybd_key(c).unwrap(),
|
|
|
|
None => {
|
|
|
|
println!("Invalid key: {}", mapping.key);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
event_key_map.insert(mapping.event, key);
|
|
|
|
}
|
2023-04-23 17:17:50 +01:00
|
|
|
|
2023-04-24 10:42:48 +01:00
|
|
|
println!("Starting OSC server on port {}...", config.server.port);
|
2023-04-23 17:17:50 +01:00
|
|
|
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<Config, String> {
|
2023-04-24 10:42:48 +01:00
|
|
|
// If the config file isn't found, create one with default values
|
|
|
|
if !std::path::Path::new("config.toml").exists() {
|
|
|
|
let default_config = Config {
|
|
|
|
server: ServerConfig { port: 9000 },
|
|
|
|
mappings: vec![],
|
|
|
|
};
|
|
|
|
let toml = toml::to_string_pretty(&default_config).map_err(|e| e.to_string())?;
|
|
|
|
std::fs::write("config.toml", toml).map_err(|e| e.to_string())?;
|
|
|
|
println!("Created default config file at config.toml");
|
|
|
|
}
|
|
|
|
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)
|
2023-04-23 17:17:50 +01:00
|
|
|
}
|
|
|
|
|
2023-04-24 10:42:48 +01:00
|
|
|
fn handle_packet(packet: OscPacket, mappings: &HashMap<String, KeybdKey>) {
|
2023-04-23 17:17:50 +01:00
|
|
|
match packet {
|
|
|
|
OscPacket::Message(msg) => {
|
2023-04-24 10:42:48 +01:00
|
|
|
// Print message
|
|
|
|
println!("OSC Message: {:?}", msg);
|
|
|
|
// Print address
|
|
|
|
println!("OSC Address: {}", msg.addr);
|
2023-04-23 17:17:50 +01:00
|
|
|
// Match event to key
|
2023-04-24 10:42:48 +01:00
|
|
|
let key = match mappings.get(&msg.addr) {
|
|
|
|
Some(k) => k,
|
|
|
|
None => {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// Press key
|
|
|
|
println!("Pressing key: {:?}", key);
|
|
|
|
key.press();
|
2023-04-23 17:17:50 +01:00
|
|
|
}
|
|
|
|
OscPacket::Bundle(bundle) => {
|
|
|
|
println!("OSC Bundle: {:?}", bundle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-04-23 13:20:07 +01:00
|
|
|
|
2023-04-23 17:17:50 +01:00
|
|
|
// Translate "F1", "F2", "F3" etc to corresponding KeybdKey.
|
2023-04-24 10:42:48 +01:00
|
|
|
// inputbot doesn't currently support this natively.
|
2023-04-23 17:17:50 +01:00
|
|
|
fn to_fkey(key: &String) -> Option<KeybdKey> {
|
2023-04-24 10:42:48 +01:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mod tests {
|
|
|
|
// Test to_fkey
|
|
|
|
#[test]
|
|
|
|
fn test_to_fkey() {
|
|
|
|
assert_eq!(super::to_fkey(&"F1".to_string()), Some(super::F1Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F2".to_string()), Some(super::F2Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F3".to_string()), Some(super::F3Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F4".to_string()), Some(super::F4Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F5".to_string()), Some(super::F5Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F6".to_string()), Some(super::F6Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F7".to_string()), Some(super::F7Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F8".to_string()), Some(super::F8Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F9".to_string()), Some(super::F9Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F10".to_string()), Some(super::F10Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F11".to_string()), Some(super::F11Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F12".to_string()), Some(super::F12Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F13".to_string()), Some(super::F13Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F14".to_string()), Some(super::F14Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F15".to_string()), Some(super::F15Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F16".to_string()), Some(super::F16Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F17".to_string()), Some(super::F17Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F18".to_string()), Some(super::F18Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F19".to_string()), Some(super::F19Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F20".to_string()), Some(super::F20Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F21".to_string()), Some(super::F21Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F22".to_string()), Some(super::F22Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F23".to_string()), Some(super::F23Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F24".to_string()), Some(super::F24Key));
|
|
|
|
assert_eq!(super::to_fkey(&"F25".to_string()), None);
|
|
|
|
}
|
2023-04-23 13:20:07 +01:00
|
|
|
}
|