How To: Force Touch-fähige Geräte (Magic Trackpad 2, z.B.) am Mac erkennen

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

Macoun 2019 - Frühbucherrabatt bis 26.7.2019

  • How To: Force Touch-fähige Geräte (Magic Trackpad 2, z.B.) am Mac erkennen

    Hallo, Leute.

    Nachdem ich es geschafft habe, Force Clicks in NSTableViews zu erkennen (siehe Foren-Eintrag hier), habe ich mich nun daran gemacht, zu erkennen, ob ein Force Touch fähiges Trackpad überhaupt gerade am Mac verfügbar ist.

    Mit Hilfe von IOKit ist es möglich. Unter iOS gibt es ja UIForceTouchCapability - am Mac muss man selber Hand anlegen.

    So sieht das Herz des Codes aus:

    C-Quellcode

    1. /*
    2. SOURCE CODE LICENSE
    3. 1) You can use the code in your own products.
    4. 2) You can modify the code as you wish, and use the modified code in your products.
    5. 3) You can redistribute the original, unmodified code, but you have to include the full license text below.
    6. 4) You can redistribute the modified code as you wish (without the full license text below).
    7. 5) In all cases, you must include a credit mentioning Matthias Gansrigler as the original author of the source.
    8. 6) I’m not liable for anything you do with the code, no matter what. So be sensible.
    9. 7) You can’t use my name or other marks to promote your products based on the code.
    10. 8) If you agree to all of that, go ahead and download the source. Otherwise, don’t.
    11. Contact: Matthias Gansrigler || opensource@eternalstorms.at || http://eternalstorms.at || @eternalstorms on twitter
    12. This NSApplication Category is available on Github at: https://github.com/eternalstorms/NSBeginAlertSheet-using-Blocks
    13. */
    14. + (BOOL)isForceTouchCapable
    15. {
    16. if (![[self class] isAtLeastElCapitan])
    17. return NO;
    18. io_iterator_t iterator;
    19. //get default HIDDevice dictionary
    20. CFMutableDictionaryRef mDict = IOServiceMatching(kIOHIDDeviceKey);
    21. //add manufacturer "Apple Inc." to dict
    22. CFDictionaryAddValue(mDict, CFSTR(kIOHIDManufacturerKey), CFSTR("Apple Inc."));
    23. //get matching services, depending on dict
    24. IOReturn ioReturnValue = IOServiceGetMatchingServices(kIOMasterPortDefault, mDict, &iterator);
    25. BOOL result = YES;
    26. if (ioReturnValue != kIOReturnSuccess)
    27. NSLog(@"error getting matching services for force touch devices");
    28. else
    29. {
    30. //recursively go through each device found and its children and grandchildren, etc.
    31. result = [[self class] _containsForceTouchDevice:iterator];
    32. IOObjectRelease(iterator);
    33. }
    34. return result;
    35. }
    36. + (BOOL)_containsForceTouchDevice:(io_iterator_t)iterator
    37. {
    38. io_object_t object = 0;
    39. BOOL success = NO;
    40. while ((object = IOIteratorNext(iterator)))
    41. {
    42. CFMutableDictionaryRef result = NULL;
    43. kern_return_t state = IORegistryEntryCreateCFProperties(object, &result, kCFAllocatorDefault, 0);
    44. if (state == KERN_SUCCESS && result != NULL)
    45. {
    46. if (CFDictionaryContainsKey(result, CFSTR("DefaultMultitouchProperties")))
    47. {
    48. CFDictionaryRef dict = CFDictionaryGetValue(result, CFSTR("DefaultMultitouchProperties"));
    49. CFTypeRef val = NULL;
    50. if (CFDictionaryGetValueIfPresent(dict, CFSTR("ForceSupported"), &val))
    51. {
    52. Boolean aBool = CFBooleanGetValue(val);
    53. if (aBool) //supported
    54. success = YES;
    55. }
    56. }
    57. }
    58. if (result != NULL)
    59. CFRelease(result);
    60. if (success)
    61. {
    62. IOObjectRelease(object);
    63. break;
    64. } else
    65. {
    66. io_iterator_t childIterator = 0;
    67. kern_return_t err = IORegistryEntryGetChildIterator(object, kIOServicePlane, &childIterator);
    68. if (!err)
    69. {
    70. success = [[self class] _containsForceTouchDevice:childIterator];
    71. IOObjectRelease(childIterator);
    72. } else
    73. success = NO;
    74. IOObjectRelease(object);
    75. }
    76. }
    77. return success;
    78. }
    Alles anzeigen
    Damit kann man einfach +(BOOL)isForceTouchCapable aufrufen und YES oder NO zurückerhalten.

    Für mich war der Sinn dahinter, dass ich Force Touch-Einstellungen anzeigen möchte - aber auch nur dann, wenn auch ein Force Touch-fähiges Trackpad am Mac angeschlossen ist.

    Einen detaillierteren Post gibt es auf meinem Blog - zusammen mit einem Example Project (Direkt-Download) :)

    Ich hoffe, es nützt euch auch :)

    Liebe Grüße und Happy Coding,
    Matthias
    Matthias Gansrigler | Eternal Storms Software
    Folge mir auf Twitter | Facebook | Blog
  • Mac & i Test Abo
  • In diesem Fall zeige ich die Force Touch Einstellungen an. Also sobald die Software erkennt, dass eines verfügbar ist, zeige ich die Einstellungen. Vielleicht entscheidet sich der Benutzer ja dann, doch das Force Touch-Trackpad zu verwenden, da hast du recht ;)
    Matthias Gansrigler | Eternal Storms Software
    Folge mir auf Twitter | Facebook | Blog

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von m.gansrigler ()

  • Schönes Snippet, danke.

    Vielleicht als Feedback / Verbesserungsvorschlag: Um nach einem bestimmten Hersteller zu suchen ist es meistens sinnvoller, nach Vendor ID zu filtern. Die ist zuverlässiger als der String - der Manufacturer String ist optional, kann lokalisiert sein und sich nach Lust und Laune des Herstellers ändern. Aber warum muss überhaupt nach Hersteller gefiltert werden? Vielleicht gibt's ja demnächst auch Force Touch von Drittherstellern. Oder gab's ohne den Filter Probleme?

    Edit: Keine Ahnung, wie das mit der Vendor ID bei kabellosen Geräten ist. Müsste man mal gucken.
    Multigrad - 360°-Produktfotografie für den Mac
  • Hab mir die vendor ID angesehen - die ist bei internen und externen Force Touch-fähigen Trackpads unterschiedlich - warum auch immer Oo...
    Deshalb filtere ich nach Apple Inc., das ist bei beiden gleich. Aber man könnte es eigentlich auch komplett weglassen. Der Unterschied in der Dauer der Methode liegt bei 0.2 Sekunden (bei mir, zumindest), wenn man nicht nach Manufacturer filtert.
    Matthias Gansrigler | Eternal Storms Software
    Folge mir auf Twitter | Facebook | Blog