aboutsummaryrefslogtreecommitdiffstats
path: root/src/map.rs
blob: 7d9cb0f5ad2b394cf0d03eca3c28a0c23694b341 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use std::env;
use std::ffi::OsString;
use std::process::Command;

use {Action, HeadphoneButton, MapAction, MapKind};
use errors::*;
use ffi::State;

#[repr(C)]
pub enum ModeChange {
    Activated,
    Deactivated,
}

pub fn run_key_action<'a>(
    state: &mut State,
    trigger: &'a [HeadphoneButton],
    on_mode_change: extern "C" fn(mode_change: ModeChange),
) -> Result<()> {
    match state.map_group {
        Some(ref map_group) => {
            let map = map_group.maps.get(trigger);
            let mode = map_group.modes.get(trigger);

            if let Some(in_mode) = state.in_mode.clone() {
                if let Some(mode) = map_group.modes.get(&in_mode) {
                    // Deactivate mode by pressing current mode trigger
                    if &in_mode[..] == trigger {
                        state.in_mode = None;

                        on_mode_change(ModeChange::Deactivated);

                        return Ok(());
                    }

                    if let Some(map) = mode.get(trigger) {
                        run_action(&map)?;
                    }
                }
            }

            if state.in_mode.is_none() {
                if let Some(map) = map {
                    run_action(&map)?;
                }
            }

            if mode.is_some() {
                state.in_mode = Some(trigger.to_vec());

                on_mode_change(ModeChange::Activated);
            }
        },
        None => (),
    };

    Ok(())
}

fn run_action(map_action: &MapAction) -> Result<()> {
    match map_action.kind {
        MapKind::Map => {
            if let Action::Map(action) = &map_action.action {
                for key in action {
                    key.tap()
                }
            }
        },
        MapKind::Command => {
            if let Action::String(action) = &map_action.action {
                let shell = match env::var_os("SHELL") {
                    Some(s) => s,
                    None => OsString::from("/bin/sh"),
                };

                return Command::new(shell)
                    .arg("-c")
                    .arg(action)
                    .spawn()
                    .map(|_| ())
                    .chain_err(|| "command failed to start");
            }
        },
    };

    Ok(())
}