1

Is it possible to find out if a Mac is Force Touch capable - either via a built-in Trackpad, like the new MacBook, or a Bluetooth device like the Magic Trackpad 2?

I'd like to present preferences specific to Force Touch if the Mac is Force Touch capable, but not display (or disable) those preferences if Force Touch is not available.

In the portion after the separator, you see the options I have in mind in the pic linked here. (sorry, embedding the pic itself didn't work).

preferences

So, not showing the preferences wouldn't restrict users who don't have force touch, it would just let users who have it configure how it should work, and those settings would be useless to users who don't have it.

Is there a way to achieve this?

Thank you and kind regards, Matt

Edit: It's in Objective-C.

m.gansrigler
  • 185
  • 2
  • 9

1 Answers1

0

I figured it out:

+ (BOOL)isForceTouchCapable
{
    if (![[self class] isAtLeastElCapitan])
        return NO;

    io_iterator_t iterator;

    //get default HIDDevice dictionary
    CFMutableDictionaryRef mDict = IOServiceMatching(kIOHIDDeviceKey);

    //add manufacturer "Apple Inc." to dict
    CFDictionaryAddValue(mDict, CFSTR(kIOHIDManufacturerKey), CFSTR("Apple Inc."));

    //get matching services, depending on dict
    IOReturn ioReturnValue = IOServiceGetMatchingServices(kIOMasterPortDefault, mDict, &iterator);

    BOOL result = YES;
    if (ioReturnValue != kIOReturnSuccess)
        NSLog(@"error getting matching services for force touch devices");
    else
    {
        //recursively go through each device found and its children and grandchildren, etc.
        result = [[self class] _containsForceTouchDevice:iterator];
        IOObjectRelease(iterator);
    }

    return result;
}

+ (BOOL)_containsForceTouchDevice:(io_iterator_t)iterator
{
    io_object_t object = 0;
    BOOL success = NO;
    while ((object = IOIteratorNext(iterator)))
    {
        CFMutableDictionaryRef result = NULL;
        kern_return_t state = IORegistryEntryCreateCFProperties(object, &result, kCFAllocatorDefault, 0);
        if (state == KERN_SUCCESS && result != NULL)
        {
            if (CFDictionaryContainsKey(result, CFSTR("DefaultMultitouchProperties")))
            {
                CFDictionaryRef dict = CFDictionaryGetValue(result, CFSTR("DefaultMultitouchProperties"));
                CFTypeRef val = NULL;
                if (CFDictionaryGetValueIfPresent(dict, CFSTR("ForceSupported"), &val))
                {
                    Boolean aBool = CFBooleanGetValue(val);
                    if (aBool) //supported
                        success = YES;
                }
            }
        }

        if (result != NULL)
            CFRelease(result);

        if (success)
        {
            IOObjectRelease(object);
            break;
        } else
        {
            io_iterator_t childIterator = 0;
            kern_return_t err = IORegistryEntryGetChildIterator(object, kIOServicePlane, &childIterator);
            if (!err)
            {
                success = [[self class] _containsForceTouchDevice:childIterator];
                IOObjectRelease(childIterator);
            } else
                success = NO;

            IOObjectRelease(object);
        }
    }

    return success;
}

Just call + (BOOL)isForceTouchCapable and it will return YES if a Force Touch device is available (a Magic Trackpad 2 or a built in force-touch-trackpad) or NO if there isn't.

For those interested in how this came to be, I wrote about it on my blog with an example project.

m.gansrigler
  • 185
  • 2
  • 9
  • I just got the Magic Trackpad 2 (with force touch) and your code doesn't detect its presence. Have you tested on the latest version of OSX? – BitBank Feb 16 '16 at 10:45
  • Tested on 10.10.3 with an external and internal FT-capable Trackpad. Do you have IORegistryExplorer? With it, you can browse your connected devices and see if perhaps your Magic Trackpad has a different key for Force Touch? (instead of "ForceSupported") – m.gansrigler Feb 16 '16 at 16:30
  • I'm running 10.11.3 (latest). I'll check out the tool you suggested. – BitBank Feb 16 '16 at 16:47
  • oh, sorry, of course I meant 10.11.3, my apologies. – m.gansrigler Feb 16 '16 at 16:56
  • if you could report back about your findings, I'd highly appreciate it - thank you! – m.gansrigler Feb 16 '16 at 17:02