Inquisitive Cocoa

Unless otherwise stated all code is released under the MIT License

Entries in the Cocoa category:

10th April ‘12

+ imageWithPDFNamed: …

@interface UIImage (AJKImageWithPDF)
 
+ (UIImage *)imageWithPDFNamed:(NSString *)pdfName;
+ (UIImage *)imageWithPDFNamed:(NSString *)pdfName scale:(CGFloat)scale;
 
@end

A small category for iOS to create an image from a .pdf file with as little fuss as possible: UIImage+WithPDF.

Cocoa, iOS, Objective-C, SourceAdd your thoughts

22nd September ‘10

Introducing Bezier

FScript is the creation of Philippe Mougin, it’s a scripting language that is loosely based on Smalltalk but is built to use native Objective-C/Cocoa objects. It’s currently the closest thing available to a scripted version of Objective-C, with lots of nice Smalltalk-esque bonuses thrown in, like blocks (more like to Ruby’s blocks than Objective-C’s) and amazingly flexible array programming. It’s extremely cool.


Bezier acts as a viewer for FScript. It’s exactly what you get if you were to take the contents of a text file, parse it as FScript and then execute it from within a views -drawRect: method.

Bezier Screenshot

The way I tend to set things up is to first create a file with the .bezier extension using my favourite text editor (I like TextMate, particularly when used in conjunction with the FScript bundle that offers syntax highlighting, some simple snippets and basic auto-completion) and open that file in Bezier. I’ll then arrange the two windows so that they are both visible, either by placing them side by side, or on different screens, if that’s an option. Bezier will redraw it’s main view whenever it detects a changes to the file (using the AJKFileSystemObserver class) so all you need to do is write some FScript based drawing code, hit ‘Save’ and the changes should be reflected in the other window.

I find it a refreshing change to the normal Build and Run approach using Xcode, particularly when it gets down to those tiny iterations that go into honing a pixel perfect UI. If your code contains any errors then the bottom view will try to offer some useful information to help with debugging:

Bezier Error

Once you’ve refined your drawing code it’s pretty easy to convert FScript code into standard Objective-C that you can use directly in your Cocoa applications thanks to their similar basic syntax although it’s worth bearing in mind that not all of FScripts niceties will translate to Objective-C.

I hope that you’ll find Bezier to be a useful tool for prototyping UI elements in code, particularly now that resolution independence is becoming a reality thanks to the new iPhones and iPods.

It currently offers a bare minimum of features. There are a few things that I plan to add when I have a spare moment (staring with a better example file), but I’m open to any suggestions, or forks if you feel like digging into the code yourself. It’d also be nice to hear from people who end up using Bezier, maybe even see some pictures if you create something super pretty!

You can download Bezier as a binary along with a sample .bezier file, or get the source code on GitHub (MIT license).

Bezier-icon.png

Cocoa, Objective-C, SourceAdd your thoughts

14th September ‘10

Going Freelance

Peering over the edge, the pool looks a lot further down than it did earlier. The water reflects the purple blue sky the single solitary cloud. Calm and unreadable, but somehow with a terrifying edge.

A moment of stillness, followed by the dive.

It will either be the most amazing, shimmering, life-changing experience.. or equally it could be a total bellyflop. The black unbroken mirror of the water looms. Impossible to fathom. Time seems to hold it’s breath, and I can’t help enjoy the feeling of falling and the thrill of the unknown.


From today I’m going freelance as a Cocoa and iOS developer, creating extra-ordinary, soulful applications for the iPhone, iPod Touch, iPad and the Mac. I’m a lone code wrangler, newly returned from shaving yaks in the distant lands of architecture, prepared to face down any problem the compiler throws at me. I’m ready, able and available for hire.

Cocoa, iOS, PersonalAdd your thoughts

14th January ‘10

NSString-EscapeHTMLCharacters

Another category on NSString. This one converts a string containing characters that are special to HTML into their HTML entities.

& becomes &
< becomes &lt;
> becomes &gt;
And so on..

