Adonit Jot Touch 4 Support for Brushes iPad App

And now for something completely different…

With the announcement of Adobe’s teaming up with Adonit to help manufacture and ship Mighty & Napolean in the first half of 2014, I thought it might be a good idea to start getting my head wrapped around how all this technology works.

I recently heard a great interview with British artist David Hockney about the incredible art he is creating on the iPad.  Unfortunately, I wasn’t able to make it out to his “A Bigger Exhibition” at the de Young museum in San Francisco, which just ended. One thing that did catch my attention in the interview though, was his mention of an app called Brushes that he uses to create his art:

image2

 

Those are just my scribblings.  Not to be confused with anything closely resembling art.

Upon further investigation, I discovered that the Brushes app is in fact open source and available on GitHub.  Brushes as it currently stands, supports the Pogo Connect pen.

In order to give myself a  good project to learn more about the Adonit Jot SDK, I forked the Brushes app and added support for the Adonit Jot Touch 4 stylus. It turned out to be much more straightforward than expected, once I got my head around the Brushes source code. You can find the results here on GitHub.  It’s probably not quite ready to be merged back into the original Brushes app, but it’s definitely a great start.

If you’re interested in what exactly I did, keep reading…

Installing the Jot Touch SDK

After cloning the Jot Touch SDK from GitHub, I copied the JotTouchSDK.framework folder to the Brushes app folder and then opened Brushes.xcodeproj. Then, I followed the instructions in the Jot Touch SDK Getting Started Guide to import the Jot Touch SDK into the app. Just read the guide for that.  There’s no reason for me to repeat some very good documentation.  The two main steps to cover are:

  • Link your project with the CoreMotion.framework, CoreBluetooth.framework and JotTouchSDK.framework frameworks
  • Add ‘-ObjC’ to the Other Linker Flags

I did have to make two minor tweaks to the Brushes app to get it to compile:

I was getting a “No newline at end of file” for JotStylusManager.h.  Rather than changing the code, I just changed the Build Setting ‘Missing Newline at End of File’ to ‘No’:

Screen Shot 2014-01-20 at 2.56.53 AM

As well, there was a minor issue in WDAddPath, line 141:

WDLog(@"Empty path bounds with path of length %d", [path.nodes count]);

had to be changed to:

WDLog(@"Empty path bounds with path of length %lu", (unsigned long)[path.nodes count]);

to prevent a casting error.

Defining a New Type of Stylus

WDStylusManager.h defines an enum ‘WDStylusType’ which originally supported WDNoStylus and WDPogoConnectStylus.  I added WDJotTouchStylus:

// Jot Touch 4
#import <JotTouchSDK/JotStylusManager.h> 

typedef enum {
    WDNoStylus = 0,
    WDPogoConnectStylus,
    WDJotTouchStylus,
    WDMaxStylusTypes
} WDStylusType;

I also defined a new stylus manager specifically for the Jot Touch:

@property (nonatomic) JotStylusManager *jotManager;

Then, in WDStylusManager.m, I needed to synthesize the jotManager:

@synthesize jotManager;

Displaying Pen Status

The Brushes app allows you to see the current stylus connection status and battery level:

image

 

In order to provide that information, the dataForStylusType method needed support for the Jot:

    ...
    } else if (type == WDJotTouchStylus) {
        data.productName = NSLocalizedString(@"Jot Touch", @"Jot Touch");
        data.connected = (jotManager.connectionStatus == JotConnectionStatusConnected);
        data.batteryLevel = @(jotManager.batteryLevel / 100.0f);
    }

The Brushes app expects a battery level between 0.0 and 1.0.  The jotManager’s batteryLevel ranges from 0.0 to 100.0 and has to be scaled appropriately.

Supplying Brushes with Pressure Data

One of the great things that separates a stylus from simply your finger for example, is the ability of the stylus to tell the app exactly how much pressure the user is exerting on the display so the app can react appropriately. In order to supply the Brushes app with that information, I had to add Jot support in the pressureForTouch method.

