Developing Xcode 4 Plugins

This is a quick guide that documents how to start developing plugins for Xcode4. You need to have Xcode installed to create plugins.

Step 1 – Xcode Plugin Project Template

  • Grab the Xcode project template for creating plugins from here
  • Create the plugin template folder ~/Library/Developer/Xcode/Templates/Project Templates/Application Plug-in/Xcode4 Plugin.xctemplate if it doesn’t already exist.
  • A quick way to do this is with the following command mkdir -p "~/Library/Developer/Xcode/Templates/Project Templates/Application Plug-in/Xcode4 Plugin.xctemplate"
  • Copy the contents of the GitHub repository to the folder you just created.
  • Restart Xcode.

Step 2 – Create a test project

  • Open Xcode, and select File > New > Project
  • Then under OS X > Templates tap Xcode4 Plugin (shown below)

Screen Shot 2013-04-29 at 3.44.05 PM

From the GitHub repo:

The default plugin file links against AppKit and Foundation, and, when built 
(and Xcode is restarted), creates a menu item labeled "Do Action" in the File menu. 
Pressing the menu item should open an alert. Customize at will!

If we run the project we just created, it will automatically build and copy the plugin to the right location. In this case it is ~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/[Project Name].xcplugin. Restarting Xcode, we get a new menu item under the File menu!

Screen Shot 2013-04-29 at 3.53.02 PM

When we click on the menu item, we get an alert:

Screen Shot 2013-04-29 at 3.53.49 PM

Notes:

  • Xcode plugins have to be written using Objective-C GC, this means you have to use retain and release calls in your code. (No ARC support).

Where to go from here?

  • This StackOverflow answer has some great ideas on where to go next.
  • You can get a dump of the private headers that Xcode uses by using the class-dump tool
  • brew install class-dump is the quickest way to get it if you have homebrew installed.
  • IDEKit and IDEFoundation are present at Xcode.app/Contents/Frameworks
  • DVTKit and DVTFoundation are present at Xcode.app/Contents/SharedFrameworks
  • By registering an observer for nil you can see all the notifications that are being called. This is useful to find out which actions are called and when, and what notifications you might need to listen for.

Setting up Kinect on OSX the easy way

Open Terminal

Install homebrew with the following command

/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)" 

Make sure homebrew is up to date with

sudo brew update

Change directory to your brew home folder with


cd /usr/local/Library/Formula
curl --insecure -O "https://raw.github.com/OpenKinect/libfreenect/master/platform/osx/homebrew/libfreenect.rb"
curl --insecure -O "https://raw.github.com/OpenKinect/libfreenect/master/platform/osx/homebrew/libusb-freenect.rb"

brew install libfreenect

glview

GlView showing kinect depth view

Listening for Global Keypresses in OSX.

While working on some new projects recently, I found it difficult to find any good information about how to listen for global keypresses in OSX using a mix of objective-c++ and c. The following code is the result of several hours of searching and frustration, hopefully it can save someone else the same pain.

The method I used to listen for global keypresses is using Event Taps from the Quartz framework. The user must either run this code as root, or have enabled access for assistive devices.

#include <ApplicationServices/ApplicationServices.h>
CGEventRef
myCGEventCallback(CGEventTapProxy proxy, CGEventType type,
                  CGEventRef event, void *refcon)
{
    // Paranoid sanity check.
    if ((type != kCGEventKeyDown) && (type != kCGEventKeyUp))
        return event;

    // The incoming keycode.
    CGKeyCode keycode = (CGKeyCode)CGEventGetIntegerValueField(
                                       event, kCGKeyboardEventKeycode);

    //Keypress code goes here.

    // We must return the event for it to be useful.
    return event;
}

int
main(void)
{
    CFMachPortRef      eventTap;
    CGEventMask        eventMask;
    CFRunLoopSourceRef runLoopSource;

    // Create an event tap. We are interested in key presses.
    eventMask = ((1 << kCGEventKeyDown) | (1 << kCGEventKeyUp));
    eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0,
                                eventMask, myCGEventCallback, NULL);
    if (!eventTap) {
        fprintf(stderr, "failed to create event tap\n");
        exit(1);
    }   

    // Create a run loop source.
    runLoopSource = CFMachPortCreateRunLoopSource(
                        kCFAllocatorDefault, eventTap, 0);

    // Add to the current run loop.
    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource,
                       kCFRunLoopCommonModes);

    // Enable the event tap.
    CGEventTapEnable(eventTap, true);

    // Set it all running.
    CFRunLoopRun();

    exit(0);
}

Compile the above code either using Xcode or GCC with the following –

gcc -Wall -o globalkeypress globalkeypress.c -framework ApplicationServices

In the next couple of days I will upload some code that shows how to move the mouse and simulate mouse clicks.