aboutsummaryrefslogtreecommitdiffstats
AgeCommit message (Collapse)Author
2018-10-22Add a description to `get_trial_start()`Teddy Wing
2018-10-22Fill in `get_trial_start()` functionTeddy Wing
Reads the encrypted timestamp from the trial file and returns a `DateTime`.
2018-10-22Move trial timestamp file to a hidden fileTeddy Wing
Make it not as obvious that it's there.
2018-10-22initialize_trial_start(): Don't rewrite the file if it already existsTeddy Wing
The `File::open` function will truncate the file if it exists already: > This function will create a file if it does not exist, and will > truncate it if it does. (https://doc.rust-lang.org/std/fs/struct.File.html#method.create) We don't want this behaviour, as the file should only be created & initialised a single time. The trial timestamp should always correspond to the first trial launch of the program. It doesn't do us any good if the file is overwritten by DomeKey and updates the trial start time to a more current value. Thanks to 'sarnold' (https://stackoverflow.com/users/377270/sarnold) on Stack Overflow for the clean pattern matching code to match the `std::io::ErrorKind::AlreadyExists` error: https://stackoverflow.com/questions/28491759/matching-on-a-specific-error-type/43884600#43884600
2018-10-22trial: Add a function to initialise a trial timestamp in a fileTeddy Wing
Save an encoded timestamp to a file. This function should be run once if no trial file is found. The encoded timestamp can then be read on subsequent launches to determine whether the trial period is still in effect. Also add a few function stubs for other actions that seem relevant.
2018-10-22decode_datetime(): Return a `Result`Teddy Wing
Make a custom error type because it's trickier to integrate with 'error-chain' given that 'magic-crypt''s `Error` type doesn't implement the `std::error::Error` trait. For the same reason, we can't use that as the `cause` for `DateCryptError::Decrypt`. This allows us to capture the errors without panicking. Include some additional cleanups as a result of removing the `use std::result` and `use errors::*` imports.
2018-10-22trial: Encrypt and decrypt timestampTeddy Wing
Add functions to encrypt and decrypt a timestamp. We'll be using those functions to write the encrypted timestamp of the first trial launch date to a file. Decided to go for some light encryption instead of just storing a plain or base64-encoded value. Still need to come up with a key, but that will be stored as a plain string in the binary. Need a way to capture the results so we don't end up panicking. Trouble is, 'magic-crypt' doesn't implement the required `Error` traits, so I can't just slot it into 'error-chain'. Still trying to work out how to deal with that. Also add a function to get the days remaining from now.
2018-10-21Add `trial` module, calculate days remainingTeddy Wing
This new module will contain functions to calculate trial days. Here we implement a function to calculate the days remaining in a trial period. If there are less than 0 days remaining, it returns an error result. Couldn't use 'error-chain' because it was complaining about `Debug` and `PartialEq` not being defined. Don't know if it's possible to implement those traits on 'error-chain''s ErrorKind`, but it was complicated enough that I ended up not bothering. Went with 'quick_error' instead to create a custom error type without having to `impl` all the required traits.
2018-10-21Cargo.toml: Add 'chrono' crateTeddy Wing
2018-10-21Rename `config_read_from_file` to `config_get`Teddy Wing
For the same reason that we renamed the Rust version of this function to `get_config`, rename this function also. (Since we're not necessarily getting the config from a file.)
2018-10-20Add an FFI function to get a `Config` or read if from `config.toml`Teddy Wing
Enables us to get a `Config` struct from the config file in the Objective-C app, which will then be passed to the `parse_args()` function to be further filled in.
2018-10-20get_config(): Don't fail if the XDG config directory isn't presentTeddy Wing
In that case, we should return the default config.
2018-10-20read_config_file(): Return a default config if no file foundTeddy Wing
The only config option we have is `timeout`, which has a default value. Any future config options, it seems, should have default values also. We shouldn't force users to create a config file, as the prior code would do. They should be able to rely on the default, and create a `config.toml` only if they want to change it. If no config file is found, we should create a default `Config`. Rename the method because now it still works without reading the config file.
2018-10-20read_config_file(): Update to get the config from `config.toml`Teddy Wing
Use XDG handling from `state_load_map_group()` to do basically the same thing here for reading the config from a `config.toml` file. Use 'error-chain' to handle the `Result`s more easily. No more nested pattern matching, we'll just have to unwrap one `Result` and write the error to stderr in an FFI function.
2018-10-20Cargo.toml: Add 'error-chain'Teddy Wing
Make it easier to handle errors with `Result` types from other crates.
2018-10-19config: Add a function to read a config file (WIP)Teddy Wing
A new function that will read a TOML config file. Doesn't currently access the filesystem. This commit is mostly supporting code to allow that to work. * Add the 'toml' crate * `parse_args()`: Take a mutable `Config` and return that config instead of creating a new one. The recipe will now be to read the config from a file first and then pass that config to this function to be updated. * Modify `c_parse_args()` to take a `*Config` and mirror the new method signature of `parse_args()`
2018-10-19Config: Add `timeout` fieldTeddy Wing
This new field will be used by the calling Objective-C code as the timeout between multi-button maps. It will be defined in a `config.toml` file in the XDG config directory, with a default if unspecified. That part of the code hasn't been written yet, but we've prepared by deriving Serde `Deserialize` on the `Config` struct in order to deserialise a TOML config file. The latest Serde is v1.0.80, but we can't use it because 'cbindgen' depends on an older version. We had been using 'cbindgen' v0.6.3, which depends on serde v1.0.21. Decided to update 'cbindgen' in order to use a newer version of Serde, but that puts us at v1.0.58 instead of the latest: error: failed to select a version for `serde_derive`. ... required by package `cbindgen v0.6.6` ... which is depended on by `dome-key-map v0.0.1 (file:///Users/tw/Documents/Development/dome-key-map)` versions that meet the requirements `= 1.0.58` are: 1.0.58 all possible versions conflict with previously selected packages. previously selected package `serde_derive v1.0.80` ... which is depended on by `dome-key-map v0.0.1 (file:///Users/tw/Documents/Development/dome-key-map)` failed to select a version for `serde_derive` which could resolve this conflict
2018-10-18Add a `<Nop>` pseudo-keyTeddy Wing
This "key" creates an empty action that doesn't do anything. Allows users to clear the default behaviour of a headphone button.
2018-10-18parser: Add a basic test for `NXKey` parsingTeddy Wing
2018-10-18Parse `NXKey`sTeddy Wing
Add a new parser for `NXKey`s. I originally thought I was going to add this to the `key_code()` parser, but that one parses to `KeyCode`s. Seemed like it would be easier to make a brand new parser to handle the different type. Need to add tests for this.
2018-10-18Rename and ignore `dktest` testTeddy Wing
Get rid of the temporary name and give it a more permanent one. I had actually written this test thinking it would be temporary and that I would remove it later. Since it will actually launch iTunes by default due to RCD, this test shouldn't be in the normal suite. However, it seemed like it would be useful to keep it around in case, so leaving it with an ignore skip.
2018-10-18Update `dktest` to use new method signatureTeddy Wing
`dkess_press_key()` now takes a `CGEventFlags` instead of an int.
2018-10-18Add `NXKey` to `KeyboardKeyWithModifiers`Teddy Wing
Add this new key type to the enum and enable it to be `tap()`ped like the others. Made `NXKey` a type alias instead of a struct to allow us to refer to any of the NX key constants using the `NXKey` type. This also meant moving those NX constants outside of the `NXKey` impl and into the top level. May end up wrapping them back up in some kind of namespace later. Adjusted the public-ness of some functions to support this change.
2018-10-18Add functions to get a `CGEventFlags` from a slice of `autopilot::Flag`Teddy Wing
These two functions are copied from `autopilot-rs/src/key.rs` at ab7ebc9fd8bc210717c0210aa20335ea9ceed200. I wanted to use the library directly, but they're private functions. I need this code in order to be able to convert the 'autopilot' `Flag` type into `CGEventFlags`. I need a `CGEventFlags` because my media key simulator, `dkess_press_key()` (an FFI function), requires a `CGEventFlags`-typed value. Needed to change the `from` function to a top-level function due to this error: error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> src/autopilot_internal.rs:213:1 | 213 | impl From<Flag> for CGEventFlags { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate | = note: the impl does not reference any types defined in this crate = note: define and implement a trait or new type instead Bringing the code into the project seemed to be the easiest way to leverage the existing 'autopilot' work.
2018-10-17key_code: Remove inconsistent spaces in attributeTeddy Wing
2018-10-17Add NX special keysTeddy Wing
These keys get pressed using the special media key simulator Objective-C library.
2018-10-15Test media key simulator using the Play media keyTeddy Wing
2018-10-15lib/dome_key_event_source_simulator: Update to latestTeddy Wing
The library now uses a new build mechanism that eliminates the `-isysroot` compiler flag, fixing the runtime link errors we were getting here in the Rust project before.
2018-10-14Compile and link 'libdome_key_event_source_simulator'Teddy Wing
Turn this into a build dependency with Make. Use Vladimir Matveev (https://stackoverflow.com/users/788207/vladimir-matveev) and Shepmaster's (https://stackoverflow.com/users/155423/shepmaster) answer on Stack Overflow to sort out getting Cargo the search path for the static library: https://stackoverflow.com/questions/26246849/how-to-i-tell-rust-where-to-look-for-a-static-library/26254062#26254062 For some reason I wasn't able to get it to work by just putting the library into `./target/debug/deps/`. I had to explicitly tell Cargo to put that in the search path. Also, we need to use `std::env` instead of the `env!` macro to get the `PROFILE` environment variable, otherwise it won't be initialised at the right time, as described in the Rust docs: > Because these variables are not yet set when the build script is > compiled, the above example using env! won't work and instead you'll > need to retrieve the values when the build script is run (https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts)
2018-10-14Add 'dome_key_event_source_simulator' project dependencyTeddy Wing
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-12Cargo.toml: Turn on link-time optimisationTeddy Wing
Thanks to Lifthrasiir for the detailed information about reducing Rust compiled binary size: https://lifthrasiir.github.io/rustlog/why-is-a-rust-executable-large.html Using link-time optimisation gets our release build built with cargo build --release down from 13 Mb to 2 Mb. Pretty good. Using RUSTFLAGS="-C opt-level=s" cargo build --release # or RUSTFLAGS="-C opt-level=z" cargo build --release brought it down additionally to 1.9 Mb. Still trying to decide if I want to keep that. Think I might, but will add it later.
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-05Cargo.toml: Add 'getopts'Teddy Wing
Decided to do command-line option parsing in Rust instead of C as it seemed like it would be easier this way.
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.