Monthly Archives: March 2021

Discoverable Key Commands

As I make progress on Black Ink for iOS, I have taken care to add keyboard shortcuts to make the app more usable on an iPad with external keyboard. One standard behavior of iPadOS is that when an app supports keyboard shortcuts, simply holding down the command key presents a nice heads-up display (HUD) with the list of shortcuts. For example, if you press the command key on the iPad home screen, you’ll see something like this:

Screenshot of prompt showing list of keyboard shortcuts on iPad.

This panel is supposed to appear automatically for any app that declares keyboard shortcuts using the UIKeyCommand interface of UIKit, which Black Ink does. I couldn’t figure out why the panel never appeared in the app. When the Command key is pressed, I confirmed that my puzzle view was the “first responder”, meaning it is the view that iOS should consult when building the list of key commands to show. What could possibly be going wrong?

Never being one to take the easy route when solving a problem, I found myself tracing the UIKit system code deep into the infrastructure that determines whether or not to show a panel or not. When the command key is held for a sufficiently long time, an internal timer expires and “-[UIKeyCommandDiscoverabilityHUD _HUDPopTimerFired:]” is reached. This method ends up calling a private “_performableKeyCommandsWithResponder:” method, which finally leads to some code that … asks each UIKeyCommand for its discoverabilityTitle, or as a backup, its title. Hmm, what is the discoverability title? Let’s look at the header for UIKeyCommmand:

// Creates an key command that will _not_ be discoverable in the UI.
+ (instancetype)keyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)modifierFlags action:(SEL)action;

// Key Commands with a discoverabilityTitle _will_ be discoverable in the UI.
+ (instancetype)keyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)modifierFlags action:(SEL)action discoverabilityTitle:(NSString *)discoverabilityTitle;

Face, meet palm.

When implementing support for keyboard shortcuts, I had leaned on code completion and went with the easiest option. The shortcuts worked, so what could go wrong? It turns out you have to declare a title for UIKeyCommand or the system won’t present a prompt to users about it. It makes sense, because what would it list as the explanation for what it does, if nothing is set on it?

After I added discoverability titles, everything looks as it should:

Screenshot of Black Ink for iOS showing a full list of keyboard shortcuts for puzzle navigation, etc.

Hopefully this will help others who are stuck trying to figure out why their app’s keyboard shortcuts aren’t showing up.

Not Applicable

From time to time, particularly when I’m working with xib files of a certain vintage, Xcode simply refuses to offer any inspector tools for the contents of a particular Interface Builder document. Instead of the typical controls for setting an object’s properties, I get this:

UntitledImage

Look familiar? It’s super-frustrating when you simply can’t get at the settings for something you desperately need to change. I’ve sometimes gotten Xcode to relent through some combination of closing the file in question, closing assistant editors, etc. But sometimes I just can’t get it to show the properties for an object no matter what I try.

The one thing that always works is to simply make a copy of the xib file in question, which Xcode will happily edit, and then copy it back over the original. It’s really that simple:

  1. Copy MyInterface.xib to MyInterface Copy.xib
  2. Double-click the copy to edit it.
  3. Save changes.
  4. Replace MyInterface.xib with MyInterface Copy.xib

This has vexed me long and hard enough that I thought some others will not have recognized there is such an easy workaround. It would be great if Apple fixes whatever bug is causing this, but in the meantime at least there’s a solution.