snes9x/macosx/Snes9x/S9xPreferences/S9xPreferencesWindowController.m

380 lines
12 KiB
Mathematica
Raw Normal View History

2019-11-07 05:44:19 +01:00
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
/***********************************************************************************
SNES9X for Mac OS (c) Copyright John Stiles
Snes9x for Mac OS X
(c) Copyright 2001 - 2011 zones
(c) Copyright 2002 - 2005 107
(c) Copyright 2002 PB1400c
(c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 Michael Donald Buckley
***********************************************************************************/
#import <snes9x_framework/snes9x_framework.h>
#import "AppDelegate.h"
#import "S9xPreferencesWindowController.h"
2019-11-07 05:44:19 +01:00
#import "S9xButtonConfigTextField.h"
NSString * const kKeyboardPrefs = @"KeyboardConfig";
NSString * const kJoypadInputPrefs = @"JoypadInputs";
NSString * const kJoypadPlayerPrefs = @"JoypadPlayers";
NSString * const kShowFPSPref = @"ShowFPS";
NSString * const kVideoModePref = @"VideoMode";
NSString * const kMacFrameSkipPref = @"FrameSkip";
@implementation S9xPreferencesWindowController
@synthesize tabView, videoModePopup, showFPSCheckbox, devicePopUp, playerPopUp, macFrameSkipTextField, macFrameSkipStepper, macFrameSkipAutomaticButton, configTextFields;
2019-11-07 05:44:19 +01:00
- (void)windowDidLoad
{
[self refresh];
}
2019-11-07 05:44:19 +01:00
- (void)awakeFromNib
{
AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
NSUInteger joypadIndex = 0;
for (S9xJoypad *joypad in [appDelegate listJoypads])
{
NSMenuItem *item = [NSMenuItem new];
item.title = joypad.name;
item.tag = joypadIndex++;
item.representedObject = joypad;
[self.devicePopUp.menu addItem:item];
}
// collect all S9xButtonConfigTextFields within subviews
NSMutableArray *configTextFields = [[NSMutableArray alloc] init];
for (NSTabViewItem *tabViewItem in self.tabView.tabViewItems) {
[configTextFields addObjectsFromArray:[self getS9xButtonConfigTextFields:tabViewItem.view]];
}
self.configTextFields = configTextFields;
2019-11-07 05:44:19 +01:00
for (S9xButtonConfigTextField *configTextField in self.configTextFields)
{
[configTextField addObserver:self forKeyPath:@"keyCode" options:NSKeyValueObservingOptionNew context:NULL];
[configTextField addObserver:self forKeyPath:@"joypadInput" options:NSKeyValueObservingOptionNew context:NULL];
}
// select Keyboard as default
[self selectDeviceForPlayer:0];
2019-11-07 05:44:19 +01:00
}
- (void)refresh
{
NSUInteger index = MIN([NSUserDefaults.standardUserDefaults integerForKey:kVideoModePref], 1);
[self.videoModePopup selectItemAtIndex:index];
2020-09-13 04:02:42 +02:00
NSInteger macFrameSkipDefault = [NSUserDefaults.standardUserDefaults integerForKey:kMacFrameSkipPref];
// if macFrameSkip is equal to -1, set automatic checkbox
// to be checked, disable the ability to change frame skip values
// from stepper/text field, else leave automatic checkbox
// unchecked and set textfield to value
if (macFrameSkipDefault == -1) {
[self.macFrameSkipTextField setEnabled: false];
[self.macFrameSkipStepper setEnabled: false];
[self.macFrameSkipTextField setIntValue: 0]; // show something at least
[self.macFrameSkipAutomaticButton setIntValue: 1];
} else {
[self.macFrameSkipTextField setIntValue: (int)macFrameSkipDefault];
[self.macFrameSkipAutomaticButton setIntValue: 0];
}
2020-09-13 04:02:42 +02:00
2019-11-07 05:44:19 +01:00
self.showFPSCheckbox.state = [NSUserDefaults.standardUserDefaults boolForKey:kShowFPSPref];
if (self.devicePopUp.selectedItem.tag < 0)
{
NSMutableDictionary<NSNumber *, NSNumber *> *controlsDict = [NSMutableDictionary new];
2019-11-07 05:44:19 +01:00
NSDictionary *keyboardDict = [NSUserDefaults.standardUserDefaults objectForKey:kKeyboardPrefs];
NSInteger playerNum = self.playerPopUp.selectedItem.tag;
for (NSUInteger i = 0; i < kNumButtons; ++i)
{
controlsDict[@(i)] = keyboardDict[@(i + (playerNum * kNumButtons)).stringValue];
2019-11-07 05:44:19 +01:00
}
for (S9xButtonConfigTextField *configTextField in self.configTextFields)
2019-11-07 05:44:19 +01:00
{
[configTextField removeObserver:self forKeyPath:@"keyCode"];
[configTextField removeObserver:self forKeyPath:@"joypadInput"];
2019-11-07 05:44:19 +01:00
NSNumber *keyCode = controlsDict[@(configTextField.tag)];
2019-11-07 05:44:19 +01:00
configTextField.joypadInput = nil;
2019-11-07 05:44:19 +01:00
if ( keyCode != nil )
{
configTextField.keyCode = keyCode.intValue;
}
else
{
configTextField.keyCode = -1;
}
[configTextField addObserver:self forKeyPath:@"keyCode" options:NSKeyValueObservingOptionNew context:NULL];
[configTextField addObserver:self forKeyPath:@"joypadInput" options:NSKeyValueObservingOptionNew context:NULL];
configTextField.disableKeyboardInput = NO;
}
}
else
{
AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
S9xJoypad *joypad = self.devicePopUp.selectedItem.representedObject;
NSString *joypadKey = [appDelegate prefsKeyForVendorID:joypad.vendorID productID:joypad.productID index:joypad.index];
NSDictionary *joypadDIct = [[NSUserDefaults.standardUserDefaults objectForKey:kJoypadInputPrefs] objectForKey:joypadKey];
for (S9xButtonConfigTextField *configTextField in self.configTextFields)
{
[configTextField removeObserver:self forKeyPath:@"keyCode"];
[configTextField removeObserver:self forKeyPath:@"joypadInput"];
uint32 cookie = 0;
int32 value = 0;
S9xButtonCode buttonCode = (S9xButtonCode)configTextField.tag;
NSString *inputString = joypadDIct[@(buttonCode).stringValue];
configTextField.keyCode = -1;
if ([appDelegate getValuesFromString:inputString cookie:&cookie value:&value])
{
S9xJoypadInput *input = [S9xJoypadInput new];
input.cookie = cookie;
input.value = value;
input.buttonCode = buttonCode;
configTextField.joypadInput = input;
configTextField.stringValue = [appDelegate labelForVendorID:joypad.vendorID productID:joypad.productID cookie:cookie value:value];
}
else
{
configTextField.joypadInput = nil;
configTextField.stringValue = @"";
}
[configTextField addObserver:self forKeyPath:@"keyCode" options:NSKeyValueObservingOptionNew context:NULL];
[configTextField addObserver:self forKeyPath:@"joypadInput" options:NSKeyValueObservingOptionNew context:NULL];
configTextField.disableKeyboardInput = YES;
}
}
}
2019-11-07 05:44:19 +01:00
- (NSArray *)getS9xButtonConfigTextFields:(NSView*)view {
NSMutableArray *S9xButtonConfigTextFields = [[NSMutableArray alloc] init];
if ([view isKindOfClass:[S9xButtonConfigTextField class]]) {
[S9xButtonConfigTextFields addObject:view];
} else if (view.subviews) {
for (NSView *subview in view.subviews) {
[S9xButtonConfigTextFields addObjectsFromArray:[self getS9xButtonConfigTextFields:subview]];
}
}
return [NSArray arrayWithArray:S9xButtonConfigTextFields];
}
- (void)selectDeviceForPlayer:(int8_t)player
{
AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
NSString* joypadKey = [[NSUserDefaults.standardUserDefaults objectForKey:kJoypadPlayerPrefs] objectForKey:@(player).stringValue];
[self.devicePopUp selectItemAtIndex:0];
if (joypadKey != nil)
{
uint32 vendorID = 0;
uint32 productID = 0;
uint32 index = 0;
if ( [appDelegate getValuesFromString:joypadKey vendorID:&vendorID productID:&productID index:&index])
{
S9xJoypad *joypad = [S9xJoypad new];
joypad.vendorID = vendorID;
joypad.productID = productID;
joypad.index = index;
for (NSMenuItem *item in self.devicePopUp.menu.itemArray)
{
if ([joypad isEqual:item.representedObject])
{
[self.devicePopUp selectItem:item];
break;
}
}
}
}
}
- (BOOL)handleInput:(S9xJoypadInput *)input fromJoypad:(S9xJoypad *)joypad
{
id firstResponder = self.window.firstResponder;
if ([firstResponder respondsToSelector:@selector(isFieldEditor)] && [firstResponder isFieldEditor])
{
firstResponder = [firstResponder delegate];
}
if ([firstResponder respondsToSelector:@selector(setJoypadInput:)])
{
S9xJoypad *currentJoypad = self.devicePopUp.selectedItem.representedObject;
if ([joypad isEqual:currentJoypad])
{
[firstResponder setJoypadInput:input];
return YES;
2019-11-07 05:44:19 +01:00
}
}
return NO;
2019-11-07 05:44:19 +01:00
}
- (void)deviceSettingChanged:(S9xDeviceSetting)deviceSetting {}
2019-11-07 05:44:19 +01:00
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
if ([keyPath isEqualToString:@"keyCode"])
{
S9xButtonConfigTextField *field = (S9xButtonConfigTextField *)object;
S9xButtonCode buttonCode = (S9xButtonCode)field.tag;
uint16_t keyCode = field.keyCode;
int8_t player = self.playerPopUp.selectedItem.tag;
if (keyCode != (CGKeyCode)-1)
{
[((AppDelegate *) NSApp.delegate) setButtonCode:buttonCode forKeyCode:keyCode player:player];
}
else
{
[((AppDelegate *) NSApp.delegate) clearButton:buttonCode forPlayer:player];
}
[NSUserDefaults.standardUserDefaults synchronize];
2019-11-07 05:44:19 +01:00
[self refresh];
}
else if ( [keyPath isEqualToString:@"joypadInput"])
{
S9xButtonConfigTextField *field = (S9xButtonConfigTextField *)object;
S9xButtonCode buttonCode = (S9xButtonCode)field.tag;
S9xJoypad *joypad = self.devicePopUp.selectedItem.representedObject;
if ([joypad isKindOfClass:[S9xJoypad class]])
{
S9xJoypadInput *input = field.joypadInput;
if (input != nil)
{
[((AppDelegate *)NSApp.delegate) setButton:buttonCode forVendorID:joypad.vendorID productID:joypad.productID index:joypad.index cookie:input.cookie value:input.value];
}
else
{
[((AppDelegate *)NSApp.delegate) clearJoypadForVendorID:joypad.vendorID productID:joypad.productID index:joypad.index buttonCode:buttonCode];
}
}
[NSUserDefaults.standardUserDefaults synchronize];
[self refresh];
}
}
- (void)setShowFPS:(BOOL)value
{
AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
[appDelegate setShowFPS:value];
}
- (void)setVideoMode:(int)value
{
AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
[appDelegate setVideoMode:value];
}
- (void)setMacFrameSkip:(int)value
{
AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
[appDelegate setMacFrameSkip:value];
}
- (IBAction)onToolbarItemPress:(NSToolbarItem *)sender
{
[self.tabView selectTabViewItemAtIndex:sender.tag];
}
- (IBAction)onCheckShowFPS:(NSButton *)sender
2020-09-13 04:02:42 +02:00
{
[self setShowFPS:sender.state == NSOnState];
2020-09-13 04:02:42 +02:00
}
- (IBAction)onSelectVideoMode:(NSPopUpButton *)sender
{
[self setVideoMode:(int)sender.selectedTag];
2019-11-07 05:44:19 +01:00
}
- (IBAction)bumpMacFrameSkip:(NSStepper *)sender
2020-09-13 04:02:42 +02:00
{
int bumpValue = sender.intValue; // 1 or -1
int nextValue = self.macFrameSkipTextField.intValue + bumpValue;
2020-09-13 04:02:42 +02:00
// constrain value
if (nextValue < 0) {
nextValue = 0;
}
if (nextValue > 200) {
nextValue = 200;
}
[self.macFrameSkipTextField setIntValue: nextValue];
2020-09-13 04:02:42 +02:00
[sender setIntValue:0]; // reset stepper value
[self setMacFrameSkip:self.macFrameSkipTextField.intValue]; // execute setter
}
- (IBAction)onChangeMacFrameSkipTextField:(NSTextField *)sender
{
[self setMacFrameSkip:sender.intValue];
}
- (IBAction)onCheckMacFrameSkipAutomaticButton:(NSButton *)sender
{
if (sender.intValue == 1) {
// when automatic is checked, disable macFrameSkipTextField and
// macFrameSkipStepper, then set macFrameSkip to -1 (automatic)
[self.macFrameSkipTextField setEnabled:false];
[self.macFrameSkipStepper setEnabled:false];
[self setMacFrameSkip:-1];
} else {
// when automatic is unchecked, enable macFrameSkipTextField and
// macFrameSkipStepper, then set macFrameSkip to value of text field
[self.macFrameSkipTextField setEnabled:true];
[self.macFrameSkipStepper setEnabled:true];
[self setMacFrameSkip:self.macFrameSkipTextField.intValue];
}
2020-09-13 04:02:42 +02:00
}
- (IBAction)onChangePlayerDropdown:(NSPopUpButton *)sender
{
[self selectDeviceForPlayer:sender.selectedTag];
[self refresh];
}
- (IBAction)onChangeDeviceDropdown:(NSPopUpButton *)sender
{
if (sender.selectedTag >= 0)
{
AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
S9xJoypad *joypad = sender.selectedItem.representedObject;
[appDelegate setPlayer:self.playerPopUp.selectedTag forVendorID:joypad.vendorID productID:joypad.productID index:joypad.index];
[NSUserDefaults.standardUserDefaults synchronize];
}
[self refresh];
}
2019-11-07 05:44:19 +01:00
@end