Introducing KeyCommands

I’m happy to announce the release of my new micro library - KeyCommands. The project is available at GitHub and uses MIT licence. The idea behind the project is extremely simple - to allow a programmer to bind actions to specified key combinations when iOS or tvOS application runs in simulator. It can make your life easier!

iOS Simulator tvOS Simulator
iOS tvOS

Origins of Idea

A lot of times, people don’t know what they want until you show it to them. (Steve Jobs, source)

For those of you who don’t know React Native, in a big shortcut, it’s a Facebook framework that allows programmers to write iOS and Android applications using Java Script language. You should really check it out - Artsy has some really interesting writeup regarding their experience with the framework.

It wasn’t until last week that I realised that I constantly use ⌘+R key combination while developing React Native app. The dynamic nature of Java Script makes it possible to reload application without recompiling it by pressing ⌘+R while it’s running in sumulator. Because it’s way faster than normal compilation process I’ve used it a lot. Only recently, during a discussion with my new teammate have we realised that binding ⌘+R (or any other combination of keys) to an action is an interesting case.

As React Native project is open sourced, I decided to check how it does key bindings. After a while, I found out class RCTKeyCommands which does the trick. It turned out that with one simple swizzle you can intercept keys pressed during the execution of the program in the simulator. Having seen an example of implementation I decided to create KeyCommands.

Taking Advantage of Swift

Despite the fact I initialy didn’t see any benefits of writing my micro library in Swift, I decided to do that anyway 😊. To my surprise, I discovered out that even in such simple project the use of Swift can result in cleaner and more straightforward library public interface. More specifically, using Swift no-case enums I managed to create singleton-like KeyCommands enum that prevents its user from creating any instance of it. Although no instance of KeyCommands enum can be created, it’s still able to manage a state using its private internal struct.

public enum KeyCommands {

    struct KeyCommandsRegister {
        static var sharedInstance = KeyCommandsRegister()
        private var actionableKeyCommands = [KeyActionableCommand]()
    }
    
    public static func registerKeyCommand(input: String, modifierFlags: UIKeyModifierFlags, action: () -> ()) {
        //access registered key commands stored in KeyCommandsRegister.sharedInstance.actionableKeyCommands
    }
       
    public static func unregisterKeyCommand(input: String, modifierFlags: UIKeyModifierFlags) {
        //access registered key commands stored in KeyCommandsRegister.sharedInstance.actionableKeyCommands
    }
    
}

That’s neat. You can read about this techinique and much more in Erica Sadun article about no-case enums.

Keeping it safe

As swizzling isn’t the best practice and can lead to App Store rejections, all methods of KeyCommands expand to empty definitions in builds for actual devices. It keeps swizzling out of the builds that are sent to App Store and allows developers to sleep well at night. 🙂

#if (arch(i386) || arch(x86_64)) && (os(iOS) || os(tvOS)) //true for simulators
//Magic happens here
#else
//Empty definitions of methods
#end

Wrapping up

I hope that you’ll find KeyCommands a helpful tool. It’s available on GitHub.