128 lines
4.3 KiB
Rust
128 lines
4.3 KiB
Rust
use crate::config::NanoKeys;
|
|
use crate::config::{Config, KeyMapVariant, MprisAction};
|
|
use crate::interaction_server::InteractionServer;
|
|
use crate::midi_client::KeyEvent;
|
|
use crate::mpris_client;
|
|
use crate::pulse_controller::{PulseController, PulseMessage};
|
|
use crossbeam_channel::{unbounded, Receiver, Sender};
|
|
use log::{error, info, warn};
|
|
use std::process::{Command, Output};
|
|
use std::sync::Arc;
|
|
use std::thread;
|
|
|
|
pub fn run(in_channel: Receiver<KeyEvent>, config: Arc<Config>) {
|
|
let (sender, receiver) = unbounded::<PulseMessage>();
|
|
let pulse = PulseController::new(receiver);
|
|
pulse.start();
|
|
thread::spawn(move || {
|
|
exec(in_channel, sender, config);
|
|
});
|
|
}
|
|
|
|
fn exec(in_channel: Receiver<KeyEvent>, pulse_channel: Sender<PulseMessage>, config: Arc<Config>) {
|
|
loop {
|
|
let event_in = in_channel.recv();
|
|
match event_in {
|
|
Ok((key, state)) => {
|
|
eval(key, state, &config, &pulse_channel);
|
|
}
|
|
Err(err) => {
|
|
error!("Failed receiving event in controller thread: {err}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn execute_binary_functionality<F>(player_ids: &Option<Vec<String>>, state: u8, exec_closure: F)
|
|
where
|
|
F: Fn(Option<&str>) -> (),
|
|
{
|
|
if is_logical_true(state) {
|
|
return;
|
|
}
|
|
match player_ids {
|
|
Some(ids) => ids.iter().for_each(|id| exec_closure(Option::Some(id))),
|
|
None => exec_closure(Option::None),
|
|
}
|
|
}
|
|
|
|
fn eval(key: NanoKeys, state: u8, config: &Arc<Config>, pulse_channel: &Sender<PulseMessage>) {
|
|
match config.keymap.get(&key) {
|
|
Some(actions) => {
|
|
info!(
|
|
"Registered actions for [{:?} | {}]: {:?}",
|
|
key, state, actions
|
|
);
|
|
for action in actions {
|
|
match action {
|
|
KeyMapVariant::Mpris { ids, action } => parse_mpris_action(state, ids, action),
|
|
KeyMapVariant::PulseAudio { ids, action } => {
|
|
//TODO: maybe clean up?
|
|
let _ = pulse_channel.send((Arc::new(ids.to_vec()), action.clone(), state));
|
|
}
|
|
KeyMapVariant::Exec { command, args } => parse_exec_action(command, args),
|
|
}
|
|
}
|
|
}
|
|
None => {
|
|
warn!("Midi input {:?} not mapped", key);
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|