Age | Commit message (Collapse) | Author |
|
|
|
Enables us to use special keys and modifier keys in action definitions.
|
|
|
|
This will load the map group from the mapping config file in the XDG
config directory. Rust errors get logged to stderr.
|
|
Delete the code that simulates key presses from map actions. Also delete
the mode saving code and the unused `cleanup` label.
Simulating key presses is now handled by the Rust library using the
'autopilot' crate. It felt easier that way to handle all types of key
presses.
|
|
|
|
Copied from the Vim help.
|
|
|
|
|
|
Turns out the order-only prerequisite from
8c363688ac173d34c865b8271ade8c845b67fa24 was a false lead. That just
made Make ignore the timestamp on the file and caused it to rebuild the
dependency tree correctly.
Looks like we need an actual dependency on the Rust source files in
order to get the tree working correctly. Can't just call into the
sub-make and have it work.
Change the `RUST_LIB` prerequisite to point to the actual file because
otherwise it always has the latest timestamp, causing `xcodebuild` to
run.
Unfortunately we end up with duplication between this Makefile and the
one in `dome-key-map`, but that seems unavoidable if we want to set up
the dependencies correctly.
Now it finally seems to work right.
|
|
|
|
Previously, Make would always run `xcodebuild`. I couldn't figure out
why, but after some looking around and experimenting, it looked to be
due to the `$(RUST_LIB)` prerequisite. Putting it in the order-only
dependencies list seems to fix the never-up-to-date problem.
Also use `:=` instead of `=` when defining `SOURCE_FILES`. During my
research, I came across this recommendation:
> always use := not = for shell (and wildcard, for that matter) for
> performance reasons.
From MadScientist (https://stackoverflow.com/users/939557/madscientist)
on Stack Overflow:
https://stackoverflow.com/questions/26694249/makefiles-using-wildcard-vs-find-for-specifying-source-files/26694693#26694693
Move the `DomeKey` debug product executable path into a variable and use
it as a target to clarify the build target and also allow us to
substitute the variable in the `run` task.
Now finally, `make run` won't re-build the project if no changes have
been made, it'll just run the executable.
|
|
Equivalent of Xcode's "Build & Run" action that we can execute in the
command line.
|
|
|
|
|
|
* Update to latest dome-key-map, which handles in-mode internally using
a `State` struct
* Make a `State *` ivar to store the current dome-key-map state, and let
it do the work of mode handling
Currently doesn't handle exiting a mode, only entering one. But that
last part actually does finally work now, yay!
Still requires cleanup to get rid of the old `in_mode` handling.
|
|
A nearly-wroking stab at making mode handling work. Here we store the
current mode in the `HeadphoneKey` object. We try to save it when
getting a mode back from `c_run_key_action()`, and use it as a filter
when running `c_run_key_action()`.
I had discovered a problem, though. During debugging, I found that the
`_in_mode` ivar would end up pointing to the same thing as the current
`trigger`. Guessed that this had to do with it being a const pointer, so
I started to write some code to store the `Trigger` by value instead of
by reference in `HeadphoneKey` `_in_mode`.
At this point, a little frustrated, I thought about the overall problem
of mode handling again. It occurred to me that I no longer like this
idea of storing the current mode in the Objective-C object, as this
recent work has left a bad taste in my mouth. Instead, I'm going to try
moving mode handling into the Rust library, and make it opaque to the
Objective-C code. Hoping that that approach will be a more pleasant
endeavor.
|
|
This method will be used from `runAction` to switch to a different mode.
|
|
If no map was defined for a headphone button, the fields in the
`CKeyActionResult` `result` would be null pointers, causing the bad
access exception.
Before doing anything, check that the pointer points to something real.
Also, fix the `kind` check to use the `ActionKind_Map` enum now that the
`dome-key-map` library has been updated with the new definition of
`CKeyActionResult`.
|
|
The interface of `c_run_key_action()` changed. Update the code here to
make it work like before.
|
|
Includes mode handling code.
|
|
Using `strlen` loops once over the string, so along with our `for` loop,
we have two loops over the string. No big deal since these shouldn't be
that long. But, using a `while` loop we can iterate just once.
Reference:
Alexandre C. (https://stackoverflow.com/users/373025/alexandre-c)
https://stackoverflow.com/questions/3213827/how-to-iterate-over-a-string-in-c/3213903#3213903
|
|
This appears to fix the weirdness I was having in
815bf3e8601b6d0cfb0296c6f2c302aaf5059b23, where extra characters were
getting sent to `simpleKeyPressWithKey:` even though there was only 1
element (the correct number of elements) in the `action` array/string.
I guess before the length was getting recalculated on each iteration of
the loop.
Previously, this would result in the Vim `x` command getting entered
just after the map action (for example `j`).
Now it appears to work correctly.
|
|
Take the headphone keys in `_key_buffer` and get the associated map
action by calling into the Rust library. If the map action has
`MapKind::Map`, then we need to simulate key presses of the characters
in the `action` field.
Works, but it's a little finicky. Maybe I'm including the null byte in
the loop?
|
|
Instead of our custom enum, use the one generated from the Rust library
now that we have it integrated with the project.
|
|
|
|
|
|
|
|
Add libdome_key_map.a to the "Link Binary With Libraries" Build Phase to
have our Rust code linked with DomeKey.
|
|
Make a sub-make target for the Rust library. We'll want to make this a
dependency of the regular DomeKey `build` target.
|
|
|
|
This is the Rust library part of the application, which will get linked
into DomeKey as a static library.
|
|
Planning on using this to set up build a dependency on the Rust project.
|
|
Replace the `keyCodeForChar:` placeholder function I had created earlier
with the new `charToKeyCode:` from `char_to_key_code.m`.
|
|
Make a corresponding header file for `char_to_key_code.m`. This enables
us to include those functions in other source files.
|
|
Fix the following warning from Xcode's analyzer:
char_to_key_code.m:62:49: Implicit conversion loses integer
precision: 'size_t' (aka 'unsigned long') to 'int'
Since `NSNumber` `numberWithInt` takes an `int`, change `i` to `int`.
|
|
The TIS functions etc. are in Carbon, which needs to be imported.
|
|
This file includes functions for getting a `CGKeyCode` from a character
reference.
Copied from Stack Overflow by Théo Winterhalter.
|
|
This as yet untested method will be responsible for simulating a key
press given a single-character string corresponding to the glyph of the
key to be pressed.
It relies on `keyCodeForChar:` to get the `CGKeyCode` corresponding to
the glyph, a method which is currently just a placeholder.
|
|
A new class that will know how to simulate key presses in order to
handle macros.
|
|
As alluded to in 8b94ca51e7ef431c476d1c500f36157a976186f0, since we
cancel the `performSelector` in `handleDeadKey:`, this method doesn't
"maybe" anything, it should always run the action.
|
|
We need a way to listen for multiple presses of the headphone buttons.
Once a timeout has been reached, the recorded button presses that
happened within the space of the timeout will be those used for
performing an associated action.
We add an enum for headphone buttons to give them an easy name to refer
to.
The default timeout between button presses before an action gets
executed is 1000 milliseconds. This will be customisable later with a
configuration file.
Already pressed "dead" keys within the timeout are stored in
`_key_buffer`. This buffer gets cleared when we run an action. I you've
pressed a headphone button key, we always try to run an action, so this
will always get cleared, even if no mapping action is found.
I decided to start `_key_buffer` with a capacity of 5 at random because
that seemed like more than enough button presses for a single mapping.
handleDeadKey::
- In order to append a `HeadphoneButton` from our enum, I needed to
convert it to an `id` type because `NSArray` doesn't allow anything
else.
- Call `maybeRunAction` with our timeout. Before doing this, make sure
we cancel any previous delayed calls to `maybeRunAction` because they
might be executed before the most recent headphone button press and
thus run the wrong action. Cancelling enables us to only run the
action once the timeout has elapsed after the most recent headphone
button press.
maybeRunAction:
- Just log the headphone button presses for now.
- Remove all presses from `_key_buffer` so to make way for a new key
mapping.
- I'm now thinking I should rename this method to remove the `maybe`.
Since the `performSelector` gets cancelled outside of this method, the
"maybe" doesn't make sense to me here any more.
|
|
Using my previous `NSLog`s, the `usageId`s came out to be 205, 233, 234.
Converted these to hex and looked for corresponding constants in
`/System/Library/Frameworks/IOKit.framework/Versions/A/Headers/hid/IOHIDUsageTables.h`.
Use these constants to figure out which button was presed. Will have to
test other headphones. I'm worried the numbers may change for different
headphones.
Added a `KeyPress` enum that's a lot easier to understand than the
`upOrDown` `BOOL`, whose meaning I completely didn't get until I looked
at the `NSLog` output I had before.
|
|
What does it mean?
|
|
Previously the `setListenInExclusiveMode:` call did appear to work,
disabling the normal functioning of the headphone buttons. But my
`NSLog`s in `ddhidAppleMikey:press:upOrDown:` didn't get printed, the
method having not been called.
Since all the other applications I found using DDHidLib were GUI apps
using `NSApplication`, I decided to take this approach here. Set up the
`NSApplication` in `main.c` and added a new `AppDelegate` class.
It seems like the reference to my `HeadphoneKey` instance wasn't getting
retained or something. When I moved the:
HeadphoneKey *h = [[HeadphoneKey alloc] init];
line into `AppDelegate`'s `applicationDidFinishLaunching:`, nothing
changed. However, when I moved all code from `HeadphoneKey` into
`AppDelegate`, my `ddhidAppleMikey:press:upOrDown:` method _did_ get
called.
At that point, it was logical to try adding a `HeadphoneKey` instance
variable and `init`ing into that variable. As a result, we now have a
working `ddhidAppleMikey:press:upOrDown:` delegate method that correctly
logs the headphone key events!
Here are the reference applications I looked at using DDHidLib, found
using a simple GitHub search:
- https://github.com/radiant-player/radiant-player-mac/pull/450/files
- https://github.com/7hil/mac_ear_control/blob/8859ed554517ce798b8ae7c2d0e78610b9994300/mac_ear_control/AppDelegate.m
- https://github.com/7hil/mac_ear_control/blob/8859ed554517ce798b8ae7c2d0e78610b9994300/mac_ear_control/AppDelegate.m
- https://github.com/schrekia/beardedspice-enhanced/blob/a9b78c0dbae6bca2cb0d2ecc362e4b7fe5b02129/BeardedSpiceControllers/BSCService.m
- https://github.com/beardedspice/beardedspice/blob/8e1aea5bda68395e6b0d866bca9289a2a5ba40ed/BeardedSpiceControllers/BSCService.m
- https://github.com/beardedspice/beardedspice/blob/8e1aea5bda68395e6b0d866bca9289a2a5ba40ed/BeardedSpiceControllers/BSCService.m
- https://github.com/BarakaAka1Only/radiant-player-mac-BarakaLyrics/blob/1ce889bbb80f081209aff7936a329a3b426462e9/radiant-player-mac/AppDelegate.m
- https://github.com/zsszatmari/MagicKeys/blob/210015d5da876cd7bb1daf73efa3c775c18e7973/MagicKeys-Agent/SPMediaKeyTap.m
Thanks immensely this Cocoa With Love article from Matt Gallagher, which
was invaluable in showing me how to create a minimal Cocoa application
without needing a nib, Info.plist, or even application bundle (instead
putting everything in a single executable, making it easier to
distribute this as a command-line application with a built-in daemon):
https://www.cocoawithlove.com/2010/09/minimalist-cocoa-programming.html
|
|
Try to set up a listener for headphone button events. Doesn't appear to
work. The initialiser is called, but the delegate method doesn't appear
to be. I'm not seeing any of those log messages.
Followed an example from here:
https://github.com/radiant-player/radiant-player-mac/pull/450/files
Not sure what I'm doing wrong yet, but decided I should commit what I
have since I can't figure it out right now.
|
|
Since the framework is external, we can't link it directly as it's a
third-party library. As such, it would be separate from our executable.
Instead, link against the static DDHidLib library so that it gets
bundled into the executable.
|
|
This will be our delegate for the DDHID key listener.
|
|
|
|
This will hopefully make it easier to interface with `IOHIDLib` and get
events from headphone buttons.
|