It’s loosely based on a similar category in the Google Toolbox. It’s written with a bias towards simplicity rather than efficiency.. and it’s on GitHub: http://github.com/inquisitiveSoft/NSString-EscapeHTMLCharacters. MIT License.

Cocoa, Objective-C, SourceAdd your thoughts

In a similar vein, here’s a command I use for building the project of the current document in Xcode.

PROJECT=$(ruby -- "${TM_BUNDLE_SUPPORT}/bin/find_xcode_project.rb")
if [[ -f "${PROJECT}/project.pbxproj" ]]; then
   open -a Xcode "${PROJECT}"
else
   echo "Didn't find an Xcode project file."
   echo "You may want to set TM_XCODE_PROJECT."
fi
 
 
osascript -e 'tell application "Xcode"
	activate
 
	set targetProject to project of active project document
	if (build targetProject) is equal to "Build succeeded" then
		launch targetProject
	end if
end tell'

Cocoa, ScriptsAdd your thoughts

14th August ‘09

As seen via gcc

My current favorite private Cocoa method:
+[NSSavePanel _crunchyRawUnbonedPanel]

CocoaAdd your thoughts

Everyone seems to have their own version of a unique identifier generator. Here’s mine:

+ (NSString *)uuid {
	uuid_t buffer;
	uuid_generate(buffer);
 
	char string[37];
	uuid_unparse_lower(buffer, string);
 
	return [NSString stringWithFormat:@"%s", string];
}

And remember to add #include <uuid/uuid.h>

Cocoa, Objective-C, SourceAdd your thoughts

5th April ‘09

Key Code Translator

The Problem

Today’s problem is to translate the keyCodes that are generated by keyboard NSEvents into characters. Press a ‘q’ key, and the field in the preferences should display an ‘q’ instead of 12. There are simpler options. If you still have the event handily lying around then you could try calling [theEvent characters] or [theEvent charactersIgnoringModifiers]. Simple.. init.

Except to keep a users keyboard preferences I don’t want to have to be archive and unarchiving NSEvents every time I want to show a list of keyboard commands. Why go to all this effort when it’d be so easy to just save that single key code as a single integer. Things get even stickier if the user has changed keyboards since they last opened your application.

I want to map the physical location of the key that’s just been pressed, to a method, regardless of whether that key will print (in this completely contrived example) a ‘b’ or an ‘ß’. All I want to change is for the label that the user sees in the preferences window to match the current keyboard layout. As well as displaying normal characters, there are a set of special characters that want to be displayed specially, for example the space, tab, enter, arrow keys all need to be displayed in a human friendly fashion.

Existing Solutions

