From 6a7c78afa7b8a34901f59a79afe41d18855734bc Mon Sep 17 00:00:00 2001 From: Joe Wreschnig Date: Wed, 20 Mar 2013 20:02:35 +0100 Subject: [PATCH] App delegate now controls communication between device / mapping controllers and view controllers. --- Classes/EnjoyableApplicationDelegate.h | 8 +++ Classes/EnjoyableApplicationDelegate.m | 71 ++++++++++++++++++++++++++ Classes/NJDeviceController.h | 26 +++++++--- Classes/NJDeviceController.m | 64 ++++++----------------- Classes/NJDeviceViewController.h | 9 ++-- Classes/NJDeviceViewController.m | 20 +++----- Classes/NJMappingsController.m | 38 ++++++-------- Classes/NJOutputController.h | 5 +- Classes/NJOutputController.m | 15 +++--- Info.plist | 2 +- Resources/English.lproj/MainMenu.xib | 56 ++++++++++++-------- 11 files changed, 188 insertions(+), 126 deletions(-) diff --git a/Classes/EnjoyableApplicationDelegate.h b/Classes/EnjoyableApplicationDelegate.h index dbc17ee..52869f2 100644 --- a/Classes/EnjoyableApplicationDelegate.h +++ b/Classes/EnjoyableApplicationDelegate.h @@ -10,8 +10,13 @@ #import "NJMappingMenuController.h" #import "NJMappingsViewController.h" +#import "NJDeviceViewController.h" +#import "NJOutputController.h" +#import "NJDeviceController.h" @interface EnjoyableApplicationDelegate : NSObject { @@ -21,7 +26,10 @@ } @property (nonatomic, strong) IBOutlet NJMappingsController *mappingsController; +@property (nonatomic, strong) IBOutlet NJDeviceController *deviceController; +@property (nonatomic, strong) IBOutlet NJOutputController *outputController; @property (nonatomic, strong) IBOutlet NJMappingsViewController *mvc; +@property (nonatomic, strong) IBOutlet NJDeviceViewController *dvc; - (IBAction)restoreToForeground:(id)sender; - (IBAction)importMappingClicked:(id)sender; diff --git a/Classes/EnjoyableApplicationDelegate.m b/Classes/EnjoyableApplicationDelegate.m index bf2a336..ca641f7 100644 --- a/Classes/EnjoyableApplicationDelegate.m +++ b/Classes/EnjoyableApplicationDelegate.m @@ -386,4 +386,75 @@ [self.mappingsController activateMapping:self.mappingsController[idx]]; } +- (id)deviceViewController:(NJDeviceViewController *)dvc + elementForUID:(NSString *)uid { + return self.deviceController[uid]; +} + +- (void)deviceViewControllerDidSelectNothing:(NJDeviceViewController *)dvc { + [self.outputController loadInput:dvc.selectedHandler]; +} + +- (void)deviceViewController:(NJDeviceViewController *)dvc + didSelectBranch:(NJInputPathElement *)handler { + [self.outputController loadInput:dvc.selectedHandler]; +} + +- (void)deviceViewController:(NJDeviceViewController *)dvc + didSelectHandler:(NJInputPathElement *)handler { + [self.outputController loadInput:dvc.selectedHandler]; +} + +- (void)deviceViewController:(NJDeviceViewController *)dvc + didSelectDevice:(NJInputPathElement *)device { + [self.outputController loadInput:dvc.selectedHandler]; +} + +- (void)deviceController:(NJDeviceController *)dc + didAddDevice:(NJDevice *)device { + [self.dvc addedDevice:device atIndex:dc.count - 1]; +} + +- (void)deviceController:(NJDeviceController *)dc + didRemoveDeviceAtIndex:(NSInteger)idx { + [self.dvc removedDeviceAtIndex:idx]; +} + +- (void)deviceControllerDidStartHID:(NJDeviceController *)dc { + [self.dvc hidStarted]; +} + +- (void)deviceControllerDidStopHID:(NJDeviceController *)dc { + [self.dvc hidStopped]; +} + +- (void)deviceController:(NJDeviceController *)dc didInput:(NJInput *)input { + [self.outputController loadInput:input]; + [self.outputController focusKey]; +} + +- (void)deviceController:(NJDeviceController *)dc didError:(NSError *)error { + // Since the error shows the window, it can trigger another attempt + // to re-open the HID manager, which will also probably fail and error, + // so don't bother repeating ourselves. + if (!window.attachedSheet) { + [NSApplication.sharedApplication activateIgnoringOtherApps:YES]; + [window makeKeyAndOrderFront:nil]; + [window presentError:error + modalForWindow:window + delegate:nil + didPresentSelector:nil + contextInfo:nil]; + } +} + +- (NSInteger)numberOfDevicesInDeviceList:(NJDeviceViewController *)dvc { + return self.deviceController.count; +} + +- (NJDevice *)deviceViewController:(NJDeviceViewController *)dvc + deviceForIndex:(NSUInteger)idx { + return self.deviceController[idx]; +} + @end diff --git a/Classes/NJDeviceController.h b/Classes/NJDeviceController.h index 29b8b38..3691d59 100644 --- a/Classes/NJDeviceController.h +++ b/Classes/NJDeviceController.h @@ -11,20 +11,34 @@ @class NJInput; @class NJMappingsController; -@class NJOutputController; -@interface NJDeviceController : NSObject { - IBOutlet NJOutputController *outputController; +@protocol NJDeviceControllerDelegate; + +@interface NJDeviceController : NSObject { IBOutlet NJMappingsController *mappingsController; IBOutlet NSButton *simulatingEventsButton; - IBOutlet NJDeviceViewController *devicesViewController; } -@property (nonatomic, readonly) NJInput *selectedInput; +@property (nonatomic, weak) IBOutlet id delegate; + @property (nonatomic, assign) NSPoint mouseLoc; @property (nonatomic, assign) BOOL simulatingEvents; - (IBAction)simulatingEventsChanged:(NSButton *)sender; +- (NJDevice *)objectAtIndexedSubscript:(NSUInteger)idx; +- (NJInputPathElement *)objectForKeyedSubscript:(NSString *)uid; +- (NSUInteger)count; + +@end + +@protocol NJDeviceControllerDelegate + +- (void)deviceController:(NJDeviceController *)dc didAddDevice:(NJDevice *)device; +- (void)deviceController:(NJDeviceController *)dc didRemoveDeviceAtIndex:(NSInteger)idx; +- (void)deviceController:(NJDeviceController *)dc didInput:(NJInput *)input; +- (void)deviceControllerDidStartHID:(NJDeviceController *)dc; +- (void)deviceControllerDidStopHID:(NJDeviceController *)dc; +- (void)deviceController:(NJDeviceController *)dc didError:(NSError *)error; + @end diff --git a/Classes/NJDeviceController.m b/Classes/NJDeviceController.m index bdd1bbf..23a0932 100644 --- a/Classes/NJDeviceController.m +++ b/Classes/NJDeviceController.m @@ -12,7 +12,6 @@ #import "NJDevice.h" #import "NJInput.h" #import "NJOutput.h" -#import "NJOutputController.h" #import "NJEvents.h" #import "NJDeviceViewController.h" @@ -68,6 +67,14 @@ [_continuousOutputsTick invalidate]; } +- (NJDevice *)objectAtIndexedSubscript:(NSUInteger)idx { + return idx < _devices.count ? _devices[idx] : nil; +} + +- (NSUInteger)count { + return _devices.count; +} + - (void)addRunningOutput:(NJOutput *)output { // Axis events will trigger every small movement, don't keep // re-adding them or they trigger multiple times each time. @@ -102,8 +109,7 @@ if (!handler) return; - [devicesViewController expandAndSelectItem:handler]; - [outputController focusKey]; + [self.delegate deviceController:self didInput:handler]; } - (void)hidManager:(NJHIDManager *)manager @@ -134,10 +140,8 @@ - (void)hidManager:(NJHIDManager *)manager deviceAdded:(IOHIDDeviceRef)device { NJDevice *match = [[NJDevice alloc] initWithDevice:device]; - [devicesViewController beginUpdates]; [self addDevice:match]; - [devicesViewController addedDevice:match atIndex:_devices.count - 1]; - [devicesViewController endUpdates]; + [self.delegate deviceController:self didAddDevice:match]; } - (NJDevice *)findDeviceByRef:(IOHIDDeviceRef)device { @@ -149,13 +153,10 @@ - (void)hidManager:(NJHIDManager *)manager deviceRemoved:(IOHIDDeviceRef)device { NJDevice *match = [self findDeviceByRef:device]; - IOHIDDeviceRegisterInputValueCallback(device, NULL, NULL); if (match) { NSInteger idx = [_devices indexOfObjectIdenticalTo:match]; - [devicesViewController beginUpdates]; [_devices removeObjectAtIndex:idx]; - [devicesViewController removedDevice:match atIndex:idx]; - [devicesViewController endUpdates]; + [self.delegate deviceController:self didRemoveDeviceAtIndex:idx]; } } @@ -173,28 +174,17 @@ } - (void)hidManager:(NJHIDManager *)manager didError:(NSError *)error { - // Since the error shows the window, it can trigger another attempt - // to re-open the HID manager, which will also probably fail and error, - // so don't bother repeating ourselves. - if (!simulatingEventsButton.window.attachedSheet) { - [NSApplication.sharedApplication activateIgnoringOtherApps:YES]; - [simulatingEventsButton.window makeKeyAndOrderFront:nil]; - [simulatingEventsButton.window presentError:error - modalForWindow:simulatingEventsButton.window - delegate:nil - didPresentSelector:nil - contextInfo:nil]; - } + [self.delegate deviceController:self didError:error]; self.simulatingEvents = NO; } - (void)hidManagerDidStart:(NJHIDManager *)manager { - [devicesViewController hidStarted]; + [self.delegate deviceControllerDidStartHID:self]; } - (void)hidManagerDidStop:(NJHIDManager *)manager { [_devices removeAllObjects]; - [devicesViewController hidStopped]; + [self.delegate deviceControllerDidStopHID:self]; } - (void)startHid { @@ -205,10 +195,6 @@ [_hidManager stop]; } -- (NJInput *)selectedInput { - return (NJInput *)devicesViewController.selectedHandler; -} - - (void)setSimulatingEvents:(BOOL)simulatingEvents { if (simulatingEvents != _simulatingEvents) { _simulatingEvents = simulatingEvents; @@ -245,8 +231,7 @@ return _devices[idx]; } -- (id)deviceViewController:(NJDeviceViewController *)dvc - elementForUID:(NSString *)uid { +- (NJInputPathElement *)objectForKeyedSubscript:(NSString *)uid { for (NJDevice *dev in _devices) { id item = [dev elementForUID:uid]; if (item) @@ -255,23 +240,4 @@ return nil; } -- (void)deviceViewControllerDidSelectNothing:(NJDeviceViewController *)dvc { - [outputController loadCurrent]; -} - -- (void)deviceViewController:(NJDeviceViewController *)dvc - didSelectBranch:(NJInputPathElement *)handler { - [outputController loadCurrent]; -} - -- (void)deviceViewController:(NJDeviceViewController *)dvc - didSelectHandler:(NJInputPathElement *)handler { - [outputController loadCurrent]; -} - -- (void)deviceViewController:(NJDeviceViewController *)dvc - didSelectDevice:(NJInputPathElement *)device { - [outputController loadCurrent]; -} - @end diff --git a/Classes/NJDeviceViewController.h b/Classes/NJDeviceViewController.h index 6935322..0a16e47 100644 --- a/Classes/NJDeviceViewController.h +++ b/Classes/NJDeviceViewController.h @@ -7,6 +7,7 @@ // @class NJDevice; +@class NJInput; @class NJInputPathElement; @protocol NJDeviceViewControllerDelegate; @@ -21,18 +22,14 @@ @property (nonatomic, weak) IBOutlet id delegate; - (void)addedDevice:(NJDevice *)device atIndex:(NSUInteger)idx; -- (void)removedDevice:(NJDevice *)device atIndex:(NSUInteger)idx; - // But using these will animate nicely. +- (void)removedDeviceAtIndex:(NSUInteger)idx; - (void)hidStarted; - (void)hidStopped; -- (void)beginUpdates; -- (void)endUpdates; - - (void)expandAndSelectItem:(NJInputPathElement *)item; -- (NJInputPathElement *)selectedHandler; +- (NJInput *)selectedHandler; @end diff --git a/Classes/NJDeviceViewController.m b/Classes/NJDeviceViewController.m index 5d0bf6a..8b36a0e 100644 --- a/Classes/NJDeviceViewController.m +++ b/Classes/NJDeviceViewController.m @@ -36,14 +36,6 @@ [self expandRecursive:[self.delegate deviceViewController:self elementForUID:uid]]; } -- (void)beginUpdates { - [self.inputsTree beginUpdates]; -} - -- (void)endUpdates { - [self.inputsTree endUpdates]; -} - - (void)reexpandAll { for (NSString *uid in [_expanded copy]) [self expandRecursiveByUID:uid]; @@ -55,18 +47,22 @@ } - (void)addedDevice:(NJDevice *)device atIndex:(NSUInteger)idx { + [self.inputsTree beginUpdates]; [self.inputsTree insertItemsAtIndexes:[[NSIndexSet alloc] initWithIndex:idx] inParent:nil withAnimation:NSTableViewAnimationEffectFade]; [self reexpandAll]; + [self.inputsTree endUpdates]; self.noDevicesNotice.hidden = YES; } -- (void)removedDevice:(NJDevice *)device atIndex:(NSUInteger)idx { +- (void)removedDeviceAtIndex:(NSUInteger)idx { BOOL anyDevices = !![self.delegate numberOfDevicesInDeviceList:self]; + [self.inputsTree beginUpdates]; [self.inputsTree removeItemsAtIndexes:[[NSIndexSet alloc] initWithIndex:idx] inParent:nil withAnimation:NSTableViewAnimationEffectFade]; + [self.inputsTree endUpdates]; self.noDevicesNotice.hidden = anyDevices || !self.hidStoppedNotice.isHidden; } @@ -163,11 +159,9 @@ objectValueForTableColumn:(NSTableColumn *)tableColumn return ![self outlineView:outlineView isGroupItem:item]; } -- (NJInputPathElement *)selectedHandler { +- (NJInput *)selectedHandler { NJInputPathElement *element = self.inputsTree.selectedItem; - return element.children ? nil : element; + return element.children ? nil : (NJInput *)element; } - - @end diff --git a/Classes/NJMappingsController.m b/Classes/NJMappingsController.m index 760b41b..44a9c43 100644 --- a/Classes/NJMappingsController.m +++ b/Classes/NJMappingsController.m @@ -85,20 +85,24 @@ _manualMapping = oldMapping; } +- (void)activateMappingForcibly:(NJMapping *)mapping { + NSLog(@"Switching to mapping %@.", mapping.name); + _currentMapping = mapping; + NSUInteger idx = [self indexOfMapping:_currentMapping]; + [NSNotificationCenter.defaultCenter + postNotificationName:NJEventMappingChanged + object:self + userInfo:@{ NJMappingKey : _currentMapping, + NJMappingIndexKey: @(idx) }]; +} + - (void)activateMapping:(NJMapping *)mapping { if (!mapping) mapping = _manualMapping; if (mapping == _currentMapping) return; - NSLog(@"Switching to mapping %@.", mapping.name); _manualMapping = mapping; - _currentMapping = mapping; - NSUInteger idx = [self indexOfMapping:_currentMapping]; - [NSNotificationCenter.defaultCenter - postNotificationName:NJEventMappingChanged - object:self - userInfo:@{ NJMappingKey : _currentMapping, - NJMappingIndexKey: @(idx) }]; + [self activateMappingForcibly:mapping]; } - (void)save { @@ -139,25 +143,15 @@ - (void)mergeMapping:(NJMapping *)mapping intoMapping:(NJMapping *)existing { [existing mergeEntriesFrom:mapping]; [self mappingsChanged]; - if (existing == _currentMapping) { - // FIXME: Hack to trigger updates in the rest of the UI. - _currentMapping = nil; - NJMapping *manual = _manualMapping; - [self activateMapping:existing]; - _manualMapping = manual; - } + if (existing == _currentMapping) + [self activateMappingForcibly:mapping]; } - (void)renameMapping:(NJMapping *)mapping to:(NSString *)name { mapping.name = name; [self mappingsChanged]; - if (mapping == _currentMapping) { - // FIXME: Hack to trigger updates in the rest of the UI. - _currentMapping = nil; - NJMapping *manual = _manualMapping; - [self activateMapping:mapping]; - _manualMapping = manual; - } + if (mapping == _currentMapping) + [self activateMappingForcibly:mapping]; } - (void)addMapping:(NJMapping *)mapping { diff --git a/Classes/NJOutputController.h b/Classes/NJOutputController.h index 3974e2e..c18275f 100644 --- a/Classes/NJOutputController.h +++ b/Classes/NJOutputController.h @@ -11,7 +11,7 @@ @class NJMappingsController; @class NJDeviceController; @class NJOutput; -@class NJOutputMouseMove; +@class NJInput; @interface NJOutputController : NSObject { IBOutlet NJKeyInputField *keyInput; @@ -24,14 +24,13 @@ IBOutlet NSTextField *title; IBOutlet NSPopUpButton *mappingPopup; IBOutlet NJMappingsController *mappingsController; - IBOutlet NJDeviceController *inputController; IBOutlet NSButton *smoothCheck; IBOutlet NSButton *unknownMapping; } @property (assign) BOOL enabled; -- (void)loadCurrent; +- (void)loadInput:(NJInput *)input; - (IBAction)radioChanged:(id)sender; - (IBAction)mdirChanged:(id)sender; - (IBAction)mbtnChanged:(id)sender; diff --git a/Classes/NJOutputController.m b/Classes/NJOutputController.m index 5235837..1567fee 100644 --- a/Classes/NJOutputController.m +++ b/Classes/NJOutputController.m @@ -20,7 +20,9 @@ #import "NJOutputMouseMove.h" #import "NJOutputMouseScroll.h" -@implementation NJOutputController +@implementation NJOutputController { + NJInput *_input; +} - (id)init { if ((self = [super init])) { @@ -157,7 +159,7 @@ } - (NJOutput *)currentOutput { - return mappingsController.currentMapping[inputController.selectedInput]; + return mappingsController.currentMapping[_input]; } - (NJOutput *)makeOutput { @@ -203,7 +205,7 @@ - (void)commit { [self cleanUpInterface]; - mappingsController.currentMapping[inputController.selectedInput] = [self makeOutput]; + mappingsController.currentMapping[_input] = [self makeOutput]; [mappingsController save]; } @@ -272,8 +274,9 @@ [self cleanUpInterface]; } -- (void)loadCurrent { - [self loadOutput:self.currentOutput forInput:inputController.selectedInput]; +- (void)loadInput:(NJInput *)input { + _input = input; + [self loadOutput:self.currentOutput forInput:input]; } - (void)focusKey { @@ -299,7 +302,7 @@ } - (void)mappingDidChange:(NSNotification *)note { - [self loadCurrent]; + [self loadInput:_input]; } @end diff --git a/Info.plist b/Info.plist index 4a78c2b..fa16792 100644 --- a/Info.plist +++ b/Info.plist @@ -46,7 +46,7 @@ CFBundleSignature ???? CFBundleVersion - 526 + 535 LSApplicationCategoryType public.app-category.utilities NSHumanReadableCopyright diff --git a/Resources/English.lproj/MainMenu.xib b/Resources/English.lproj/MainMenu.xib index 7cd0972..bbb398e 100644 --- a/Resources/English.lproj/MainMenu.xib +++ b/Resources/English.lproj/MainMenu.xib @@ -1695,11 +1695,11 @@ aW5nLg - devicesViewController + delegate - + - 992 + 1029 @@ -1765,6 +1765,30 @@ aW5nLg 1024 + + + dvc + + + + 1025 + + + + deviceController + + + + 1026 + + + + outputController + + + + 1027 + performClick: @@ -1797,14 +1821,6 @@ aW5nLg 821 - - - inputController - - - - 828 - mouseDirSelect @@ -2085,14 +2101,6 @@ aW5nLg 969 - - - delegate - - - - 984 - hidStoppedNotice @@ -2117,6 +2125,14 @@ aW5nLg 989 + + + delegate + + + + 1028 + view @@ -3328,7 +3344,7 @@ aW5nLg - 1024 + 1029 0 -- 2.30.2