Handling Cocoa keyboard events using Blocks

I’ve added a project to GitHub on handling keyboard events in Cocoa apps with blocks.

The handling code is all in the CSTEventManager class: you can register for events like this:

Here’s the contents of my README file from the GitHub project:

NSEvent uses NSTimeInterval (the time since your computer last booted) as the time when an event occurs. For logging and other purposes, I’d rather have an absolute time, and coming from Java, I’m used to Unix time (milliseconds since January 1st, 1970).

I found some great code on Stackoverflow for efficiently converting an NSTimeInterval to a Unix time. Using an Objective-C NSEvent category, I added a new property to NSEvent called “unixtimestamp” that gives you the value in a long long:

The relevant code is in NSEvent+CSTUnixTimestamp.h/m

At the same time, I wanted something similar to the Java AWT’s addEventListener API for handling keyboard events using blocks.

I’m not an AppKit expert, but from what I gathered the simplest technique is subclassing NSWindow and track the keyboard events there. Instead of plopping all of the handling code in that subclass, I made a separate protocol and class so you can quickly reuse the code in other NSResponder implementations.

The protocol is CSTEventSource.h, and the handling class is CSTEventManager.

Another thing that I found annoying is that NSEvent keycode constants don’t exist for most of the standard keys, so I created one for just a couple of keys as an example of how it could be done. Check out CSTKeyConstants.h/m to see how I did it (nothing special).

This project has a complete UI example. When using these classes in your own project that builds everything from a nib, remember to input the NSWindow subclass in the object inspector’s Custom Class field. One trick that I do is override –initWithContentRect:styleMask:backing:defer: and add an NSLog message: if the logging message doesn’t appear when the nib is loaded, that means I forgot to set the custom class.

Run the program and press the spacebar. You should see the down and up events in the attached NSTextField, and the up event is also logged using NSLog, showing how you can register more than one handler per event type.

Repeat keydown events are blocked by default in the CSTEventManager, but you can enable them using the property keyDownRepeat:

Cocoa wrapper for iOS cryptography

Java has many APIs that I miss when programming in Objective-C, but by far the most painful loss has been the Java Cryptography Extension. I’m not an expert in cryptography, but there’s an elegance in that API that is missing from Apple’s CDSA and CommonCrypto mashup available natively on iOS.

So, I thought it would be nice to abstract some of the features behind Objective-C protocols:

  • KeyGenerator: creates new SecretKey objects
  • SecretKey: represents a symmetric key
  • KeySpec: represents pre-existing key material for generating SecretKey objects using a SecretKeyFactory
  • SecretKeyFactory: generates a SecretKey from pre-existing key material
  • Cipher: represents an engine for either encrypting plaintext or decrypting ciphertext with a symmetric algorithm and an existing SecretKey
  • RSAKey: I didn’t do much to abstract this. This should really be called “AsymmetricKey”.

All of the code is up on GitHub. Here’s a quick example of how you can generate a new 128-bit AESKey:

And how you can generate an AESKey from a password using the PBKDF2 specification:

Note: I’m using ARC, so if you’re importing the code into an older iOS application, please keep that in mind.

Audio Queue Services and garbage device unique ids

I’m a CoreAudio beginner and I got tripped up over this one. Hopefully this post (and radar bug) will improve error reporting in future releases of Apple’s audio queue services API.

Here’s the problem: we’re supposed to use the AudioQueueSetProperty API when associating a AudioQueueRef with an AudioObject. Instead of passing the AudioDeviceID of the device, we’re supposed to pass the device unique id, a pointer to a CFStringRef.

The call to AudioQueueSetProperty will succeed regardless of the CFStringRef's value

What does that mean? That means you’ll fail later in your application if you’ve passed a bad value to AudioQueueSetProperty

Creating temporary files from Cocoa

I wish NSFileManager had something like Java’s java.io.File.createTemporaryFile, but it doesn’t.

So I added it with a Category. Wonderful thing, Objective-C categories.

The project is up on GitHub, but I thought I’d include just the code here as well: