aboutsummaryrefslogtreecommitdiffstats
AgeCommit message (Collapse)Author
2018-09-26HeadphoneKey(runAction): Get rid of keyboard simulationTeddy Wing
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.
2018-09-26lib/dome-key-map: Update for file MapGroup and loggingTeddy Wing
2018-09-25TODO: Add notes for escapingTeddy Wing
Copied from the Vim help.
2018-09-25Update TODOTeddy Wing
2018-09-25Update TODOTeddy Wing
2018-09-25Makefile: Fix dependency on Rust libTeddy Wing
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.
2018-09-25Add TODOTeddy Wing
2018-09-24Makefile: Only run `xcodebuild` when there are changesTeddy Wing
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.
2018-09-24Makefile: Add a target to run the programTeddy Wing
Equivalent of Xcode's "Build & Run" action that we can execute in the command line.
2018-09-24lib/dome-key-map: Simulate key pressesTeddy Wing
2018-09-24lib/dome-key-map: Add current mode deactivation functionalityTeddy Wing
2018-09-24HeadphoneKey: Get switching to mode workingTeddy Wing
* 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.
2018-09-21HeadphoneKey: Start of mode handling (WIP)Teddy Wing
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.
2018-09-18HeadphoneKey: Add a method to switch modesTeddy Wing
This method will be used from `runAction` to switch to a different mode.
2018-09-18HeadphoneKey(runAction): Fix EXC_BAD_ACCESS on undefined mapTeddy Wing
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`.
2018-09-18HeadphoneKey(runAction): Update for new `dome-key-map` interfaceTeddy Wing
The interface of `c_run_key_action()` changed. Update the code here to make it work like before.
2018-09-18Update `lib/dome-key-map` to latestTeddy Wing
Includes mode handling code.
2018-08-28HeadphoneKey(runAction): Use `while` loop over `result->action`Teddy Wing
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
2018-08-28HeadphoneKey(runAction): Take `strlen` out of loopTeddy Wing
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.
2018-08-28HeadphoneKey: Press keys from `_key_buffer` mapTeddy Wing
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?
2018-08-28HeadphoneKey.h: Use `HeadphoneButton` from `dome_key_map.h`Teddy Wing
Instead of our custom enum, use the one generated from the Rust library now that we have it integrated with the project.
2018-08-28Update 'dome-key-map' to latestTeddy Wing
2018-08-28Add dome_key_map.h to the projectTeddy Wing
2018-08-28Makefile(build): Add dependency on Rust library targetTeddy Wing
2018-08-28Link with libdome_key_map.aTeddy Wing
Add libdome_key_map.a to the "Link Binary With Libraries" Build Phase to have our Rust code linked with DomeKey.
2018-08-27Makefile: Add target for Rust libraryTeddy Wing
Make a sub-make target for the Rust library. We'll want to make this a dependency of the regular DomeKey `build` target.
2018-08-27Makefile: Make `build` target phonyTeddy Wing
2018-08-27Add 'dome-key-map' as a submoduleTeddy Wing
This is the Rust library part of the application, which will get linked into DomeKey as a static library.
2018-08-27Add MakefileTeddy Wing
Planning on using this to set up build a dependency on the Rust project.
2018-08-27KeyboardSimulator: Use `char_to_key_code`Teddy Wing
Replace the `keyCodeForChar:` placeholder function I had created earlier with the new `charToKeyCode:` from `char_to_key_code.m`.
2018-08-27Add char_to_key_code.h header fileTeddy Wing
Make a corresponding header file for `char_to_key_code.m`. This enables us to include those functions in other source files.
2018-08-27char_to_key_code.m: Change loop index type to `int`Teddy Wing
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`.
2018-08-27char_to_key_code.m: Import CarbonTeddy Wing
The TIS functions etc. are in Carbon, which needs to be imported.
2018-08-27Add char_to_key_code.mTeddy Wing
This file includes functions for getting a `CGKeyCode` from a character reference. Copied from Stack Overflow by Théo Winterhalter.
2018-08-27KeyboardSimulator: Add `simpleKeyPressWithKey:` methodTeddy Wing
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.
2018-08-27Add `KeyboardSimulator`Teddy Wing
A new class that will know how to simulate key presses in order to handle macros.
2018-08-21HeadphoneKey: Rename `maybeRunAction` to `runAction`Teddy Wing
As alluded to in 8b94ca51e7ef431c476d1c500f36157a976186f0, since we cancel the `performSelector` in `handleDeadKey:`, this method doesn't "maybe" anything, it should always run the action.
2018-08-21HeadphoneKey: Add system for handling dead keysTeddy Wing
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.
2018-08-16HeadphoneKey: Detect 3 headphone button typesTeddy Wing
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.
2018-08-16Random xcodeproj changeTeddy Wing
What does it mean?
2018-08-16Use an `NSApplication`Teddy Wing
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
2018-08-15Try to get headphone button eventsTeddy Wing
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.
2018-08-15Link static DDHidLib library instead of frameworkTeddy Wing
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.
2018-08-14Add `HeadphoneKey` classTeddy Wing
This will be our delegate for the DDHID key listener.
2018-08-07Add DDHidLib framework as a target dependencyTeddy Wing
2018-08-07Add submodule for DDHidLib libraryTeddy Wing
This will hopefully make it easier to interface with `IOHIDLib` and get events from headphone buttons.
2018-08-06Add .gitignoreTeddy Wing
Taken from https://www.gitignore.io/api/objective-c with modifications. Cleaned up the comments and got rid of things I didn't think were necesary.
2018-08-06New Xcode 9.2 command-line tool projectTeddy Wing