Compare commits

..

3 commits

Author SHA1 Message Date
1819dabbc4
Improve default config
now includes media control keys
2024-03-14 13:53:01 +01:00
fdb5774594
Save config file to .config dir 2024-03-14 13:52:43 +01:00
7c842c457b
Clean up code
extract functions
rename exec functions to separate from Exec functionality
2024-03-14 13:51:46 +01:00
6 changed files with 278 additions and 109 deletions

168
Cargo.lock generated
View file

@ -18,7 +18,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2562ad8dcf0f789f65c6fdaad8a8a9708ed6b488e649da28c01656ad66b8b47"
dependencies = [
"alsa-sys",
"bitflags",
"bitflags 1.3.2",
"libc",
"nix",
]
@ -68,7 +68,7 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
dependencies = [
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@ -78,7 +78,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
dependencies = [
"anstyle",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@ -93,6 +93,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
[[package]]
name = "bumpalo"
version = "3.13.0"
@ -223,6 +229,27 @@ dependencies = [
"syn 0.11.11",
]
[[package]]
name = "directories"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.48.0",
]
[[package]]
name = "either"
version = "1.9.0"
@ -296,6 +323,17 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "getrandom"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.14.0"
@ -366,9 +404,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.147"
version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "libdbus-sys"
@ -385,7 +423,7 @@ version = "2.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3557a2dfc380c8f061189a01c6ae7348354e0c9886038dc6c171219c08eaff"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"libc",
"libpulse-sys",
"num-derive",
@ -406,6 +444,17 @@ dependencies = [
"winapi",
]
[[package]]
name = "libredox"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
dependencies = [
"bitflags 2.4.2",
"libc",
"redox_syscall",
]
[[package]]
name = "log"
version = "0.4.21"
@ -425,7 +474,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a456444d83e7ead06ae6a5c0a215ed70282947ff3897fb45fcb052b757284731"
dependencies = [
"alsa",
"bitflags",
"bitflags 1.3.2",
"coremidi",
"js-sys",
"libc",
@ -453,7 +502,7 @@ version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"cfg-if",
"libc",
]
@ -485,10 +534,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "pico_kontroller"
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "picokontroller"
version = "0.1.0"
dependencies = [
"crossbeam-channel",
"directories",
"env_logger",
"int-enum",
"itertools",
@ -544,6 +600,26 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "redox_users"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
dependencies = [
"getrandom",
"libredox",
"thiserror",
]
[[package]]
name = "regex"
version = "1.10.3"
@ -734,6 +810,12 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.87"
@ -835,13 +917,37 @@ dependencies = [
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
"windows-targets 0.52.4",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
@ -865,6 +971,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.4"
@ -877,6 +989,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.4"
@ -889,6 +1007,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.4"
@ -901,6 +1025,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.4"
@ -913,6 +1043,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.4"
@ -925,6 +1061,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.4"
@ -937,6 +1079,12 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.4"

View file

@ -1,10 +1,11 @@
[package]
name = "pico_kontroller"
name = "picokontroller"
version = "0.1.0"
edition = "2021"
[dependencies]
crossbeam-channel = "0.5.8"
directories = "5.0.1"
env_logger = "0.11.3"
int-enum = "1.0.1"
itertools = "0.11.0"

View file

@ -1,43 +1,57 @@
use int_enum::IntEnum;
use log::error;
use serde::{Deserialize, Serialize};
use std::path::Path;
use std::path::PathBuf;
use std::process;
use std::{collections::BTreeMap, fmt::Debug, fs};
use toml::ser::Error;
pub fn init(path: &str) -> Config {
if !Path::new(path).exists() {
write_default(path);
pub fn init(path: PathBuf) -> Config {
if !path.exists() {
let prefix = path.parent().unwrap();
std::fs::create_dir_all(prefix).unwrap();
write_default(&path);
}
load(path)
load(&path)
}
fn serialize_default() -> Result<String, Error> {
let mut mpris = BTreeMap::new();
let mut keymap = BTreeMap::new();
keymap.insert(
NanoKeys::Param4Mute,
vec![
KeyMapVariant::Mpris {
ids: Option::Some(vec!["Feishin".to_string()]),
action: MprisAction::PlayPause,
},
KeyMapVariant::PipeWire {
ids: vec![
"alsa_output.usb-0d8c_Generic_USB_Audio_Device-00.iec958-stereo".to_string(),
],
},
],
);
keymap.insert(
NanoKeys::Play,
vec![KeyMapVariant::Exec {
command: "echo hello".to_string(),
args: Option::None,
vec![KeyMapVariant::Mpris {
ids: Option::None,
action: MprisAction::PlayPause,
}],
);
keymap.insert(
NanoKeys::Stop,
vec![KeyMapVariant::Mpris {
ids: Option::None,
action: MprisAction::Stop,
}],
);
keymap.insert(
NanoKeys::Next,
vec![KeyMapVariant::Mpris {
ids: Option::None,
action: MprisAction::Next,
}],
);
keymap.insert(
NanoKeys::Prev,
vec![KeyMapVariant::Mpris {
ids: Option::None,
action: MprisAction::Previous,
}],
);
keymap.insert(
NanoKeys::Param1Slider,
vec![KeyMapVariant::Mpris {
ids: Option::Some(vec!["Feishin".to_string()]),
action: MprisAction::Volume,
}],
);
mpris.insert("music".to_string(), "Feishin".to_string());
let conf: Config = Config {
general: General {
midi_device: "nanoKONTROL2".to_string(),
@ -49,24 +63,24 @@ fn serialize_default() -> Result<String, Error> {
toml::to_string(&conf)
}
fn deserialize(path: &str) -> Result<Config, toml::de::Error> {
fn deserialize(path: &PathBuf) -> Result<Config, toml::de::Error> {
let cfg_str = fs::read_to_string(path).unwrap();
toml::from_str::<Config>(&cfg_str)
}
pub fn load(path: &str) -> Config {
pub fn load(path: &PathBuf) -> Config {
let cfg = deserialize(path);
match cfg {
Ok(expr) => expr,
Err(expr) => {
error!("Failed loading config at {path}: {expr}");
error!("Failed loading config at {:?}: {expr}", path);
process::exit(1);
}
}
}
pub fn write_default(path: &str) -> () {
pub fn write_default(path: &PathBuf) -> () {
let cfg_toml = serialize_default();
match cfg_toml {
Ok(cfg_toml_text) => {
@ -97,7 +111,7 @@ pub enum KeyMapVariant {
ids: Option<Vec<String>>,
action: MprisAction,
},
PipeWire {
PulseAudio {
ids: Vec<String>,
},
Exec {

View file

@ -28,7 +28,7 @@ fn exec(in_channel: Receiver<KeyEvent>, config: Arc<Config>) {
}
}
fn exec_binary_functionality<F>(player_ids: &Option<Vec<String>>, state: u8, exec_closure: F)
fn execute_binary_functionality<F>(player_ids: &Option<Vec<String>>, state: u8, exec_closure: F)
where
F: Fn(Option<&str>) -> (),
{
@ -50,62 +50,9 @@ fn eval(key: NanoKeys, state: u8, config: &Arc<Config>) {
);
for action in actions {
match action {
KeyMapVariant::Mpris { ids, action } => match action {
MprisAction::Play => {
exec_binary_functionality(ids, state, |player_id: Option<&str>| {
mpris_client::play(player_id)
})
}
MprisAction::Pause => {
exec_binary_functionality(ids, state, |player_id: Option<&str>| {
mpris_client::pause(player_id)
})
}
MprisAction::PlayPause => {
exec_binary_functionality(ids, state, |player_id: Option<&str>| {
mpris_client::play_pause(player_id)
})
}
MprisAction::Stop => {
exec_binary_functionality(ids, state, |player_id: Option<&str>| {
mpris_client::stop(player_id)
})
}
MprisAction::Next => {
exec_binary_functionality(ids, state, |player_id: Option<&str>| {
mpris_client::next(player_id)
})
}
MprisAction::Previous => {
exec_binary_functionality(ids, state, |player_id: Option<&str>| {
mpris_client::previous(player_id)
})
}
MprisAction::Volume => {
let volume = state as f64 / 100.0;
match ids {
Some(some_ids) => some_ids.iter().for_each(|id| {
mpris_client::set_volume(Option::Some(id), volume)
}),
None => mpris_client::set_volume(Option::None, volume),
}
}
},
KeyMapVariant::PipeWire { ids } => {}
KeyMapVariant::Exec { command, args } => {
let output: Result<Output, std::io::Error> = match args {
Some(some_args) => Command::new(command).args(some_args).output(),
None => Command::new(command).output(),
};
match output {
Ok(out) => {
info!("{:?}", out);
}
Err(err) => {
error!("{:?}", err);
}
}
}
KeyMapVariant::Mpris { ids, action } => parse_mpris_action(state, ids, action),
KeyMapVariant::PulseAudio { ids } => {}
KeyMapVariant::Exec { command, args } => parse_exec_action(command, args),
}
}
}
@ -115,6 +62,59 @@ fn eval(key: NanoKeys, state: u8, config: &Arc<Config>) {
}
}
fn parse_mpris_action(state: u8, ids: &Option<Vec<String>>, action: &MprisAction) {
match action {
MprisAction::Play => execute_binary_functionality(ids, state, |player_id: Option<&str>| {
mpris_client::play(player_id)
}),
MprisAction::Pause => {
execute_binary_functionality(ids, state, |player_id: Option<&str>| {
mpris_client::pause(player_id)
})
}
MprisAction::PlayPause => {
execute_binary_functionality(ids, state, |player_id: Option<&str>| {
mpris_client::play_pause(player_id)
})
}
MprisAction::Stop => execute_binary_functionality(ids, state, |player_id: Option<&str>| {
mpris_client::stop(player_id)
}),
MprisAction::Next => execute_binary_functionality(ids, state, |player_id: Option<&str>| {
mpris_client::next(player_id)
}),
MprisAction::Previous => {
execute_binary_functionality(ids, state, |player_id: Option<&str>| {
mpris_client::previous(player_id)
})
}
MprisAction::Volume => {
let volume = state as f64 / 100.0;
match ids {
Some(some_ids) => some_ids
.iter()
.for_each(|id| mpris_client::set_volume(Option::Some(id), volume)),
None => mpris_client::set_volume(Option::None, volume),
}
}
}
}
fn parse_exec_action(command: &str, args: &Option<Vec<String>>) {
let output: Result<Output, std::io::Error> = match args {
Some(some_args) => Command::new(command).args(some_args).output(),
None => Command::new(command).output(),
};
match output {
Ok(out) => {
info!("{:?}", out);
}
Err(err) => {
error!("{:?}", err);
}
}
}
fn is_logical_true(state: u8) -> bool {
return state == 127;
}

View file

@ -4,15 +4,21 @@ mod midi_client;
mod mpris_client;
mod pulse_client;
use crossbeam_channel::unbounded;
use std::sync::Arc;
use directories::ProjectDirs;
use std::{path::PathBuf, sync::Arc};
fn main() {
env_logger::init();
let path: &str = "./config.toml";
let proj_dirs = ProjectDirs::from("com", "ghoscht", "picoKontroller");
let path: PathBuf = proj_dirs.unwrap().config_dir().join("config.toml");
// let path: &str = "./config.toml";
let cfg: config::Config = config::init(path);
let arc_cfg = Arc::new(cfg);
// midi_client::list_ports();
// mpris_client::list_clients();
midi_client::list_ports();
println!("\nMPRIS Clients:");
mpris_client::list_clients();
let (sender, receiver) = unbounded::<midi_client::KeyEvent>();
controller::run(receiver, Arc::clone(&arc_cfg));

View file

@ -48,7 +48,7 @@ where
}
}
fn exec_functionality<F>(player_id: Option<&str>, exec_closure: F)
fn execute_functionality<F>(player_id: Option<&str>, exec_closure: F)
where
F: Fn(&Player) -> (),
{
@ -59,43 +59,43 @@ where
}
pub fn play(player_id: Option<&str>) -> () {
exec_functionality(player_id, |player: &Player| {
execute_functionality(player_id, |player: &Player| {
let _ = player.play();
});
}
pub fn pause(player_id: Option<&str>) -> () {
exec_functionality(player_id, |player: &Player| {
execute_functionality(player_id, |player: &Player| {
let _ = player.pause();
});
}
pub fn play_pause(player_id: Option<&str>) -> () {
exec_functionality(player_id, |player: &Player| {
execute_functionality(player_id, |player: &Player| {
let _ = player.play_pause();
});
}
pub fn stop(player_id: Option<&str>) -> () {
exec_functionality(player_id, |player: &Player| {
execute_functionality(player_id, |player: &Player| {
let _ = player.stop();
});
}
pub fn next(player_id: Option<&str>) -> () {
exec_functionality(player_id, |player: &Player| {
execute_functionality(player_id, |player: &Player| {
let _ = player.next();
});
}
pub fn previous(player_id: Option<&str>) -> () {
exec_functionality(player_id, |player: &Player| {
execute_functionality(player_id, |player: &Player| {
let _ = player.previous();
});
}
pub fn set_volume(player_id: Option<&str>, volume: f64) -> () {
exec_functionality(player_id, |player: &Player| {
execute_functionality(player_id, |player: &Player| {
let _ = player.set_volume(volume);
});
}