aboutsummaryrefslogtreecommitdiffstats
path: root/src
AgeCommit message (Collapse)Author
2018-10-14Test media key simulator static libraryTeddy Wing
Added a build of `libdome_key_event_source_simulator.a` to the root of the project to test running the function from Rust. Works. Needs to be built with custom `RUSTFLAGS` in order to build: $ RUSTFLAGS="-L ." cargo test dktest We'll need to figure out how to add this to the Rust build script. Now that we know it works, we can integrate the static library more permanently into the project.
2018-10-14key_code: Ideas for a new `KeyCode` typeTeddy Wing
Not fully worked out yet. The idea is to somehow wrap 'autopilot' keys and special `ev_keymap.h` keys.
2018-10-13Get rid of media key simulation codeTeddy Wing
Can't deal with segfaults any more. This code will be moved to Objective-C.
2018-10-13Try to send media key events using `NSEvent` and `CGevent`Teddy Wing
Segfaults on key_code.rs:184: error: process didn't exit successfully: `.../dome-key-map/target/debug/deps/dome_key_map-0efa5c8428fad354 send_media_key --nocapture` (signal: 11, SIGSEGV: invalid memory reference) shell returned 101 This is my attempt to use first the 'cocoa' and 'core-graphics' crates, then the 'objc' crate (because I hoped that would get around the segfault), to simulate a media key event. Once I got the types right and the code compiling, I couldn't get past segfaults. After struggling with this for over a day and not being able to figure out what on earth is going on, I wrote the exact same thing in Objective-C and it just worked. That's it, I'm done with this. This code is going to be expunged and I'm going to take a C function pointer in the function that runs map actions that will simulate media key presses in real Cocoa/Carbon. Enough of this headache.
2018-10-11Add a function to send media key eventsTeddy Wing
Media keys (rewind, play/pause, fast forward on Mac function keys) are different from normal keys. These use a different API, and sending events to simulate those keys is different. Here's a first stab at getting something working for posting simulated media key events. This will be used for new special keys in mapping actions. Haven't tested this at all yet, just happy that it finally compiles. Follow the two Stack Overflow answers referenced in the comments (from Albert https://stackoverflow.com/users/133374/albert and Nick Sweeting https://stackoverflow.com/users/2156113/nick-sweeting). Add the `core-graphics` crate to give us access to `CGEvent`, `CGKeyCode`, and related types. Also include some commented `CGKeyCode` definitions for future use.
2018-10-06c_parse_args(): Change return value to mut pointerTeddy Wing
Otherwise we aren't able to pass it to the `config_free()` function.
2018-10-06c_parse_args(): Box the returned `Config` pointerTeddy Wing
Otherwise it gets freed too early by Rust. Add (re-add) a free function for it too now that we know it must be freed manually.
2018-10-05Fix command line argument FFI issuesTeddy Wing
I was getting this error when I brought the library into the Objective-C application: Undefined symbols for architecture x86_64: "_parse_args", referenced from: _main in main.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) Ended up renaming my FFI function to `c_parse_args()` (like with `c_run_key_action()`) which fixed this. Going to have to rename those to use a `dome_key_` prefix eventually. Then, my `args` argument didn't have the right type. It had a `*const c_char` type, which is a string, when it should have been an array of strings. We just needed a double pointer. A Stack Overflow answer from Tibor Benke (https://stackoverflow.com/users/3989982/tibor-benke) proved helpful in this regard: fn foo(argc: c_int, argv: *const *const c_char); https://stackoverflow.com/questions/34379641/how-do-i-convert-rust-args-into-the-argc-and-argv-c-equivalents/34379937#34379937 Update the `map()` call to account for the new type, and check that we don't have any null pointers within the array. Finally, shift the first (command name) argument off the list when parsing options as suggested in the 'getopts' doc example.
2018-10-05Turn `Config` into a C struct instead of an opaque structTeddy Wing
We want to be able to access the fields in `Config`, so make them accessible across the FFI boundary. * Return a regular, not boxed, `Config` from `parse_args()`. * Add `repr(C)`s on our structs (had forgotten how this worked in 961b3b0b2d33a2c632fbc093b61e2c2d4dc07f70). * Delete the `config_free()` function as I think the stuct doesn't need to be freed being a POD struct. Hopefully that's the case.
2018-10-05Add an FFI bridge to the `parse_args()` functionTeddy Wing
This will allow us to parse command line arguments starting from a C argv array (hopefully).
2018-10-05Add a command line option parserTeddy Wing
Parse command line options in this library. Need to figure out how to communicate these over FFI to the Objective-C code.
2018-10-04run_key_action_for_mode(): Fix in_mode deactivationTeddy Wing
I broke deactivation of the active mode by pressing the mode trigger sequence in 9af4701e7364dac691ce8d2f2875a974091d5453. Get it working again.
2018-10-03run_key_action_for_mode(): Extract action code to a new methodTeddy Wing
Move the key simulation and command execution code to a new method so that it can be reused in both top-level map and mode branches. This additionally enables command running from top-level maps (previously it only worked for in-mode maps).
2018-10-03Remove return values from `c_run_key_action()` etc.Teddy Wing
Get rid of the return values on `c_run_key_action()` and `run_key_action_for_mode()`. The reason why we returned a result previously was to feed information back to the Objective-C caller to run subsequent parts of the pipeline, like storing the current in-mode and simulating key presses. Now that both of those are handled by the Rust code, we have no more need for these return structs. Get rid of the return values to clean up the code a bit.
2018-10-03Remove `action_parses_command_to_vec_of_words()` testTeddy Wing
Commands now stay `Action::String`s without getting re-parsed to `Action::Command`s (as per 79dfb6c8cd536e9448f05421d5018785a8b590ce). This test is therefore unnecessary.
2018-10-03run_key_action_for_mode(): Run mode-level commandsTeddy Wing
Originally I was going to use `Action::Command` for this, which was intended to hold a `Vec` of command arguments. I decided against that approach. After thinking about command parsing a bit, it's of course not just splitting into a `Vec` on whitespace. You need to take into account quoting and whatever other idiosyncrasies. Instead, I think I'm going to leave commands as `Action::String`s and end up not using `Action::Command` for anything. We take the shell command string from the action and feed it to a new `Command`, executed using the `-c` option to the parent shell. As I understand it, `spawn()` will reuse the parent process' stdout etc. descriptors.
2018-10-03parse_actions(): Parse `Action::Map` for mode mapsTeddy Wing
Previously I had only implemented it for top-level maps. Get it working for in-mode maps too. Move the parsing code to a function so it can be re-used in both places.
2018-10-03run_key_action_for_mode(): Remove `type_string()` callsTeddy Wing
Actions should now be typed using the `tap()` method and `Action::Map` types instead of `Action::String`s in order to enable modifier keys.
2018-10-03Remove old code from 52398f0c8507fdb5fe4a680bbbb841232b396ae7Teddy Wing
Non-working attempts.
2018-10-03run_key_action_for_mode(): Tap keys using `KeyboardKeyWithModifiers`Teddy Wing
Use `autopilot::key::tap()` to simulate each key and modifier in an action. Originally tried to do this using a method that takes a closure to access the `KeyCodeConvertible` types inside `KeyboardKey`. Ended up with a much cleaner API solution that only requires a single method call.
2018-10-03KeyboardKeyWithModifiers: Remove `Option` from `flags` fieldTeddy Wing
I originally wrapped the contained `Vec` in an `Option` to that we wouldn't have to initialise whole new empty `Vec` for every key in an `Action` list. However, this made less sense once I wrote the parser and ended up with an empty `Vec` by default that I then had to convert into an `Option`. Now I've started the code to type keys including modifiers, and the `Option` no longer makes any sense at all. In order to type keys (including modifiers), I'll be using Autopilot's `tap()` function: pub fn tap<T: KeyCodeConvertible + Copy>(key: T, flags: &[Flag], delay_ms: u64) { This function requires a slice, so I ended up getting a `Vec` from my parser, converting it to an Option to satisfy my original interface, and now would have to convert it back into a `Vec` or slice in order to be able to pass it into `tap()`. Talk about unnecessary. Get rid of the `Option` because it's more work for absolutely no reason.
2018-10-03Clean up old code from 48fcb96befe65ca30bfd91f4194afb9e99258f4aTeddy Wing
Get rid of old commented code now that we have a working version.
2018-10-02Re-parse map `Action::String`s to `Action::Map`s (WIP)Teddy Wing
First, `MapGroup::parse` parses actions to `Action::String`s. We then run a second pass on the parsed actions to parse them into `Action::Map`s. A few failed attempts but finally got it working. Tried a few ways of doing it and kept running into various borrowing problems. Glad it's working now.
2018-10-01Revert "Add <Bslash> and <lt> escapes for action (WIP)"Teddy Wing
This reverts commit 5ef2443642a2d8b223afdf169200a725d2809b76. See that commit for details.
2018-10-01Add <Bslash> and <lt> escapes for action (WIP)Teddy Wing
Trying to add new escape special keys for '\' and '<' but having a bit of trouble. Looks like I'm not using `and` `satisfy` correctly, as I'm getting this error: error[E0271]: type mismatch resolving `<(impl combine::Parser, combine::combinator::Satisfy<_, [closure@src/parser.rs:263:56: 263:68]>) as combine::Parser>::Output == char` --> src/parser.rs:260:18 | 260 | (choice!( | __________________^ 261 | | try(string_case_insensitive("Bslash")).map(|_| '\\'), 262 | | try(string_case_insensitive("lt")).map(|_| '<'), 263 | | try(action_character().and(satisfy(|c| c != '>'))) 264 | | ).map(|c| | |_________________^ expected tuple, found char | = note: expected type `(char, _)` found type `char` = note: required because of the requirements on the impl of `combine::Parser` for `combine::combinator::Try<(impl combine::Parser, combine::combinator::Satisfy<_, [closure@src/parser.rs:263:56: 263:68]>)>` = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) I had added the `satisfy` not '>' after getting this test failure without it: ---- parser::tests::action_parses_map_with_bslash_and_lt_special_keys stdout ---- thread 'parser::tests::action_parses_map_with_bslash_and_lt_special_keys' panicked at 'assertion failed: `(left == right)` left: `Err(Errors { position: PointerOffset(4332007031), errors: [Unexpected(Token('l')), Expected(Token('>'))] })`, right: `Ok(Map([KeyboardKeyWithModifiers { key: Character(Character(Character('a'))), flags: None }, KeyboardKeyWithModifiers { key: Character(Character(Character('\\'))), flags: None }, KeyboardKeyWithModifiers { key: Character(Character(Character('A'))), flags: None }, KeyboardKeyWithModifiers { key: Character(Character(Character('N'))), flags: None }, KeyboardKeyWithModifiers { key: Character(Character(Character('D'))), flags: None }, KeyboardKeyWithModifiers { key: Character(Character(Character('<'))), flags: None }, KeyboardKeyWithModifiers { key: Character(Character(Character('>'))), flags: None }, KeyboardKeyWithModifiers { key: Character(Character(Character('\\'))), flags: Some([Control]) }, KeyboardKeyWithModifiers { key: Character(Character(Character('<'))), flags: Some([Meta, Shift]) }]))`', src/parser.rs:928:9 as I suspected this was a problem with `<lt>`. But now that I think about it, it could just as easily have been a problem with `<Bslash>`. Not sure. Anyway, I'm thinking of dropping these escapes because they're redundant (we already have '\' escaping) and because I'm tired of these errors.
2018-10-01Fill in `action_parses_map_with_simple_characters()` testTeddy Wing
A simple test to check parsing of a simple string without any special keys or modifiers.
2018-09-30Fill in `action_parses_map_with_multiple_modifiers()`Teddy Wing
Make this test do something, validating that it parses multiple modifier prefixes in a special key.
2018-09-30action_parses_map_with_less_than_escape(): Add `>` to end of test stringTeddy Wing
Add a '>' closing bracket to the end of the test string to make sure that the '<' gets escaped even with a '>' following it.
2018-09-30special_key(): Handle modifier + character special keysTeddy Wing
Previously we were able to parse modifier + KeyCode (`<C-Enter>`) special keys and plain KeyCode ones (`<Esc>`). This change adds parsing support for the final type of special key, modifier + character (e.g. `<C-l>`). action_character(): Move the `map` outside of this function and into `action_map()` to allow us to reuse the parsed `char` in `special_key()`. key_modifier(): * Move the `many()` parser and `Option` handling outside of this function and into `special_key()`. Doing so enables us to say: <C-l> // Character special keys _require_ a modifier (thus // `many1`) <[C-]Left> // KeyCode special keys may or may not have a modifier // (thus `many`) * Rename from `key_modifiers()` to singular now that it only parses a single modifier. special_key(): Parse both character and KeyCode special keys with modifiers. action_parses_map_with_modifier(): Change input string to include a KeyCode-style special key with a modifier since we didn't have one previously. This ensures we test both kinds of special keys.
2018-09-30Try to parse modifier keys (WIP)Teddy Wing
Add some parsing code for modifier keys inside special keys (`<`- `>`-wrapped keys). Currently only works for special keys defined in `special_key()`. Needs to be extended to work for modified character keys (e.g. <C-l>), thus the test in this commit doesn't pass.
2018-09-30action_map(): Add backslash escapingTeddy Wing
Escape '<' and '\' by prepending a backslash. Since special characters are enclosed in '<' '>' brackets, in order to type a literal '<', we need a way to escape it. Use backslash, like in Vim.
2018-09-30Extract action normal character parsing to a functionTeddy Wing
Splits up the `action_map()` function and gives the parser a name.
2018-09-30Get `action_map()` parser workingTeddy Wing
Additionally, fix a problem in `key_code()` when using special key names that start with the same character (like any of the F keys, or Enter and Esc). The parser would discard the first character, like in the `definitions()` parser. Use the same solution here, by wrapping the parser choices in `try()`s. Add `Esc` to the test to confirm that it fails not just for the F keys but for all key names that start similarly.
2018-09-30parser: Add `key_code` and `special_key` parsersTeddy Wing
Still need to test them though. They'll be used in conjunction with another new parser, `action_map`, which will parser map-type action strings. `key_code` parses `autopilot::key::KeyCode`s, basically all special keys and modifiers. `special_key` parses key codes inside `<` `>` braces. Change the test to use `easy_parse` to give a clear error message. Add `recursion_limit` to the crate on the advice of the compiler in order for the `choice!` macro in `key_code()` to work properly. Otherwise it spits out a giant error message complaining about `rustc --explain E0277`. If I remove a handful of elements from the `choice!`, it compiles, so it seems there's an upper bound restricted by the recursion limit. Modifier keys are included in a commented section as these are part of the 'autopilot' `KeyCode` enum, but they'll be handled in a separate parser.
2018-09-29Start filling new action parser testsTeddy Wing
* Some stub ideas for test text * Fill in the test for special keys * Add some convenience methods to more easily create the expected test result objects
2018-09-29parser: Add some stub tests for a new `Action` parserTeddy Wing
Ideas for some things we should be testing.
2018-09-29cocoa_bridge: Get rid of unused testTeddy Wing
There's no longer a `parse_mappings()` function (did I write one of those?), which causes this test to error on compilation. Remove it since it's just a stub for an old model of the code.
2018-09-29parser: Correct tests to use new `Action` enum typeTeddy Wing
Fix these tests that were based on the `String` version of `Action`, before b02e7366c3c4b9edb5afa0d012952fad369b66a9.
2018-09-29Change `parser::Action` to an enumTeddy Wing
It will now be a different type of `Vec` depending on whether it represents a string map or a command. We'll have new parsers to parse the action definition in a more fine-grained way. The `String` variant is just there for temporary backward compatibility while I figure out parsing for the other two. Still need to update the tests for this change.
2018-09-29Revert "Try to propagate KeyCodeConvertible from Action to everywhere"Teddy Wing
This reverts commit 16cd3895f7b111544927d71904aab912d9abbf59. See that commit message for details.
2018-09-29Try to propagate KeyCodeConvertible from Action to everywhereTeddy Wing
Such a pain. As soon as I clear one set of compilation errors, another set crops up. The last one was like the following: error[E0277]: the trait bound `K: std::default::Default` is not satisfied --> src/cocoa_bridge.rs:117:1 | 117 | / pub extern "C" fn state_new<K>() -> *mut State<K> 118 | | where K: KeyCodeConvertible { 119 | | Box::into_raw(Box::new(State::default())) 120 | | } | |_^ the trait `std::default::Default` is not implemented for `K` | = help: consider adding a `where K: std::default::Default` bound note: required by `cocoa_bridge::State` --> src/cocoa_bridge.rs:100:1 | 100 | / pub struct State<K: KeyCodeConvertible> 101 | | where K: Default { 102 | | in_mode: Option<Vec<HeadphoneButton>>, 103 | | map_group: Option<MapGroup<K>>, 104 | | } | |_^ error[E0277]: the trait bound `K: std::default::Default` is not satisfied I'm done with this. Just going to make a darn enum of 'autopilot's `Character` and `KeyCode` structs so I don't have to deal with this mess.
2018-09-28Revert "parser::map(): Try to parse Action with a dependency on MapKind"Teddy Wing
This reverts commit 76ab45d4a5890c4c348b33c32775e45a7c320c58. See that commit for details.
2018-09-28parser::map(): Try to parse Action with a dependency on MapKindTeddy Wing
Some non-working code where I was trying to get an `Action2` to parse correctly, with a dependency on the result of the `map_kind()` parser. Couldn't figure out how to get this to work though, as I couldn't escape errors like this one: error[E0271]: type mismatch resolving `<[closure@src/parser.rs:157:36: 186:6] as std::ops::FnOnce<(_,)>>::Output == std::result::Result<parser::Map, <I as combine::StreamOnce>::Error>` --> src/parser.rs:137:16 | 137 | fn map<I>() -> impl Parser<Input = I, Output = Map> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `parser::Map` | = note: expected type `std::result::Result<std::result::Result<(parser::Map, _), _>, _>` found type `std::result::Result<parser::Map, _>` = note: required because of the requirements on the impl of `combine::Parser` for `combine::combinator::FlatMap<combine::combinator::TakeUntil<_, combine::char::Newline<I>>, [closure@src/parser.rs:157:36: 186:6]>` = note: the return type of a function must have a statically known size error: aborting due to previous error For more information about this error, try `rustc --explain E0271`. Feeling like I've spent way too long stuck on this, so I'm just going to parse actions into new action type (`Action2` for now) by doing a second parsing pass. It's not going to be as performant, but at least I'm confident that will work. We can always come back to this later. I'll be reverting this commit.
2018-09-27parser: Make a new `Action` typeTeddy Wing
With this new type, I'm trying to set up a way to parse actions more precisely, to allow us to get special keys and modifier-flagged keys. Still trying to work out how this is going to work at the parser level though, since the action parser is going to need to depend on the map kind parser.
2018-09-25logger_init(): Configure `stderrlog`Teddy Wing
* No colours * Add timestamp
2018-09-25Add `logger_init()` to init 'stderrlog'Teddy Wing
Trying to see if this works. If I call the init function over FFI and then call functions that use the error macro, will logging work?
2018-09-25state_load_map_group(): Log errors instead of panickingTeddy Wing
This allows us to log the errors without exiting the program.
2018-09-25state_load_map_group(): Fix double slash in error messageTeddy Wing
2018-09-25run_key_action_for_mode(): Fix bugs from recent state & autopilot changeTeddy Wing
* Use `state.in_mode` as `in_mode` will always be `None` now * Use `type_string` for map actions inside a mode. Otherwise the action wouldn't be typed.
2018-09-25run_key_action_for_mode(): Get `MapGroup` from stateTeddy Wing
Now that there can be a `MapGroup` in the `State`, get it from there. This will allow us to get the `MapGroup` from a configuration file.