D5F80A9D0FB0A2FF0006A4DE /* icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = D5617A080FAEAF8300928B3A /* icon.icns */; };
EE1D7C9216E01E7000B000EB /* NSView+FirstResponder.m in Sources */ = {isa = PBXBuildFile; fileRef = EE1D7C9116E01E7000B000EB /* NSView+FirstResponder.m */; };
EE1D7C9616E0ECCF00B000EB /* NSError+Description.m in Sources */ = {isa = PBXBuildFile; fileRef = EE1D7C9516E0ECCF00B000EB /* NSError+Description.m */; };
+ EE96929416E54B480054A3C8 /* NSMenu+RepresentedObjectAccessors.m in Sources */ = {isa = PBXBuildFile; fileRef = EE96929316E54B480054A3C8 /* NSMenu+RepresentedObjectAccessors.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
EE1D7C9116E01E7000B000EB /* NSView+FirstResponder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSView+FirstResponder.m"; sourceTree = "<group>"; };
EE1D7C9416E0ECCF00B000EB /* NSError+Description.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+Description.h"; sourceTree = "<group>"; };
EE1D7C9516E0ECCF00B000EB /* NSError+Description.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+Description.m"; sourceTree = "<group>"; };
+ EE96929216E54B480054A3C8 /* NSMenu+RepresentedObjectAccessors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMenu+RepresentedObjectAccessors.h"; sourceTree = "<group>"; };
+ EE96929316E54B480054A3C8 /* NSMenu+RepresentedObjectAccessors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMenu+RepresentedObjectAccessors.m"; sourceTree = "<group>"; };
EEF86B7316E2241000674B87 /* NJInputPathElement.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NJInputPathElement.h; sourceTree = "<group>"; };
EEF86B7416E298CD00674B87 /* NJEvents.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NJEvents.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
EE1D7C9516E0ECCF00B000EB /* NSError+Description.m */,
EE1D7C9016E01E7000B000EB /* NSView+FirstResponder.h */,
EE1D7C9116E01E7000B000EB /* NSView+FirstResponder.m */,
+ EE96929216E54B480054A3C8 /* NSMenu+RepresentedObjectAccessors.h */,
+ EE96929316E54B480054A3C8 /* NSMenu+RepresentedObjectAccessors.m */,
);
name = Categories;
sourceTree = "<group>";
8BEFADA015C476DC00823AEC /* NJOutputSwitchMouseMode.m in Sources */,
EE1D7C9216E01E7000B000EB /* NSView+FirstResponder.m in Sources */,
EE1D7C9616E0ECCF00B000EB /* NSError+Description.m in Sources */,
+ EE96929416E54B480054A3C8 /* NSMenu+RepresentedObjectAccessors.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
#import "NJOutputController.h"
#import "NJEvents.h"
-@implementation EnjoyableApplicationDelegate {
- NSInteger mappingsMenuIndex;
-}
+@implementation EnjoyableApplicationDelegate
- (void)didSwitchApplication:(NSNotification *)notification {
NSRunningApplication *currentApp = notification.userInfo[NSWorkspaceApplicationKey];
name:NJEventTranslationDeactivated
object:nil];
- while (![dockMenuBase itemAtIndex:mappingsMenuIndex++].tag);
-
- self.outputController.enabled = NO;
[self.inputController setup];
[self.mappingsController load];
}
- (void)mappingListDidChange:(NSNotification *)note {
NSArray *mappings = note.object;
- NSInteger removeFrom = mappingsMenuIndex;
- while (dockMenuBase.numberOfItems > removeFrom)
- [dockMenuBase removeItemAtIndex:dockMenuBase.numberOfItems - 1];
+ while (dockMenuBase.lastItem.representedObject)
+ [dockMenuBase removeLastItem];
int added = 0;
for (NJMapping *mapping in mappings) {
NSString *keyEquiv = ++added < 10 ? @(added).stringValue : @"";
- [dockMenuBase addItemWithTitle:mapping.name
- action:@selector(chooseMapping:)
- keyEquivalent:keyEquiv];
-
+ NSMenuItem *item = [dockMenuBase addItemWithTitle:mapping.name
+ action:@selector(chooseMapping:)
+ keyEquivalent:keyEquiv];
+ item.representedObject = mapping;
}
[_outputController refreshMappings];
}
- (void)mappingDidChange:(NSNotification *)note {
NJMapping *current = note.object;
- NSArray *mappings = self.mappingsController.mappings;
- for (NSUInteger i = 0; i < mappings.count; ++i)
- [dockMenuBase itemAtIndex:i + mappingsMenuIndex].state = mappings[i] == current;
+ for (NSMenuItem *item in dockMenuBase.itemArray)
+ if (item.representedObject)
+ item.state = item.representedObject == current;
}
-- (void)chooseMapping:(id)sender {
- NSInteger idx = [dockMenuBase indexOfItem:sender] - mappingsMenuIndex;
- NJMapping *chosen = self.mappingsController[idx];
- [_mappingsController activateMapping:chosen];
+- (void)chooseMapping:(NSMenuItem *)sender {
+ NJMapping *chosen = sender.representedObject;
+ [self.mappingsController activateMapping:chosen];
}
@end
#import <IOKit/hid/IOHIDLib.h>
-#import "NSView+FirstResponder.h"
#import "NSError+Description.h"
+#import "NSMenu+RepresentedObjectAccessors.h"
+#import "NSView+FirstResponder.h"
- (void)mappingsChanged {
[self save];
[tableView reloadData];
+ popoverActivate.title = _currentMapping.name;
[NSNotificationCenter.defaultCenter
postNotificationName:NJEventMappingListChanged
object:_mappings];
- (void)activateMapping:(NJMapping *)mapping {
if (!mapping)
mapping = manualMapping;
+ if (mapping == _currentMapping)
+ return;
NSLog(@"Switching to mapping %@.", mapping.name);
manualMapping = mapping;
_currentMapping = mapping;
[removeButton setEnabled:_mappings[0] != mapping];
[outputController loadCurrent];
popoverActivate.title = _currentMapping.name;
+ NSUInteger selected = [_mappings indexOfObject:mapping];
+ [tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:selected] byExtendingSelection:NO];
+ [NSUserDefaults.standardUserDefaults setInteger:selected forKey:@"selected"];
[NSNotificationCenter.defaultCenter postNotificationName:NJEventMappingChanged
object:_currentMapping];
- [tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:[_mappings indexOfObject:mapping]] byExtendingSelection:NO];
}
- (IBAction)addPressed:(id)sender {
}
- (BOOL)tableView:(NSTableView *)view shouldEditTableColumn:(NSTableColumn *)column row:(NSInteger)index {
- return index > 0;
+ return YES;
}
- (void)save {
NSLog(@"Saving mappings to defaults.");
- [NSUserDefaults.standardUserDefaults setValuesForKeysWithDictionary:[self dumpAll]];
-}
-
-- (void)load {
- [self loadAllFrom:NSUserDefaults.standardUserDefaults.dictionaryRepresentation];
-}
-
-- (NSDictionary *)dumpAll {
NSMutableArray *ary = [[NSMutableArray alloc] initWithCapacity:_mappings.count];
for (NJMapping *mapping in _mappings)
[ary addObject:[mapping serialize]];
- NSUInteger current = _currentMapping ? [_mappings indexOfObject:_currentMapping] : 0;
- return @{ @"mappings": ary, @"selected": @(current) };
+ [NSUserDefaults.standardUserDefaults setObject:ary forKey:@"mappings"];
+}
+
+- (void)load {
+ NSUInteger selected = [NSUserDefaults.standardUserDefaults integerForKey:@"selected"];
+ NSArray *mappings = [NSUserDefaults.standardUserDefaults arrayForKey:@"mappings"];
+ [self loadAllFrom:mappings andActivate:selected];
}
-- (void)loadAllFrom:(NSDictionary*)envelope {
- NSArray *storedMappings = envelope[@"mappings"];
+- (void)loadAllFrom:(NSArray *)storedMappings andActivate:(NSUInteger)selected {
NSMutableArray* newMappings = [[NSMutableArray alloc] initWithCapacity:storedMappings.count];
// have to do two passes in case mapping1 refers to mapping2 via a NJOutputMapping
}
if (newMappings.count) {
- unsigned current = [envelope[@"selected"] unsignedIntValue];
- if (current >= newMappings.count)
- current = 0;
_mappings = newMappings;
+ if (selected >= newMappings.count)
+ selected = 0;
[self mappingsChanged];
- [self activateMapping:_mappings[current]];
+ [self activateMapping:_mappings[selected]];
}
}
keyInput.keyCode = [(NJOutputKeyPress*)output vk];
} else if ([output isKindOfClass:NJOutputMapping.class]) {
[radioButtons selectCellAtRow:2 column:0];
- NSUInteger idx = [mappingPopup indexOfItemWithRepresentedObject:[(NJOutputMapping *)output mapping]];
- if (idx == NSNotFound) {
+ NSMenuItem *item = [mappingPopup itemWithRepresentedObject:[(NJOutputMapping *)output mapping]];
+ [mappingPopup selectItem:item];
+ if (!item)
[radioButtons selectCellAtRow:self.enabled ? 0 : -1 column:0];
- [mappingPopup selectItemAtIndex:-1];
- } else
- [mappingPopup selectItemAtIndex:idx];
}
else if ([output isKindOfClass:NJOutputMouseMove.class]) {
[radioButtons selectCellAtRow:3 column:0];
item.representedObject = mapping;
[mappingPopup.menu addItem:item];
}
- [mappingPopup selectItemAtIndex:[mappingPopup indexOfItemWithRepresentedObject:current]];
+ [mappingPopup selectItemWithRepresentedObject:current];
}
@end
--- /dev/null
+//
+// NSMenu+RepresentedObjectAccessors.h
+// Enjoyable
+//
+// Created by Joe Wreschnig on 3/4/13.
+//
+//
+
+#import <Cocoa/Cocoa.h>
+
+@interface NSMenu (RepresentedObjectAccessors)
+ // Helpers for using represented objects in menu items.
+
+- (NSMenuItem *)itemWithRepresentedObject:(id)object;
+ // Returns the first menu item in the receiver that has a given
+ // represented object.
+
+- (void)removeItemWithRepresentedObject:(id)object;
+ // Removes the first menu item representing the given object in the
+ // receiver.
+ //
+ // After it removes the menu item, this method posts an
+ // NSMenuDidRemoveItemNotification.
+
+- (NSMenuItem *)lastItem;
+ // Return the last menu item in the receiver, or nil if the menu
+ // has no items.
+
+- (void)removeLastItem;
+ // Removes the last menu item in the receiver, if there is one.
+ //
+ // After and if it removes the menu item, this method posts an
+ // NSMenuDidRemoveItemNotification.
+
+@end
+
+@interface NSPopUpButton (RepresentedObjectAccessors)
+
+- (NSMenuItem *)itemWithRepresentedObject:(id)object;
+ // Returns the first item in the receiver's menu that has a given
+ // represented object.
+
+- (void)selectItemWithRepresentedObject:(id)object;
+ // Selects the first item in the receiver's menu that has a give
+ // represented object.
+
+@end
--- /dev/null
+//
+// NSMenu+RepresentedObjectAccessors.m
+// Enjoyable
+//
+// Created by Joe Wreschnig on 3/4/13.
+//
+//
+
+#import "NSMenu+RepresentedObjectAccessors.h"
+
+@implementation NSMenu (RepresentedObjectAccessors)
+
+- (NSMenuItem *)itemWithRepresentedObject:(id)object {
+ for (NSMenuItem *item in self.itemArray)
+ if ([item.representedObject isEqual:object])
+ return item;
+ return nil;
+}
+
+- (void)removeItemWithRepresentedObject:(id)object {
+ NSInteger idx = [self indexOfItemWithRepresentedObject:object];
+ if (idx != -1)
+ [self removeItemAtIndex:idx];
+}
+
+- (NSMenuItem *)lastItem {
+ return self.itemArray.lastObject;
+}
+
+- (void)removeLastItem {
+ if (self.numberOfItems)
+ [self removeItemAtIndex:self.numberOfItems - 1];
+}
+
+@end
+
+@implementation NSPopUpButton (RepresentedObjectAccessors)
+
+- (NSMenuItem *)itemWithRepresentedObject:(id)object {
+ return [self.menu itemWithRepresentedObject:object];
+}
+
+- (void)selectItemWithRepresentedObject:(id)object {
+ [self selectItemAtIndex:[self indexOfItemWithRepresentedObject:object]];
+}
+
+
+@end