Switch from NSTimer to a CVDisplayLink to handle continuous events. NSTimer was never...
authorJoe Wreschnig <joe.wreschnig@gmail.com>
Wed, 14 Aug 2013 19:27:49 +0000 (21:27 +0200)
committerJoe Wreschnig <joe.wreschnig@gmail.com>
Wed, 14 Aug 2013 19:27:49 +0000 (21:27 +0200)
Classes/NJInputController.m
Enjoyable.xcodeproj/project.pbxproj
Info.plist

index cd665de..face5e7 100644 (file)
 #import "NJOutput.h"
 #import "NJEvents.h"
 
+#import <CoreVideo/CoreVideo.h>
+
+@interface NJInputController ()
+
+- (void)updateContinuousOutputs;
+
+@end
+
+static CVReturn displayLink_update_cb(CVDisplayLinkRef displayLink,
+                                          const CVTimeStamp *inNow,
+                                          const CVTimeStamp *inOutputTime,
+                                          CVOptionFlags flagsIn,
+                                          CVOptionFlags *flagsOut,
+                                          void *ctxManager) {
+    NJInputController *manager = (__bridge NJInputController *)ctxManager;
+    [manager performSelectorOnMainThread:@selector(updateContinuousOutputs)
+                              withObject:nil
+                           waitUntilDone:NO];
+    return kCVReturnSuccess;
+}
+
 @implementation NJInputController {
     NJHIDManager *_HIDManager;
-    NSTimer *_continuousOutputsTick;
     NSMutableArray *_continousOutputs;
     NSMutableArray *_devices;
     NSMutableArray *_mappings;
     NJMapping *_manualMapping;
+    CVDisplayLinkRef displayLink;
 
 }
 
     if ((self = [super init])) {
         _devices = [[NSMutableArray alloc] initWithCapacity:16];
         _continousOutputs = [[NSMutableArray alloc] initWithCapacity:32];
+
+        CVReturn error = CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
+        if (error) {
+            [self.delegate inputController:self
+                                  didError:[NSError errorWithDomain:NSCocoaErrorDomain
+                                                               code:error
+                                                           userInfo:nil]];
+            NSLog(@"DisplayLink failed creation with error: %d.", error);
+            displayLink = NULL;
+        }
+        CVDisplayLinkSetOutputCallback(displayLink, displayLink_update_cb, (__bridge void *)self);
         
         _HIDManager = [[NJHIDManager alloc] initWithCriteria:@[
                        @{ NSSTR(kIOHIDDeviceUsagePageKey) : @(kHIDPage_GenericDesktop),
 
 - (void)dealloc {
     [NSNotificationCenter.defaultCenter removeObserver:self];
-    [_continuousOutputsTick invalidate];
+    if (displayLink) {
+        CVDisplayLinkStop(displayLink);
+        CVDisplayLinkRelease(displayLink);
+    }
 }
 
 - (void)addRunningOutput:(NJOutput *)output {
     // re-adding them or they trigger multiple times each time.
     if (![_continousOutputs containsObject:output])
         [_continousOutputs addObject:output];
-    if (!_continuousOutputsTick) {
-        _continuousOutputsTick = [NSTimer scheduledTimerWithTimeInterval:1.0/60.0
-                                                           target:self
-                                                         selector:@selector(updateContinuousOutputs:)
-                                                         userInfo:nil
-                                                          repeats:YES];
+    if (displayLink && !CVDisplayLinkIsRunning(displayLink)) {
+        CVDisplayLinkStart(displayLink);
     }
 }
 
     }
 }
 
-- (void)updateContinuousOutputs:(NSTimer *)timer {
+- (void)updateContinuousOutputs {
     self.mouseLoc = [NSEvent mouseLocation];
     for (NJOutput *output in [_continousOutputs copy]) {
         if (![output update:self]) {
             [_continousOutputs removeObject:output];
         }
     }
-    if (!_continousOutputs.count) {
-        [_continuousOutputsTick invalidate];
-        _continuousOutputsTick = nil;
+    if (!_continousOutputs.count && displayLink) {
+        CVDisplayLinkStop(displayLink);
     }
 }
 
 - (void)HIDManager:(NJHIDManager *)manager didError:(NSError *)error {
     [self.delegate inputController:self didError:error];
     self.simulatingEvents = NO;
+    if (displayLink)
+        CVDisplayLinkStop(displayLink);
 }
 
 - (void)HIDManagerDidStart:(NJHIDManager *)manager {
 
 - (void)HIDManagerDidStop:(NJHIDManager *)manager {
     [_devices removeAllObjects];
+    if (displayLink)
+        CVDisplayLinkStop(displayLink);
     [self.delegate inputControllerDidStopHID:self];
 }
 
index 8e9a213..c6b1cd9 100644 (file)
@@ -10,6 +10,7 @@
                8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
                D594BF000FAE7397007A85F2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D594BEFF0FAE7397007A85F2 /* IOKit.framework */; };
                EE1F3CEA16EF4182008C6426 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = EE1F3CE816EF4182008C6426 /* Localizable.strings */; };
+               EE35A6E417BBCC9500413995 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE35A6E317BBCC9500413995 /* CoreVideo.framework */; };
                EE3D897A16EA7EFC00596D1F /* Status Menu Icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = EE3D897916EA7EFC00596D1F /* Status Menu Icon@2x.png */; };
                EE3D897C16EA806E00596D1F /* Status Menu Icon Disabled@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = EE3D897B16EA806E00596D1F /* Status Menu Icon Disabled@2x.png */; };
                EE3D897F16EA817E00596D1F /* Status Menu Icon Disabled.png in Resources */ = {isa = PBXBuildFile; fileRef = EE3D897D16EA817E00596D1F /* Status Menu Icon Disabled.png */; };
@@ -77,6 +78,7 @@
                8D1107320486CEB800E47090 /* Enjoyable.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Enjoyable.app; sourceTree = BUILT_PRODUCTS_DIR; };
                D594BEFF0FAE7397007A85F2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
                EE1F3CE916EF4182008C6426 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = Resources/English.lproj/Localizable.strings; sourceTree = "<group>"; };
+               EE35A6E317BBCC9500413995 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
                EE3D897916EA7EFC00596D1F /* Status Menu Icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Status Menu Icon@2x.png"; path = "Resources/Status Menu Icon@2x.png"; sourceTree = "<group>"; };
                EE3D897B16EA806E00596D1F /* Status Menu Icon Disabled@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Status Menu Icon Disabled@2x.png"; path = "Resources/Status Menu Icon Disabled@2x.png"; sourceTree = "<group>"; };
                EE3D897D16EA817E00596D1F /* Status Menu Icon Disabled.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Status Menu Icon Disabled.png"; path = "Resources/Status Menu Icon Disabled.png"; sourceTree = "<group>"; };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               EE35A6E417BBCC9500413995 /* CoreVideo.framework in Frameworks */,
                                8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
                                D594BF000FAE7397007A85F2 /* IOKit.framework in Frameworks */,
                                EED4CE7716EE195100C65AA8 /* Sparkle.framework in Frameworks */,
                29B97314FDCFA39411CA2CEA /* Enjoy */ = {
                        isa = PBXGroup;
                        children = (
+                               EE35A6E317BBCC9500413995 /* CoreVideo.framework */,
                                8D1107310486CEB800E47090 /* Info.plist */,
                                080E96DDFE201D6D7F000001 /* Classes */,
                                EE1D5F8B16E403D600749C36 /* Categories */,
index d480f07..9917f03 100644 (file)
@@ -46,7 +46,7 @@
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>583</string>
+       <string>598</string>
        <key>LSApplicationCategoryType</key>
        <string>public.app-category.utilities</string>
        <key>NSHumanReadableCopyright</key>