There are other options out there that currently solve this problem. There’s Shortcut Recorder (originally created Waffle Software but now with it’s own google code site, which has it’s own Leopard only branch, and a snazzy new IB3 palette. It looks pretty decent. With a nice simple drag & drop & hook up to the delegate, it’s easy to use too. Which is all well and good.. until you try and get it too compile against 10.5 frameworks. Eek!! The compiler bails. KLGetCurrentKeyboardLayout() and KLGetKeyboardLayoutProperty() are undefined. The documentation says that they’ve only been depreciated, but that doesn’t help when the compiler starts popping up errors. The solution is simple. Compile against the 32 bit, 10.4 framework.

Except that I want it to work the ‘right’ way, darn it. I want 64 bits. I want the future, not the hackery of a previous system, and it’d be kinda nice if it didn’t break at the first sight of Snow Leopard.

Updated 2009 – 12 – 22
Shortcut Recorder is now full 64bit friendly, and rather good. It does a lot more than my version, and does it better. For one thing it has a complete dictionary of replacement characters, and support for Padkey’s and similar niceties. I’m sure I’ll be using it in the future.

HotKey3 from Rogue Amoeba is available from their /source directory and with the application the 105SDK.patch file. Not being a command-line ace, I couldn’t even figure out how to apply the patch. Plus with 6 classes and over a thousand lines of code in its pre-patched state (I never did get the patch utility to work) PTKeyCode is overkill for my very basic needs. I could cut it down to two classes and only 379 lines of code, but still, 22 methods is excessive. It takes a concerted effort to trace back what’s going on. Simplicity is key to easy understanding, and I like to understand the code that I’m including in my applications.

My version is a category on NSString. One class method that takes a key code and any modifier flags (or zero if you want to ignore modifiers) and returns either the character, or a friendly name for the key that is defined in the mapOfNamesForUnicodeGlyphs struct in the header file.

+ (NSString *)stringForKeyCode:(unsigned short)keyCode withModifierFlags:(NSUInteger)modifierFlags
 
{
   TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
   CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
   const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
 
   if(keyboardLayout) {
      UInt32 deadKeyState = 0;
      UniCharCount maxStringLength = 255;
      UniCharCount actualStringLength = 0;
      UniChar unicodeString[maxStringLength];
 
      OSStatus status = UCKeyTranslate(keyboardLayout,
                               keyCode, kUCKeyActionDown, modifierFlags,
                               LMGetKbdType(), 0,
                               &amp;deadKeyState,
                               maxStringLength,
                               &amp;actualStringLength, unicodeString);
 
      if(status != noErr)
         NSLog(@"There was an %s error translating from the '%d' key code to a human readable string: %s",
                                 GetMacOSStatusErrorString(status), status, GetMacOSStatusCommentString(status));
      else if(actualStringLength &gt; 0) {
         // Replace certain characters with user friendly names, e.g. Space, Enter, Tab etc.
         NSUInteger i = 0;
         while(i &lt;= NumberOfUnicodeGlyphReplacements) {
            if(mapOfNamesForUnicodeGlyphs[i].glyph == unicodeString[0])
               return NSLocalizedString(([NSString stringWithFormat:@"%s", mapOfNamesForUnicodeGlyphs[i].name, nil]), @"Friendly Key Name");
 
            i++;
         }
 
         // NSLog(@"Unicode character as hexadecimal: %X", unicodeString[0]);
         return [NSString stringWithCharacters:unicodeString length:(NSInteger)actualStringLength];
      } else
         NSLog(@"Couldn't find a translation for the '%d' key code", keyCode);
   } else
      NSLog(@"Couldn't find a suitable keyboard layout from which to translate");
 
   return nil;
}

I’m not going to explain much at all. When you see it all in one place it’s hopefully not too hard to read what’s going on. The code is reasonably self documenting, although the mix of syntaxes complicates things. The difficult part was taking a series of leaps that the documentation completely fail to explain. For instance getting from a TISGetInputSourceRef to a UCKeyboardLayout is particularly tenuous.

The method itself is 41 lines of code in all, which is pretty neat considering. The source files are available here under the MIT license. It’d be nice to hear if you end up using this, maybe even an attribution in your About pane.

What it doesn’t do?

  1. It doesn’t load the keys to replace from a localizable dictionary. (like PTHotKeysLib does)
  2. It doesn’t (and could easily be modified to..) filter keyCodes before their translated, rather than after they’ve been converted to unicode characters. Useful for handling F keys.
  3. It doesn’t work with the delete/backspace key. This is particularly annoying, since I have no idea why. It should work. The hexadecimal characters match up. Maybe there is a better way to compare unicode characters than the simple ‘==’ I currently use. (See no. 2 for a easy solution)
    Now works as expected.
  4. It current only filters characters that are 1 unicode character long. In other languages, particularly asian alphabets, one key press can produce a series of unicode characters. Hopefully the value that UCKeyTranslate returns will be suitable to cover these cases.

Doubts

Bear in mind that I’m very definitely a Cocoa person and this problem is pushing at the limits of my comfort zone of C/Carbon. I think I’ve done right, but I still have doubts. Should I be retaining that CFDataRef? Why don’t the unicode character constants defined by Apple match up to the expected key presses?

I’m open to any corrections or suggestions.

Update
Fixed the link to the source files. Thanks Zac for the heads up.
Updated again, to use LMGetKbdType() instead of some other kludge that just happened to work at the time, and set deadKeyState to 0. Many thanks to Micheal Tyson for the fixes.

Cocoa, Objective-C, Source3 Responses, Add your thoughts

Categories & Tags:
By Date: