-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 7957e8d
Showing
54 changed files
with
7,087 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# OS X | ||
.DS_Store | ||
|
||
# Xcode | ||
build/ | ||
*.pbxuser | ||
!default.pbxuser | ||
*.mode1v3 | ||
!default.mode1v3 | ||
*.mode2v3 | ||
!default.mode2v3 | ||
*.perspectivev3 | ||
!default.perspectivev3 | ||
*.xcworkspace | ||
!default.xcworkspace | ||
xcuserdata | ||
profile | ||
*.moved-aside | ||
DerivedData/ | ||
|
||
# Makefile products | ||
Gamepad Menu.app | ||
Gamepad Menu.zip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// | ||
// AppDelegate.h | ||
// Gamepad Menu Helper | ||
// | ||
// Created by Robbert Klarenbeek on 12/01/16. | ||
// Copyright © 2016 Robbert Klarenbeek. All rights reserved. | ||
// | ||
|
||
#import <Cocoa/Cocoa.h> | ||
|
||
@interface AppDelegate : NSObject <NSApplicationDelegate> | ||
|
||
@end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// | ||
// AppDelegate.m | ||
// Gamepad Menu Helper | ||
// | ||
// Created by Robbert Klarenbeek on 12/01/16. | ||
// Copyright © 2016 Robbert Klarenbeek. All rights reserved. | ||
// | ||
|
||
#import "AppDelegate.h" | ||
|
||
@implementation AppDelegate | ||
|
||
- (void)applicationWillFinishLaunching:(NSNotification *)notification { | ||
NSString *appPath = [[[[[[NSBundle mainBundle] bundlePath] | ||
stringByDeletingLastPathComponent] | ||
stringByDeletingLastPathComponent] | ||
stringByDeletingLastPathComponent] | ||
stringByDeletingLastPathComponent]; | ||
[[NSWorkspace sharedWorkspace] launchApplication:appPath]; | ||
[NSApp terminate:nil]; | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>CFBundleDevelopmentRegion</key> | ||
<string>en</string> | ||
<key>CFBundleExecutable</key> | ||
<string>$(EXECUTABLE_NAME)</string> | ||
<key>CFBundleIconFile</key> | ||
<string></string> | ||
<key>CFBundleIdentifier</key> | ||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> | ||
<key>CFBundleInfoDictionaryVersion</key> | ||
<string>6.0</string> | ||
<key>CFBundleName</key> | ||
<string>$(PRODUCT_NAME)</string> | ||
<key>CFBundlePackageType</key> | ||
<string>APPL</string> | ||
<key>CFBundleShortVersionString</key> | ||
<string>1.0</string> | ||
<key>CFBundleSignature</key> | ||
<string>????</string> | ||
<key>CFBundleVersion</key> | ||
<string>1</string> | ||
<key>LSMinimumSystemVersion</key> | ||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string> | ||
<key>NSHumanReadableCopyright</key> | ||
<string>Copyright © 2016 Robbert Klarenbeek. All rights reserved.</string> | ||
<key>NSPrincipalClass</key> | ||
<string>NSApplication</string> | ||
<key>LSUIElement</key> | ||
<true/> | ||
</dict> | ||
</plist> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// | ||
// main.m | ||
// Gamepad Menu Helper | ||
// | ||
// Created by Robbert Klarenbeek on 12/01/16. | ||
// Copyright © 2016 Robbert Klarenbeek. All rights reserved. | ||
// | ||
|
||
#import <Cocoa/Cocoa.h> | ||
#import "AppDelegate.h" | ||
|
||
int main(int argc, const char * argv[]) { | ||
AppDelegate *delegate = [[AppDelegate alloc] init]; | ||
[[NSApplication sharedApplication] setDelegate:delegate]; | ||
[NSApp run]; | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// | ||
// AppDelegate.h | ||
// Gamepad Menu | ||
// | ||
// Created by Robbert Klarenbeek on 12/01/16. | ||
// Copyright © 2016 Robbert Klarenbeek. All rights reserved. | ||
// | ||
|
||
#import <Cocoa/Cocoa.h> | ||
|
||
@interface AppDelegate : NSObject <NSApplicationDelegate> | ||
@property (assign) IBOutlet NSMenu *menu; | ||
@property (nonatomic, strong) NSStatusItem *statusItem; | ||
@end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
// | ||
// AppDelegate.m | ||
// Gamepad Menu | ||
// | ||
// Created by Robbert Klarenbeek on 12/01/16. | ||
// Copyright © 2016 Robbert Klarenbeek. All rights reserved. | ||
// | ||
|
||
#import "AppDelegate.h" | ||
|
||
#import "ElementBinding.h" | ||
#import "GamepadManager.h" | ||
#import "PresetMenuItem.h" | ||
|
||
static NSString *const kStatusMenuTemplateName = @"StatusMenuTemplate"; | ||
|
||
static NSString *const kDeviceProfilesDirectory = @"Device Profiles"; | ||
static NSString *const kPresetsDirectory = @"Presets"; | ||
|
||
static NSString *const kEntityTitleKey = @"Title"; | ||
static NSString *const kDeviceProfileIdentifierKey = @"Identifier"; | ||
static NSString *const kDeviceProfileIdentifierVendorKey = @"Vendor"; | ||
static NSString *const kDeviceProfileIdentifierProductKey = @"Product"; | ||
|
||
@interface AppDelegate () <GamepadManagerDelegate, PresetMenuItemDelegate> { | ||
NSArray *_deviceProfiles; | ||
NSArray *_presets; | ||
|
||
GamepadManager *_gamepadManager; | ||
NSMutableDictionary *_connectedDevices; | ||
NSMutableDictionary *_elementBindings; | ||
} | ||
|
||
@end | ||
|
||
@implementation AppDelegate | ||
|
||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { | ||
_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; | ||
_statusItem.menu = self.menu; | ||
_statusItem.image = [NSImage imageNamed:kStatusMenuTemplateName]; | ||
_statusItem.highlightMode = YES; | ||
|
||
_connectedDevices = [NSMutableDictionary new]; | ||
_elementBindings = [NSMutableDictionary new]; | ||
|
||
_deviceProfiles = [self loadPlistsFromDirectory:kDeviceProfilesDirectory]; | ||
_presets = [self loadPlistsFromDirectory:kPresetsDirectory]; | ||
|
||
_gamepadManager = [GamepadManager new]; | ||
_gamepadManager.delegate = self; | ||
} | ||
|
||
- (void)applicationWillTerminate:(NSNotification *)aNotification { | ||
[[NSStatusBar systemStatusBar] removeStatusItem:self.statusItem]; | ||
} | ||
|
||
- (NSArray *)loadPlistsFromDirectory:(NSString *)directory { | ||
NSMutableArray *items = [NSMutableArray new]; | ||
NSBundle *bundle = [NSBundle mainBundle]; | ||
NSArray *files = [[bundle pathsForResourcesOfType:@"plist" inDirectory:directory] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; | ||
for (NSString *file in files) { | ||
NSMutableDictionary *item = [NSMutableDictionary dictionaryWithContentsOfFile:file]; | ||
item[kEntityTitleKey] = [[file lastPathComponent] stringByDeletingPathExtension]; | ||
[items addObject:item]; | ||
} | ||
return items; | ||
} | ||
|
||
- (NSMenuItem *)menuItemForDevice:(IOHIDDeviceRef)device withDeviceProfile:(NSDictionary *)deviceProfile { | ||
NSMenu *menu = [NSMenu new]; | ||
|
||
for (NSDictionary *preset in _presets) { | ||
PresetMenuItem *menuItem = [[PresetMenuItem alloc] initWithDevice:device deviceProfile:deviceProfile preset:preset]; | ||
menuItem.delegate = self; | ||
[menu addItem:menuItem]; | ||
} | ||
|
||
[menu addItem:[NSMenuItem separatorItem]]; | ||
PresetMenuItem *disabledMenuItem = [PresetMenuItem disabledMenuItem:device]; | ||
disabledMenuItem.delegate = self; | ||
[menu addItem:disabledMenuItem]; | ||
|
||
NSMenuItem *menuItem = [NSMenuItem new]; | ||
menuItem.title = deviceProfile[kEntityTitleKey]; | ||
menuItem.submenu = menu; | ||
return menuItem; | ||
} | ||
|
||
- (NSMenuItem *)menuItemForUnknownDeviceWithVendor:(uint32_t)vendorId product:(uint32_t)productId { | ||
NSMenu *menu = [NSMenu new]; | ||
|
||
NSMenuItem *infoItem = [NSMenuItem new]; | ||
infoItem.title = NSLocalizedString(@"No profile exists for this device", @"Unknown device info text"); | ||
infoItem.enabled = NO; | ||
[menu addItem:infoItem]; | ||
[menu addItem:[NSMenuItem separatorItem]]; | ||
|
||
NSMenuItem *vendorIdItem = [NSMenuItem new]; | ||
vendorIdItem.title = [NSString stringWithFormat:@"Vendor ID: 0x%02x", vendorId]; | ||
vendorIdItem.enabled = NO; | ||
[menu addItem:vendorIdItem]; | ||
|
||
NSMenuItem *productIdItem = [NSMenuItem new]; | ||
productIdItem.title = [NSString stringWithFormat:@"Product ID: 0x%02x", productId]; | ||
productIdItem.enabled = NO; | ||
[menu addItem:productIdItem]; | ||
|
||
NSMenuItem *menuItem = [NSMenuItem new]; | ||
menuItem.title = NSLocalizedString(@"Unknown Gamepad", @"Name for unknown device"); | ||
menuItem.submenu = menu; | ||
return menuItem; | ||
} | ||
|
||
#pragma mark - PresetMenuItemDelegate | ||
|
||
- (void)clearElementBindingsForDevice:(IOHIDDeviceRef)device { | ||
for (id elementHash in [_elementBindings allKeys]) { | ||
ElementBinding *elementBinding = _elementBindings[elementHash]; | ||
if (elementBinding.device == device) [_elementBindings removeObjectForKey:elementHash]; | ||
} | ||
} | ||
|
||
- (void)addElementBinding:(ElementBinding *)elementBinding { | ||
id elementHash = [NSValue valueWithPointer:elementBinding.element]; | ||
_elementBindings[elementHash] = elementBinding; | ||
} | ||
|
||
#pragma mark - GamepadManagerDelegate | ||
|
||
- (void)deviceDidConnect:(IOHIDDeviceRef)device { | ||
uint32_t vendorId = 0; | ||
CFNumberGetValue(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)), kCFNumberSInt32Type, &vendorId); | ||
|
||
uint32_t productId = 0; | ||
CFNumberGetValue(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)), kCFNumberSInt32Type, &productId); | ||
|
||
NSDictionary *deviceProfile; | ||
for (NSDictionary *deviceProfileCandidate in _deviceProfiles) { | ||
id identifier = deviceProfileCandidate[kDeviceProfileIdentifierKey]; | ||
NSArray *identifierCandidates; | ||
if ([identifier isKindOfClass:[NSDictionary class]]) { | ||
identifierCandidates = @[identifier]; | ||
} else if ([identifier isKindOfClass:[NSArray class]]) { | ||
identifierCandidates = identifier; | ||
} else { | ||
continue; | ||
} | ||
for (NSDictionary *identifierCandidate in identifierCandidates) { | ||
if (vendorId != [identifierCandidate[kDeviceProfileIdentifierVendorKey] unsignedIntegerValue]) continue; | ||
if (productId != [identifierCandidate[kDeviceProfileIdentifierProductKey] unsignedIntegerValue]) continue; | ||
deviceProfile = deviceProfileCandidate; | ||
break; | ||
} | ||
if (deviceProfile) break; | ||
} | ||
|
||
NSMenuItem *menuItem; | ||
if (!deviceProfile) { | ||
menuItem = [self menuItemForUnknownDeviceWithVendor:vendorId product:productId]; | ||
deviceProfile = @{}; | ||
} else { | ||
menuItem = [self menuItemForDevice:device withDeviceProfile:deviceProfile]; | ||
} | ||
menuItem.tag = (NSInteger)device; | ||
|
||
NSMenuItem *placeholder = nil; | ||
BOOL didInsert = NO; | ||
for (NSMenuItem *existingMenuItem in _menu.itemArray) { | ||
if (existingMenuItem.isSeparatorItem) break; | ||
if (existingMenuItem.tag == 0) { | ||
placeholder = existingMenuItem; | ||
continue; | ||
} | ||
if (didInsert) continue; | ||
NSComparisonResult compare = [existingMenuItem.title caseInsensitiveCompare:menuItem.title]; | ||
if (compare == NSOrderedAscending) continue; | ||
if (compare == NSOrderedSame && menuItem.tag > existingMenuItem.tag) continue; | ||
[_menu insertItem:menuItem atIndex:[_menu indexOfItem:existingMenuItem]]; | ||
didInsert = YES; | ||
} | ||
|
||
if (!didInsert) [_menu insertItem:menuItem atIndex:[_menu indexOfItem:placeholder]]; | ||
placeholder.hidden = YES; | ||
|
||
_connectedDevices[[NSValue valueWithPointer:device]] = deviceProfile; | ||
} | ||
|
||
- (void)deviceDidDisconnect:(IOHIDDeviceRef)device { | ||
[_connectedDevices removeObjectForKey:[NSValue valueWithPointer:device]]; | ||
[self clearElementBindingsForDevice:device]; | ||
|
||
NSMenuItem *placeholder = nil; | ||
for (NSMenuItem *existingMenuItem in _menu.itemArray) { | ||
if (existingMenuItem.isSeparatorItem) break; | ||
if (existingMenuItem.tag == 0) placeholder = existingMenuItem; | ||
if (existingMenuItem.tag == (NSInteger)device) [_menu removeItem:existingMenuItem]; | ||
} | ||
|
||
placeholder.hidden = _connectedDevices.count > 0; | ||
} | ||
|
||
- (void)deviceDidChange:(IOHIDValueRef)value { | ||
IOHIDElementRef element = IOHIDValueGetElement(value); | ||
id elementHash = [NSValue valueWithPointer:element]; | ||
ElementBinding *elementBinding = _elementBindings[elementHash]; | ||
[elementBinding updateValue:IOHIDValueGetIntegerValue(value)]; | ||
} | ||
|
||
@end |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+15.7 KB
Gamepad Menu/Assets.xcassets/AppIcon.appiconset/AppIcon-128x128@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+32.6 KB
Gamepad Menu/Assets.xcassets/AppIcon.appiconset/AppIcon-256x256@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+68.5 KB
Gamepad Menu/Assets.xcassets/AppIcon.appiconset/AppIcon-512x512@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.