I tried turning the actual touch passed into the method into a JotTouch, and then getting the pressure from that, but that didn’t seem to work for some reason, so I ended up just retrieving the current pressure directly as shown below:

- (float) pressureForTouch:(UITouch *)touch realPressue:(BOOL *)isRealPressure
{
    float   pressure = 1.0f;
    BOOL    isReal = NO;

    if ((mode == WDPogoConnectStylus) && [pogoManager oneOrMorePensAreConnected]) {
        isReal = YES;
        pressure = [pogoManager pressureForTouch:touch];
    } else if ((mode == WDJotTouchStylus) && ([jotManager connectionStatus] == JotConnectionStatusConnected)) {
        isReal = YES;
        pressure = [jotManager getPressure] / 2047.0f;
    } else if (mode != WDNoStylus) {
        isReal = YES;
        // since we're in stylus mode, but no styli are active, use 1.0 pressure
    }

    if (isRealPressure) {
        *isRealPressure = isReal;
    }

    return pressure;
}

The Brushes app expects the pressure value to range from 0.0 to 1.0.  The jotManager returns values from 0.0 to 2047.0 so they have to be scaled appropriately.

Listening for Connect/Disconnect Events

Finally, we need to listen for Jot connect/disconnect events and tell the app when these events occur so it can update the display appropriately.

When the Bluetooth state is set in setBlueToothState, if the Bluetooth is on (blueToothState == WDBlueToothLowEnergy), we initialize the jotManager and listen for connection status changes:

- (void) setBlueToothState:(WDBlueToothState)inBlueToothState
{
    if (inBlueToothState == blueToothState) {
        return;
    }

    blueToothState = inBlueToothState;

    if (blueToothState == WDBlueToothLowEnergy) {
        if (!pogoManager) {
            pogoManager = [T1PogoManager pogoManagerWithDelegate:self];
            pogoManager.enablePenInputOverNetworkIfIncompatiblePad = YES;
        }

        if (!jotManager) {
            jotManager = [JotStylusManager sharedInstance];

            [[NSNotificationCenter defaultCenter] 
                addObserver: self
                selector:@selector(jotConnectionChange:)
                name: JotStylusManagerDidChangeConnectionStatus
                object:nil];
            jotManager.rejectMode = NO;
            jotManager.enabled = YES;
        }
    }

    [[NSNotificationCenter defaultCenter] postNotificationName:WDBlueToothStateChangedNotification object:self];
}

This will call jotConnectionChange whenever there is a change to the connection status.  jotConnectionChange is then defined as follows:

- (void)jotConnectionChange:(NSNotification *) note
{
    switch([[JotStylusManager sharedInstance] connectionStatus])
    {
        case JotConnectionStatusOff:
            break;
        case JotConnectionStatusScanning:
            break;
        case JotConnectionStatusPairing:
            break;
        case JotConnectionStatusConnected:
            [self didConnectStylus:NSLocalizedString(@"Jot Touch", @"Jot Touch")];
            break;
        case JotConnectionStatusDisconnected:
            [self didDisconnectStylus:NSLocalizedString(@"Jot Touch", @"Jot Touch")];
            break;
        default:
            break;
    }
}

And that’s really all I had to do.  The only other issue I had was getting the Jot Touch 4 stylus to connect with the iPad the first time.  I kept getting JotConnectionStatusPairing notices, followed by JotConnectionStatusDisconnected notices. I finally realized that the JotConnectionStatusPairing notice was telling me that it was waiting for me to draw on the iPad to confirm that I wanted to pair my device.  Once I did that, it connected just fine, and I never needed to do it again.  The device just connects automatically when I start the app.

Next Steps

The Jot Touch SDK can send you drawing and palm rejection events.  The latter can be used to ignore events generated by your palm resting on the iPad as you draw.

In the meantime, have a play around with it and let me know what you think.

Tagged , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *