| Age | Commit message (Collapse) | Author |
|
Wrap the function in an `extern "C"` function, make it public, and
export it.
|
|
Otherwise we might end up printing things like error messages from the
license check. Not very nice-looking to have that after the help message
output.
|
|
Should print the version of the program. Doesn't actually do any
printing in Rust, because the Rust library's version number is different
from the DomeKey program version. We just indicate to the Objective-C
code that it should print the version number.
|
|
Add a new argument that allows users to pass in the path to a license
file. Doing so should get picked up by the Objective-C code which will
copy and validate the license.
In order for the Objective-C code to pick up the path string, we add a
`license` field to the `Config.Args` struct.
The new `license` field is a `*mut c_char`, which means we can't derive
Default any more and need to implement a custom `Default` impl for
`Args`.
Additionally, 'getopts' gives us a Rust string (of course), which needs
to be converted into a raw `CString` before we can stick it in the
`license` field in `Args`. I previously wrote `dkeprintln` to be able to
print an error here at the conversion point between `CString` and raw C
string.
Since we used `CString#into_raw()`, we need to call `from_raw()` on the
pointer to free it, otherwise we end up with a memory leak. This
necessitated adding some additional code to `config_free()` to free the
`license` field if non-null.
In order to access `config.args.license` from within `config_free()`, I
also needed to make the `args` and `license` struct fields public, since
the free function is in a different module. Instead of making only those
two fields public, I decided to make them all public, as all the fields
are technically accessible from C code, and are needed by that C code.
Finally, move the module declaration of `prefix_println` to the top of
the module list instead of listing it alphabetically, because otherwise
any modules declared before it (like `config`) don't get access to its
macro. Also add a `#[macro_use]` attribute to the module declaration
because we do want to export its macro.
(https://stackoverflow.com/questions/26731243/how-do-i-use-a-macro-across-module-files#comment78329437_31749071)
|
|
This macro functions exactly like `eprintln` while prepending the string
"dome-key: error: " to all messages. Allows us to give a uniform prefix
to printed rerrors.
Used the `println` macro as a reference:
https://doc.rust-lang.org/src/std/macros.rs.html#157-162
|
|
Make it clearer that the function exits.
|
|
|
|
Plus a little dumb pluralisation.
|
|
I was using `rsplitn` to split the encoded value into an encrypted
timestamp and initialisation vector. Originally, I had used `splitn`,
but upon discovering `rsplitn` decided to use that instead to ensure we
captured the initialisation vector first, and that anything else would
be captured to a single string.
Didn't realise, though, that `rsplitn` orders element in reverse order
compared to `splitn`. Correct the capture order.
|
|
Order them like imports, with `std` errors first, followed by extern
crate errors, followed by local errors, alphabetically.
|
|
I was getting these warnings:
warning: unreachable pattern
--> src/trial.rs:41:17
|
40 | DurationError => return trial_expired(),
| ------------- matches any value
41 | e => {
| ^ unreachable pattern
warning: unreachable pattern
--> src/trial.rs:55:9
|
54 | DurationError => trial_expired(),
| ------------- matches any value
55 | Err(e) => (),
| ^^^^^^ unreachable pattern
Wasn't correctly matching the `DurationError`s.
Add an 'error-chain' `ErrorKind` for `DurationError` to make it the same
type as the others matched in the first `match` pattern.
|
|
Don't apply an offset to converted local times as the offset will
incorrectly shift the correct time. Instead, treat the local time as
0/UTC so that no offset gets applied, even if that's not the correct
local timezone.
|
|
This function serves as the entry point to all trial functionality. When
called, it will try to determine the number of days remaining in the
trial.
* If the trial period is in progress, the number of days remaining will
be printed.
* If an error is encountered involving the trial file, or the trial has
expired, an error message is printed and the program exits.
* Finally, if an unrelated error occurs, print the error without
exiting.
Change `DateTime<Local>`s to `DateTime<FixedOffset>`s in order to have
uniform date types. Otherwise we run into trouble when comparing dates
and when querying functions with different date typs.
TODO: This fails the tests (unless your local timezone is UTC
presumably) because the local time gets stripped of its offset and the
correct offset gets reapplied, incorrectly shifting the time. Figure out
a way to have uniform datetime types without muffing up the timezone
offsets.
|
|
|
|
Reads the encrypted timestamp from the trial file and returns a
`DateTime`.
|
|
Make it not as obvious that it's there.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.)
|
|
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.
|
|
In that case, we should return the default config.
|
|
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.
|
|
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.
|
|
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()`
|
|
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
|
|
This "key" creates an empty action that doesn't do anything. Allows
users to clear the default behaviour of a headphone button.
|
|
|
|
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.
|
|
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.
|
|
`dkess_press_key()` now takes a `CGEventFlags` instead of an int.
|
|
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.
|
|
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.
|
|
|
|
These keys get pressed using the special media key simulator Objective-C
library.
|
|
|
|
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.
|
|
Not fully worked out yet. The idea is to somehow wrap 'autopilot' keys
and special `ev_keymap.h` keys.
|
|
Can't deal with segfaults any more. This code will be moved to
Objective-C.
|
|
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.
|
|
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.
|
|
Otherwise we aren't able to pass it to the `config_free()` function.
|
|
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.
|
|
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.
|
|
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.
|
|
This will allow us to parse command line arguments starting from a C
argv array (hopefully).
|
|
Parse command line options in this library. Need to figure out how to
communicate these over FFI to the Objective-C code.
|
|
I broke deactivation of the active mode by pressing the mode trigger
sequence in 9af4701e7364dac691ce8d2f2875a974091d5453. Get it working
again.
|