//
-// NJDeviceController.m
-// Enjoy
-//
-// Created by Sam McCall on 4/05/09.
+// NJInputController.m
+// Enjoyable
//
#import "NJInputController.h"
#import "NJOutput.h"
#import "NJEvents.h"
+#import <CoreVideo/CoreVideo.h>
+
+@interface NJInputController ()
+
+- (void)updateContinuousOutputs;
+
+@end
+
+static CVReturn _updateDL(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;
+ NJHIDManager *_HIDManager;
NSMutableArray *_continousOutputs;
NSMutableArray *_devices;
NSMutableArray *_mappings;
NJMapping *_manualMapping;
-
+ CVDisplayLinkRef _displayLink;
}
#define NSSTR(e) ((NSString *)CFSTR(e))
if ((self = [super init])) {
_devices = [[NSMutableArray alloc] initWithCapacity:16];
_continousOutputs = [[NSMutableArray alloc] initWithCapacity:32];
+
+ CVReturn cvErr = CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink);
+ if (cvErr) {
+ NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain
+ code:cvErr
+ userInfo:nil];
+ [self.delegate inputController:self didError:error];
+ NSLog(@"DisplayLink failed creation with error: %@", error);
+ _displayLink = NULL;
+ }
+ CVDisplayLinkSetOutputCallback(_displayLink, _updateDL, (__bridge void *)self);
- _hidManager = [[NJHIDManager alloc] initWithCriteria:@[
+ _HIDManager = [[NJHIDManager alloc] initWithCriteria:@[
@{ NSSTR(kIOHIDDeviceUsagePageKey) : @(kHIDPage_GenericDesktop),
NSSTR(kIOHIDDeviceUsageKey) : @(kHIDUsage_GD_Joystick) },
@{ 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)runOutputForDevice:(IOHIDDeviceRef)device value:(IOHIDValueRef)value {
if (!handler)
return;
- [self.delegate deviceController:self didInput:handler];
+ [self.delegate inputController:self didInput:handler];
}
-- (void)hidManager:(NJHIDManager *)manager
+- (void)HIDManager:(NJHIDManager *)manager
valueChanged:(IOHIDValueRef)value
fromDevice:(IOHIDDeviceRef)device {
if (self.simulatingEvents
[_devices addObject:device];
}
-- (void)hidManager:(NJHIDManager *)manager deviceAdded:(IOHIDDeviceRef)device {
+- (void)HIDManager:(NJHIDManager *)manager deviceAdded:(IOHIDDeviceRef)device {
NJDevice *match = [[NJDevice alloc] initWithDevice:device];
[self addDevice:match];
- [self.delegate deviceController:self didAddDevice:match];
+ [self.delegate inputController:self didAddDevice:match];
}
- (NJDevice *)findDeviceByRef:(IOHIDDeviceRef)device {
return nil;
}
-- (void)hidManager:(NJHIDManager *)manager deviceRemoved:(IOHIDDeviceRef)device {
+- (void)HIDManager:(NJHIDManager *)manager deviceRemoved:(IOHIDDeviceRef)device {
NJDevice *match = [self findDeviceByRef:device];
if (match) {
NSInteger idx = [_devices indexOfObjectIdenticalTo:match];
[_devices removeObjectAtIndex:idx];
- [self.delegate deviceController:self didRemoveDeviceAtIndex:idx];
+ [self.delegate inputController:self didRemoveDeviceAtIndex:idx];
}
}
-- (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 deviceController:self didError:error];
+- (void)HIDManager:(NJHIDManager *)manager didError:(NSError *)error {
+ [self.delegate inputController:self didError:error];
self.simulatingEvents = NO;
+ if (_displayLink)
+ CVDisplayLinkStop(_displayLink);
}
-- (void)hidManagerDidStart:(NJHIDManager *)manager {
- [self.delegate deviceControllerDidStartHID:self];
+- (void)HIDManagerDidStart:(NJHIDManager *)manager {
+ [self.delegate inputControllerDidStartHID:self];
}
-- (void)hidManagerDidStop:(NJHIDManager *)manager {
+- (void)HIDManagerDidStop:(NJHIDManager *)manager {
[_devices removeAllObjects];
- [self.delegate deviceControllerDidStopHID:self];
+ if (_displayLink)
+ CVDisplayLinkStop(_displayLink);
+ [self.delegate inputControllerDidStopHID:self];
}
- (void)startHid {
- [_hidManager start];
+ [_HIDManager start];
}
- (void)stopHid {
- [_hidManager stop];
+ [_HIDManager stop];
}
- (void)setSimulatingEvents:(BOOL)simulatingEvents {
- (void)mappingsSet {
[self postLoadProcess];
[NSNotificationCenter.defaultCenter
- postNotificationName:NJEventMappingListChanged
- object:self
- userInfo:@{ NJMappingListKey: _mappings,
- NJMappingKey: _currentMapping }];
+ postNotificationName:NJEventMappingListChanged
+ object:self
+ userInfo:@{ NJMappingListKey: _mappings,
+ NJMappingKey: _currentMapping }];
}
- (void)mappingsChanged {
if ([oldMapping.name.lowercaseString isEqualToString:@"@application"]
|| [oldMapping.name.lowercaseString isEqualToString:
NSLocalizedString(@"@Application", nil).lowercaseString]) {
- oldMapping.name = app.bestMappingName;
- [self mappingsChanged];
+ [self renameMapping:oldMapping to:app.bestMappingName];
}
}
_manualMapping = oldMapping;
_currentMapping = mapping;
NSUInteger idx = [self indexOfMapping:_currentMapping];
[NSNotificationCenter.defaultCenter
- postNotificationName:NJEventMappingChanged
- object:self
- userInfo:@{ NJMappingKey : _currentMapping,
- NJMappingIndexKey: @(idx) }];
+ postNotificationName:NJEventMappingChanged
+ object:self
+ userInfo:@{ NJMappingKey : _currentMapping,
+ NJMappingIndexKey: @(idx) }];
}
- (void)activateMapping:(NJMapping *)mapping {