From e8bf5effb7b7c37684f397fd5865b29431ecbcc0 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sat, 27 Oct 2018 16:58:49 +0200 Subject: Rename `cocoa_bridge.rs` to `ffi.rs` When I first created the file, it was going to be used to call Cocoa methods using the 'cocoa' crate. It's since turned into a module that contains C functions called by Objective-C code. This new name makes more sense. We'll need to move one or two non-FFI functions outside of this module for better organisation. --- src/cocoa_bridge.rs | 245 ---------------------------------------------------- src/ffi.rs | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 +- 3 files changed, 247 insertions(+), 247 deletions(-) delete mode 100644 src/cocoa_bridge.rs create mode 100644 src/ffi.rs (limited to 'src') diff --git a/src/cocoa_bridge.rs b/src/cocoa_bridge.rs deleted file mode 100644 index f3175b7..0000000 --- a/src/cocoa_bridge.rs +++ /dev/null @@ -1,245 +0,0 @@ -use std::env; -use std::ffi::{CStr, CString, OsString}; -use std::fs; -use std::process::Command; -use std::ptr; -use std::slice; - -use libc::{c_char, size_t}; -use stderrlog; -use xdg; - -use {Action, HeadphoneButton, MapAction, MapGroup, MapKind}; -use config::{self, Config}; -use trial; - -#[repr(C)] -#[derive(Debug)] -pub struct Trigger { - pub buttons: *const HeadphoneButton, - pub length: size_t, -} - -#[repr(C)] -pub enum ActionKind { - Map, - Command, - Mode, -} - -#[derive(Default)] -pub struct State { - in_mode: Option>, - map_group: Option, -} - -#[no_mangle] -pub extern "C" fn dome_key_logger_init() { - stderrlog::new() - .module(module_path!()) - .color(stderrlog::ColorChoice::Never) - .timestamp(stderrlog::Timestamp::Millisecond) - .init() - .unwrap(); -} - -#[no_mangle] -pub extern "C" fn dome_key_state_new() -> *mut State { - Box::into_raw(Box::new(State::default())) -} - -#[no_mangle] -pub extern "C" fn dome_key_state_free(ptr: *mut State) { - if ptr.is_null() { return } - unsafe { Box::from_raw(ptr); } -} - -#[no_mangle] -pub extern "C" fn dome_key_state_load_map_group(ptr: *mut State) { - match xdg::BaseDirectories::with_prefix("dome-key") { - Ok(xdg_dirs) => { - match xdg_dirs.find_config_file("mappings.dkmap") { - Some(mapping_file) => { - let state = unsafe { - assert!(!ptr.is_null()); - &mut *ptr - }; - - let dkmap = fs::read_to_string(mapping_file) - .expect("Failed to read 'mappings.dkmap'"); - - let mut map_group = MapGroup::parse(&dkmap) - .expect("Failed to parse 'mappings.dkmap'"); - map_group.parse_actions(); - - state.map_group = Some(map_group); - }, - None => { - match xdg_dirs.get_config_home().to_str() { - Some(config_home) => { - error!( - "No mapping file found at '{}{}'", - config_home, - "mappings.dkmap" - ) - }, - None => { - error!("Config home path contains invalid unicode") - } - } - }, - } - }, - Err(e) => error!("{}", e), - } -} - -#[no_mangle] -pub extern "C" fn dome_key_run_key_action( - state: *mut State, - trigger: Trigger, -) { - let trigger = unsafe { - assert!(!trigger.buttons.is_null()); - - slice::from_raw_parts(trigger.buttons, trigger.length as usize) - }; - - let mut state = unsafe { - assert!(!state.is_null()); - &mut *state - }; - - run_key_action_for_mode(&mut state, trigger); -} - -// TODO: un-extern -#[no_mangle] -pub extern "C" fn run_key_action_for_mode<'a>( - state: &mut State, - trigger: &'a [HeadphoneButton], -) { - 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; - - return; - } - - if let Some(map) = mode.get(trigger) { - run_action(&map); - } - } - } - - // TODO: make sure this doesn't run when in_mode - 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()); - } - }, - None => (), - } -} - -fn run_action(map_action: &MapAction) { - 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"), - }; - - match Command::new(shell) - .arg("-c") - .arg(action) - .spawn() { - Ok(_) => (), - Err(e) => error!( - "Command failed to start: `{}'", - e - ), - } - } - }, - } -} - -#[no_mangle] -pub extern "C" fn dome_key_parse_args( - args: *const *const c_char, - length: size_t, - config_ptr: *mut Config -) -> *mut Config { - let args = unsafe { - assert!(!args.is_null()); - - let args = slice::from_raw_parts(args, length as usize); - - args - .iter() - .map(|s| { - assert!(!s.is_null()); - - CStr::from_ptr(*s) - .to_string_lossy() - .into_owned() - }) - .collect::>() - }; - - let config = unsafe { - assert!(!config_ptr.is_null()); - - &mut *config_ptr - }; - config::parse_args(&args, config); - - config_ptr -} - -#[no_mangle] -pub extern "C" fn dome_key_config_get() -> *mut Config { - match config::get_config() { - Ok(config) => Box::into_raw(Box::new(config)), - Err(e) => { - error!("{}", e); - - ptr::null_mut() - }, - } -} - -#[no_mangle] -pub extern "C" fn dome_key_config_free(ptr: *mut Config) { - if ptr.is_null() { return } - let config = unsafe { Box::from_raw(ptr) }; - - if config.args.license.is_null() { return } - unsafe { CString::from_raw(config.args.license); } -} - -#[no_mangle] -pub extern "C" fn dome_key_do_trial() { - trial::do_trial(); -} diff --git a/src/ffi.rs b/src/ffi.rs new file mode 100644 index 0000000..f3175b7 --- /dev/null +++ b/src/ffi.rs @@ -0,0 +1,245 @@ +use std::env; +use std::ffi::{CStr, CString, OsString}; +use std::fs; +use std::process::Command; +use std::ptr; +use std::slice; + +use libc::{c_char, size_t}; +use stderrlog; +use xdg; + +use {Action, HeadphoneButton, MapAction, MapGroup, MapKind}; +use config::{self, Config}; +use trial; + +#[repr(C)] +#[derive(Debug)] +pub struct Trigger { + pub buttons: *const HeadphoneButton, + pub length: size_t, +} + +#[repr(C)] +pub enum ActionKind { + Map, + Command, + Mode, +} + +#[derive(Default)] +pub struct State { + in_mode: Option>, + map_group: Option, +} + +#[no_mangle] +pub extern "C" fn dome_key_logger_init() { + stderrlog::new() + .module(module_path!()) + .color(stderrlog::ColorChoice::Never) + .timestamp(stderrlog::Timestamp::Millisecond) + .init() + .unwrap(); +} + +#[no_mangle] +pub extern "C" fn dome_key_state_new() -> *mut State { + Box::into_raw(Box::new(State::default())) +} + +#[no_mangle] +pub extern "C" fn dome_key_state_free(ptr: *mut State) { + if ptr.is_null() { return } + unsafe { Box::from_raw(ptr); } +} + +#[no_mangle] +pub extern "C" fn dome_key_state_load_map_group(ptr: *mut State) { + match xdg::BaseDirectories::with_prefix("dome-key") { + Ok(xdg_dirs) => { + match xdg_dirs.find_config_file("mappings.dkmap") { + Some(mapping_file) => { + let state = unsafe { + assert!(!ptr.is_null()); + &mut *ptr + }; + + let dkmap = fs::read_to_string(mapping_file) + .expect("Failed to read 'mappings.dkmap'"); + + let mut map_group = MapGroup::parse(&dkmap) + .expect("Failed to parse 'mappings.dkmap'"); + map_group.parse_actions(); + + state.map_group = Some(map_group); + }, + None => { + match xdg_dirs.get_config_home().to_str() { + Some(config_home) => { + error!( + "No mapping file found at '{}{}'", + config_home, + "mappings.dkmap" + ) + }, + None => { + error!("Config home path contains invalid unicode") + } + } + }, + } + }, + Err(e) => error!("{}", e), + } +} + +#[no_mangle] +pub extern "C" fn dome_key_run_key_action( + state: *mut State, + trigger: Trigger, +) { + let trigger = unsafe { + assert!(!trigger.buttons.is_null()); + + slice::from_raw_parts(trigger.buttons, trigger.length as usize) + }; + + let mut state = unsafe { + assert!(!state.is_null()); + &mut *state + }; + + run_key_action_for_mode(&mut state, trigger); +} + +// TODO: un-extern +#[no_mangle] +pub extern "C" fn run_key_action_for_mode<'a>( + state: &mut State, + trigger: &'a [HeadphoneButton], +) { + 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; + + return; + } + + if let Some(map) = mode.get(trigger) { + run_action(&map); + } + } + } + + // TODO: make sure this doesn't run when in_mode + 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()); + } + }, + None => (), + } +} + +fn run_action(map_action: &MapAction) { + 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"), + }; + + match Command::new(shell) + .arg("-c") + .arg(action) + .spawn() { + Ok(_) => (), + Err(e) => error!( + "Command failed to start: `{}'", + e + ), + } + } + }, + } +} + +#[no_mangle] +pub extern "C" fn dome_key_parse_args( + args: *const *const c_char, + length: size_t, + config_ptr: *mut Config +) -> *mut Config { + let args = unsafe { + assert!(!args.is_null()); + + let args = slice::from_raw_parts(args, length as usize); + + args + .iter() + .map(|s| { + assert!(!s.is_null()); + + CStr::from_ptr(*s) + .to_string_lossy() + .into_owned() + }) + .collect::>() + }; + + let config = unsafe { + assert!(!config_ptr.is_null()); + + &mut *config_ptr + }; + config::parse_args(&args, config); + + config_ptr +} + +#[no_mangle] +pub extern "C" fn dome_key_config_get() -> *mut Config { + match config::get_config() { + Ok(config) => Box::into_raw(Box::new(config)), + Err(e) => { + error!("{}", e); + + ptr::null_mut() + }, + } +} + +#[no_mangle] +pub extern "C" fn dome_key_config_free(ptr: *mut Config) { + if ptr.is_null() { return } + let config = unsafe { Box::from_raw(ptr) }; + + if config.args.license.is_null() { return } + unsafe { CString::from_raw(config.args.license); } +} + +#[no_mangle] +pub extern "C" fn dome_key_do_trial() { + trial::do_trial(); +} diff --git a/src/lib.rs b/src/lib.rs index 0e57cc0..e73c59b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,14 +32,14 @@ extern crate xdg; mod prefix_println; mod autopilot_internal; -mod cocoa_bridge; mod config; mod errors; +mod ffi; mod key_code; mod parser; mod trial; use parser::{Action, HeadphoneButton, MapAction, MapGroup, MapKind}; -pub use cocoa_bridge::*; +pub use ffi::*; pub use config::{Config, parse_args}; -- cgit v1.2.3