Mac: Rebuilt Cheat Finder

This commit is contained in:
Michael Buckley 2023-03-25 07:36:29 -07:00
parent 35ea8b4ec9
commit 2e568452c0
19 changed files with 1854 additions and 1358 deletions

View File

@ -33,6 +33,7 @@ extern NSWindowFrameAutosaveName const kMainWindowIdentifier;
@property (nonatomic, strong) NSWindow *gameWindow; @property (nonatomic, strong) NSWindow *gameWindow;
@property (nonatomic, strong) S9xPreferencesWindowController *preferencesWindowController; @property (nonatomic, strong) S9xPreferencesWindowController *preferencesWindowController;
@property (nonatomic, strong) NSWindowController *cheatsWindowController; @property (nonatomic, strong) NSWindowController *cheatsWindowController;
@property (nonatomic, strong) NSWindowController *cheatFinderWindowController;
@property (nonatomic, readonly, assign) S9xDeviceSetting deviceSetting; @property (nonatomic, readonly, assign) S9xDeviceSetting deviceSetting;
- (void)setButtonCode:(S9xButtonCode)buttonCode forKeyCode:(int16)keyCode player:(int8)player; - (void)setButtonCode:(S9xButtonCode)buttonCode forKeyCode:(int16)keyCode player:(int8)player;

View File

@ -21,9 +21,14 @@
#import <Carbon/Carbon.h> #import <Carbon/Carbon.h>
#import "AppDelegate.h" #import "AppDelegate.h"
#import "S9xPreferencesConstants.h" #import "S9xPreferencesConstants.h"
#import "S9xCheatFinderViewController.h"
NSWindowFrameAutosaveName const kMainWindowIdentifier = @"s9xMainWindow"; NSWindowFrameAutosaveName const kMainWindowIdentifier = @"s9xMainWindow";
NSWindowFrameAutosaveName const kCheatsWindowIdentifier = @"s9xCheatsWindow"; NSWindowFrameAutosaveName const kCheatsWindowIdentifier = @"s9xCheatsWindow";
NSWindowFrameAutosaveName const kCheatFinderWindowIdentifier = @"s9xCheatFinderWindow";
@interface AppDelegate () <S9xCheatFinderDelegate>
@end
@implementation AppDelegate @implementation AppDelegate
@ -638,4 +643,39 @@ NSWindowFrameAutosaveName const kCheatsWindowIdentifier = @"s9xCheatsWindow";
[NSUserDefaults.standardUserDefaults setBool:self.s9xEngine.cheatsEnabled forKey:kEnableCheatsPref]; [NSUserDefaults.standardUserDefaults setBool:self.s9xEngine.cheatsEnabled forKey:kEnableCheatsPref];
} }
- (IBAction)openCheatFinderWindow:(id)sender
{
if ( self.cheatFinderWindowController == nil )
{
S9xCheatFinderViewController *vc = [[S9xCheatFinderViewController alloc] initWithNibName:@"S9xCheatFinderViewController" bundle:nil];
vc.engine = self.s9xEngine;
vc.delegate = self;
NSWindow *window = [NSWindow windowWithContentViewController:vc];
self.cheatFinderWindowController = [[NSWindowController alloc] initWithWindow:window];
window = self.cheatFinderWindowController.window;
window.title = NSLocalizedString(@"Cheat Finder", nil);
window.restorationClass = self.class;
window.frameAutosaveName = kCheatFinderWindowIdentifier;
window.releasedWhenClosed = NO;
if ( ![window setFrameUsingName:kCheatFinderWindowIdentifier] )
{
[window center];
}
}
[self.cheatFinderWindowController showWindow:nil];
[self.cheatFinderWindowController.window makeKeyAndOrderFront:nil];
[self.cheatFinderWindowController.window makeKeyWindow];
}
- (void)addedCheat
{
[((S9xCheatsViewController *)self.cheatsWindowController.contentViewController) deselectAll];
[((S9xCheatsViewController *)self.cheatsWindowController.contentViewController) reloadData];
}
@end @end

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> <document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies> <dependencies>
<deployment identifier="macosx"/> <deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19529"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
</dependencies> </dependencies>
<objects> <objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication"> <customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@ -404,12 +404,18 @@
<action selector="toggleCheats:" target="-1" id="IZg-ZR-9iA"/> <action selector="toggleCheats:" target="-1" id="IZg-ZR-9iA"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Show Cheats" id="9oz-Uu-GkA"> <menuItem title="Show Cheats" id="9oz-Uu-GkA">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="openCheatsWindow:" target="-1" id="VdR-bM-JgN"/> <action selector="openCheatsWindow:" target="-1" id="VdR-bM-JgN"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Cheat Finder…" id="FVY-1R-MN4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="openCheatFinderWindow:" target="-1" id="6gG-03-7xm"/>
</connections>
</menuItem>
</items> </items>
</menu> </menu>
</menuItem> </menuItem>

View File

@ -28,6 +28,13 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithCheatItem:(nullable S9xCheatItem *)cheatItem saveCallback:(void (^)(void))saveCallback; - (instancetype)initWithCheatItem:(nullable S9xCheatItem *)cheatItem saveCallback:(void (^)(void))saveCallback;
- (void)updateSaveButton;
@property (nonatomic, weak) IBOutlet NSTextField *codeField;
@property (nonatomic, weak) IBOutlet NSTextField *descriptionField;
@property (nonatomic, weak) IBOutlet NSTextField *addressField;
@property (nonatomic, weak) IBOutlet NSTextField *valueField;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@ -25,10 +25,6 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@interface S9xCheatEditViewController () <NSTextFieldDelegate> @interface S9xCheatEditViewController () <NSTextFieldDelegate>
@property (nonatomic, weak) IBOutlet NSTextField *codeField;
@property (nonatomic, weak) IBOutlet NSTextField *descriptionField;
@property (nonatomic, weak) IBOutlet NSTextField *addressField;
@property (nonatomic, weak) IBOutlet NSTextField *valueField;
@property (nonatomic, weak) IBOutlet NSTextField *invalidCodeLabel; @property (nonatomic, weak) IBOutlet NSTextField *invalidCodeLabel;
@property (nonatomic, weak) IBOutlet NSButton *saveButton; @property (nonatomic, weak) IBOutlet NSButton *saveButton;

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> <document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies> <dependencies>
<deployment identifier="macosx"/> <deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19529"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<objects> <objects>

View File

@ -0,0 +1,38 @@
/*****************************************************************************\
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 - 2023 Michael Donald Buckley
***********************************************************************************/
#import <Cocoa/Cocoa.h>
#import <snes9x_framework/snes9x_framework.h>
NS_ASSUME_NONNULL_BEGIN
@protocol S9xCheatFinderDelegate <NSObject>
- (void)addedCheat;
@end
@interface S9xCheatFinderViewController : NSViewController
@property (nonatomic, strong) S9xEngine *engine;
@property (nonatomic, weak) id<S9xCheatFinderDelegate> delegate;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,927 @@
/*****************************************************************************\
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 - 2023 Michael Donald Buckley
***********************************************************************************/
#import <snes9x_framework/snes9x_framework.h>
#import "S9xCheatFinderViewController.h"
#import "S9xCheatEditViewController.h"
#import "S9xHexNumberFormatter.h"
#define MAIN_MEMORY_SIZE 0x20000
#define MAIN_MEMORY_BASE 0x7E0000
#define MAX_WATCHES 16
typedef NS_ENUM(uint32_t, S9xCheatFinderByteSize) {
S9xCheatFinderByteSize1 = 1,
S9xCheatFinderByteSize2 = 2,
S9xCheatFinderByteSize3 = 3,
S9xCheatFinderByteSize4 = 4
};
typedef NS_ENUM(uint32_t, S9xCheatFinderValueType) {
S9xCheatFinderValueTypeUnsigned = 101,
S9xCheatFinderValueTypeSigned = 102,
S9xCheatFinderValueTypeHexadecimal = 103
};
typedef NS_ENUM(uint32_t, S9xCheatFinderComparisonType) {
S9xCheatFinderComparisonTypeEqual = 0,
S9xCheatFinderComparisonTypeNotEqual = 1,
S9xCheatFinderComparisonTypeGreaterThan = 2,
S9xCheatFinderComparisonTypeGreaterThanOrEqual = 3,
S9xCheatFinderComparisonTypeLessThan = 4,
S9xCheatFinderComparisonTypeLessThanOrEqual = 5
};
typedef NS_ENUM(uint32_t, S9xCheatFinderCompareTo) {
S9xCheatFinderCompareToCustom = 200,
S9xCheatFinderCompareToPrevious = 201,
S9xCheatFinderCompareToStored = 202
};
typedef NS_ENUM(uint32_t, S9xCheatFinderWatchSegments) {
S9xCheatFinderWatchSegmentsAdd = 0,
S9xCheatFinderWatchSegmentsRemove = 1,
S9xCheatFinderWatchSegmentsSave = 2,
S9xCheatFinderWatchSegmentsLoad = 3
};
@interface S9xCheatFinderTableView : NSTableView
@property (nonatomic, strong, nullable) void (^deleteBlock)(NSIndexSet *);
@end
@interface S9xCheatFinderViewController () <NSTableViewDataSource, NSTableViewDelegate, NSTextFieldDelegate, S9xEmulationDelegate>
@property (nonatomic, weak) IBOutlet S9xCheatFinderTableView *addressTableView;
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *addressTableWidthConstraint;
@property (nonatomic, weak) IBOutlet NSPopUpButton *byteSizePopUp;
@property (nonatomic, weak) IBOutlet NSPopUpButton *comparisonTypePopUp;
@property (nonatomic, weak) IBOutlet NSTextField *customValueField;
@property (nonatomic, weak) IBOutlet NSButton *resetButon;
@property (nonatomic, weak) IBOutlet NSButton *searchButton;
@property (nonatomic, weak) IBOutlet NSButton *addCheatButton;
@property (nonatomic, weak) IBOutlet S9xCheatFinderTableView *watchTableView;
@property (nonatomic, weak) IBOutlet NSSegmentedControl *watchButtonsSegmentedControl;
@property (nonatomic, readonly, assign) S9xCheatFinderByteSize byteSize;
@property (nonatomic, readonly, assign) S9xCheatFinderValueType valueType;
@property (nonatomic, readonly, assign) S9xCheatFinderComparisonType compareType;
@property (nonatomic, readonly, assign) S9xCheatFinderCompareTo compareTo;
@property (nonatomic, readonly, strong) NSNumber *customValue;
@end
@interface S9xCheatFinderEntry : NSObject
@property (nonatomic, assign) uint32_t address;
@property (nonatomic, assign) uint32_t value;
@property (nonatomic, assign) uint32_t prevValue;
@property (nonatomic, assign) uint32_t storedValue;
@end
@implementation S9xCheatFinderViewController
{
BOOL _hasStored;
BOOL _hasPrevious;
uint8_t _storedRAM[MAIN_MEMORY_SIZE];
uint8_t _previousRAM[MAIN_MEMORY_SIZE];
uint8_t _currentRAM[MAIN_MEMORY_SIZE];
uint8_t _statusFlag[MAIN_MEMORY_SIZE];
NSMutableArray<S9xCheatFinderEntry *> *_addressRows;
NSMutableArray<S9xWatchPoint *> *_watchRows;
NSNumberFormatter *_unsignedFormatter;
NSNumberFormatter *_signedFormatter;
NSNumberFormatter *_hexFormatter;
BOOL _shouldReopen;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_unsignedFormatter = [NSNumberFormatter new];
_unsignedFormatter.minimum = @(0);
_unsignedFormatter.maximum = @(UINT_MAX);
_signedFormatter = [NSNumberFormatter new];
_signedFormatter.minimum = @(INT_MIN);
_signedFormatter.maximum = @(INT_MAX);
_hexFormatter = [S9xHexNumberFormatter new];
[NSNotificationCenter.defaultCenter addObserverForName:NSPreferredScrollerStyleDidChangeNotification object:nil queue:NSOperationQueue.mainQueue usingBlock:^(NSNotification *notification)
{
[self updateScrollBar];
}];
__weak S9xCheatFinderViewController *weakSelf = self;
self.addressTableView.deleteBlock = ^(NSIndexSet *deletedIndexes)
{
__strong S9xCheatFinderViewController *strongSelf = weakSelf;
[deletedIndexes enumerateIndexesUsingBlock:^(NSUInteger i, BOOL *stop)
{
S9xCheatFinderEntry *entry = strongSelf->_addressRows[i];
strongSelf->_statusFlag[entry.address] = 0;
strongSelf.resetButon.enabled = YES;
}];
[strongSelf reloadData];
};
self.watchTableView.deleteBlock = ^(NSIndexSet *deletedIndexes)
{
__strong S9xCheatFinderViewController *strongSelf = weakSelf;
[strongSelf->_watchRows removeObjectsAtIndexes:deletedIndexes];
[strongSelf.engine setWatchPoints:self->_watchRows];
[strongSelf reloadWatchPoints];
};
[self resetAll];
}
- (void)viewWillAppear
{
[super viewWillAppear];
[self updateScrollBar];
[self.engine copyRAM:(uint8_t *)_currentRAM length:sizeof(_currentRAM)];
[self reloadData];
[self reloadWatchPoints];
}
- (void)viewWillDisappear
{
[super viewWillDisappear];
[self copyPrevious];
}
- (void)resetAll
{
[self.byteSizePopUp selectItemWithTag:S9xCheatFinderByteSize2];
((NSButton *)[self.view viewWithTag:S9xCheatFinderValueTypeUnsigned]).state = NSControlStateValueOn;
((NSButton *)[self.view viewWithTag:S9xCheatFinderCompareToCustom]).state = NSControlStateValueOn;
((NSButton *)[self.view viewWithTag:S9xCheatFinderCompareToPrevious]).enabled = NO;
((NSButton *)[self.view viewWithTag:S9xCheatFinderCompareToStored]).enabled = NO;
self.resetButon.enabled = NO;
self.searchButton.enabled = NO;
self.addCheatButton.enabled = NO;
[self.comparisonTypePopUp selectItemWithTag:S9xCheatFinderComparisonTypeEqual];
self.customValueField.stringValue = @"";
self.customValueField.formatter = _unsignedFormatter;
_hasStored = NO;
_hasPrevious = NO;
_shouldReopen = NO;
self.engine.emulationDelegate = self;
[self.engine copyRAM:(uint8_t *)_currentRAM length:sizeof(_currentRAM)];
[self.engine setWatchPoints:@[]];
[self reset:self];
}
- (void)copyPrevious
{
memcpy(_previousRAM, _currentRAM, MAIN_MEMORY_SIZE);
_hasPrevious = YES;
((NSButton *)[self.view viewWithTag:S9xCheatFinderCompareToPrevious]).enabled = YES;
}
- (void)reloadData
{
NSMutableSet<NSNumber *> *selectedAddresses = [NSMutableSet new];
[self.addressTableView.selectedRowIndexes enumerateIndexesUsingBlock:^(NSUInteger i, BOOL *stop)
{
[selectedAddresses addObject:@(_addressRows[i].address)];
}];
_addressRows = [NSMutableArray new];
for ( NSUInteger i = 0; i < MAIN_MEMORY_SIZE; ++i )
{
if ( _statusFlag[i] )
{
S9xCheatFinderEntry *entry = [S9xCheatFinderEntry new];
entry.address = (uint32_t)i;
entry.value = [self copyValueFrom:_currentRAM index:i];
entry.prevValue = [self copyValueFrom:_previousRAM index:i];
entry.storedValue = [self copyValueFrom:_storedRAM index:i];
[_addressRows addObject:entry];
}
}
[self.addressTableView reloadData];
NSIndexSet *newRows = [_addressRows indexesOfObjectsPassingTest:^(S9xCheatFinderEntry *entry, NSUInteger i, BOOL *stop)
{
return [selectedAddresses containsObject:@(entry.address)];
}];
[self.addressTableView selectRowIndexes:newRows byExtendingSelection:NO];
}
- (void)reloadWatchPoints
{
_watchRows = [[self.engine getWatchPoints] mutableCopy];
[self.watchTableView reloadData];
}
- (uint32_t)copyValueFrom:(uint8_t *)buffer index:(NSUInteger)index
{
uint32_t value = 0;
NSInteger size = self.byteSize;
if (size + index >= MAIN_MEMORY_SIZE)
{
size = MAIN_MEMORY_SIZE - index;
}
memcpy(&value, &(buffer[index]), size);
return value;
}
- (NSString *)stringFor:(uint8_t *)buffer index:(NSUInteger)index
{
uint32_t value = [self copyValueFrom:buffer index:index];
NSString *string = nil;
switch (self.valueType)
{
case S9xCheatFinderValueTypeUnsigned:
string = [NSString stringWithFormat:@"%u", value];
break;
case S9xCheatFinderValueTypeSigned:
switch (self.byteSize)
{
case S9xCheatFinderByteSize1:
string = [NSString stringWithFormat:@"%d", (int8_t)value];
break;
case S9xCheatFinderByteSize2:
string = [NSString stringWithFormat:@"%d", (int16_t)value];
break;
case S9xCheatFinderByteSize3:
if (value >= (1 << 23))
{
value = (int32_t)value - (1 << 24);
}
string = [NSString stringWithFormat:@"%d", value];
break;
case S9xCheatFinderByteSize4:
string = [NSString stringWithFormat:@"%d", value];
break;
}
break;
case S9xCheatFinderValueTypeHexadecimal:
{
switch(self.byteSize)
{
case S9xCheatFinderByteSize1:
string = [NSString stringWithFormat:@"%02X", value];
break;
case S9xCheatFinderByteSize2:
string = [NSString stringWithFormat:@"%04X", value];
break;
case S9xCheatFinderByteSize3:
string = [NSString stringWithFormat:@"%06X", value];
break;
case S9xCheatFinderByteSize4:
string = [NSString stringWithFormat:@"%08X", value];
break;
}
break;
}
}
return string;
}
- (void)updateSearchButton
{
switch (self.compareTo)
{
case S9xCheatFinderCompareToCustom:
self.searchButton.enabled = self.customValueField.stringValue.length > 0;
break;
case S9xCheatFinderCompareToPrevious:
self.searchButton.enabled = _hasPrevious;
break;
case S9xCheatFinderCompareToStored:
self.searchButton.enabled = _hasStored;
break;
}
}
- (void)updateWatchButtons
{
NSInteger numAddressesSelected = self.addressTableView.numberOfSelectedRows;
NSUInteger numWatches = _watchRows.count;
NSInteger numWatchesSelected = self.watchTableView.numberOfSelectedRows;
[self.watchButtonsSegmentedControl setEnabled:numAddressesSelected > 0 && numAddressesSelected + numWatches <= MAX_WATCHES forSegment:S9xCheatFinderWatchSegmentsAdd];
[self.watchButtonsSegmentedControl setEnabled:numWatchesSelected > 0 forSegment:(NSInteger)S9xCheatFinderWatchSegmentsRemove];
[self.watchButtonsSegmentedControl setEnabled:numWatches != 0 forSegment:S9xCheatFinderWatchSegmentsSave];
}
- (void)updateScrollBar
{
const CGFloat defaultWidth = 393.0;
const CGFloat scrollbarWidth = 15.0;
if (NSScroller.preferredScrollerStyle == NSScrollerStyleLegacy)
{
self.addressTableWidthConstraint.constant = defaultWidth + scrollbarWidth;
}
else
{
self.addressTableWidthConstraint.constant = defaultWidth;
}
[self.view layout];
[self.addressTableView sizeLastColumnToFit];
[self.watchTableView sizeLastColumnToFit];
}
#pragma mark - Actions
- (IBAction)storeValues:(id)sender
{
memcpy(_storedRAM, _currentRAM, MAIN_MEMORY_SIZE);
_hasStored = YES;
((NSButton *)[self.view viewWithTag:S9xCheatFinderCompareToStored]).enabled = YES;
[self reloadData];
[self updateSearchButton];
}
- (IBAction)reset:(id)sender
{
memset(_statusFlag, 1, sizeof(_statusFlag));
self.resetButon.enabled = NO;
[self reloadData];
[self updateSearchButton];
[self.addressTableView deselectAll:self];
[self.watchTableView deselectAll:self];
[self updateWatchButtons];
}
- (IBAction)search:(id)sender
{
NSMutableIndexSet *rowsToRemove = [NSMutableIndexSet new];
NSNumber *customValue = self.customValue;
S9xCheatFinderValueType valueType = self.valueType;
S9xCheatFinderComparisonType comparisonType = self.compareType;
S9xCheatFinderCompareTo compareTo = self.compareTo;
for (S9xCheatFinderEntry *entry in _addressRows)
{
switch(valueType)
{
case S9xCheatFinderValueTypeUnsigned:
case S9xCheatFinderValueTypeHexadecimal:
{
uint32_t value = [self copyValueFrom:_currentRAM index:entry.address];
uint32_t comparedValue;
switch(compareTo)
{
case S9xCheatFinderCompareToCustom:
comparedValue = customValue.unsignedIntValue;
break;
case S9xCheatFinderCompareToStored:
comparedValue = [self copyValueFrom:_storedRAM index:entry.address];
break;
case S9xCheatFinderCompareToPrevious:
comparedValue = [self copyValueFrom:_previousRAM index:entry.address];
break;
}
switch(comparisonType)
{
case S9xCheatFinderComparisonTypeEqual:
_statusFlag[entry.address] = (value == comparedValue);
break;
case S9xCheatFinderComparisonTypeNotEqual:
_statusFlag[entry.address] = (value != comparedValue);
break;
case S9xCheatFinderComparisonTypeGreaterThan:
_statusFlag[entry.address] = (value > comparedValue);
break;
case S9xCheatFinderComparisonTypeGreaterThanOrEqual:
_statusFlag[entry.address] = (value >= comparedValue);
break;
case S9xCheatFinderComparisonTypeLessThan:
_statusFlag[entry.address] = (value < comparedValue);
break;
case S9xCheatFinderComparisonTypeLessThanOrEqual:
_statusFlag[entry.address] = (value <= comparedValue);
break;
}
break;
}
case S9xCheatFinderValueTypeSigned:
{
int32_t value = [self copyValueFrom:_currentRAM index:entry.address];
int32_t comparedValue;
switch(compareTo)
{
case S9xCheatFinderCompareToCustom:
comparedValue = customValue.intValue;
break;
case S9xCheatFinderCompareToStored:
comparedValue = [self copyValueFrom:_storedRAM index:entry.address];
break;
case S9xCheatFinderCompareToPrevious:
comparedValue = [self copyValueFrom:_previousRAM index:entry.address];
break;
}
switch(comparisonType)
{
case S9xCheatFinderComparisonTypeEqual:
_statusFlag[entry.address] = (value == comparedValue);
break;
case S9xCheatFinderComparisonTypeNotEqual:
_statusFlag[entry.address] = (value != comparedValue);
break;
case S9xCheatFinderComparisonTypeGreaterThan:
_statusFlag[entry.address] = (value > comparedValue);
break;
case S9xCheatFinderComparisonTypeGreaterThanOrEqual:
_statusFlag[entry.address] = (value >= comparedValue);
break;
case S9xCheatFinderComparisonTypeLessThan:
_statusFlag[entry.address] = (value < comparedValue);
break;
case S9xCheatFinderComparisonTypeLessThanOrEqual:
_statusFlag[entry.address] = (value <= comparedValue);
break;
}
break;
}
}
}
[_addressRows removeObjectsAtIndexes:rowsToRemove];
[self reloadData];
[self updateWatchButtons];
self.resetButon.enabled = YES;
}
- (IBAction)reload:(id)sender
{
[self reloadData];
}
- (IBAction)setFormat:(id)sender
{
[self reloadData];
S9xCheatFinderValueType valueType = (S9xCheatFinderValueType)[sender tag];
NSNumber *value = self.customValue;
switch (valueType)
{
case S9xCheatFinderValueTypeUnsigned:
self.customValueField.formatter = _unsignedFormatter;
break;
case S9xCheatFinderValueTypeSigned:
self.customValueField.formatter = _signedFormatter;
break;
case S9xCheatFinderValueTypeHexadecimal:
self.customValueField.formatter = _hexFormatter;
break;
}
self.customValueField.stringValue = [self.customValueField.formatter stringForObjectValue:value];
}
- (IBAction)setCompareTarget:(id)sender
{
[self reloadData];
[self updateSearchButton];
[self updateWatchButtons];
}
- (IBAction)addCheat:(id)sender
{
S9xCheatFinderEntry *entry = _addressRows[self.addressTableView.selectedRow];
S9xCheatEditViewController *vc = [[S9xCheatEditViewController alloc] initWithCheatItem:nil saveCallback:^
{
[self.delegate addedCheat];
}];
[self presentViewControllerAsSheet:vc];
vc.addressField.objectValue = @(entry.address + MAIN_MEMORY_BASE);
vc.valueField.objectValue = @(_currentRAM[entry.address]);
[vc.view.window makeFirstResponder:vc.descriptionField];
[vc updateSaveButton];
}
- (IBAction)watchesAction:(NSSegmentedControl *)sender
{
switch((S9xCheatFinderWatchSegments)sender.selectedSegment)
{
case S9xCheatFinderWatchSegmentsAdd:
{
NSIndexSet *selectedIndexes = self.addressTableView.selectedRowIndexes;
[selectedIndexes enumerateIndexesUsingBlock:^(NSUInteger i, BOOL *stop)
{
S9xWatchPoint *watchPoint = [S9xWatchPoint new];
S9xCheatFinderEntry *entry = _addressRows[i];
watchPoint.address = entry.address + MAIN_MEMORY_BASE;
watchPoint.size = self.byteSize;
watchPoint.format = self.valueType - 100;
[_watchRows addObject:watchPoint];
}];
[self.engine setWatchPoints:_watchRows];
[self reloadWatchPoints];
break;
}
case S9xCheatFinderWatchSegmentsRemove:
{
[_watchRows removeObjectsAtIndexes:self.watchTableView.selectedRowIndexes];
[self reloadWatchPoints];
break;
}
case S9xCheatFinderWatchSegmentsSave:
{
NSSavePanel *savePanel = [NSSavePanel new];
savePanel.nameFieldStringValue = @"watches.txt";
[savePanel beginSheetModalForWindow:self.view.window completionHandler:^(NSModalResponse response)
{
if (response == NSModalResponseOK)
{
FILE *file = fopen(savePanel.URL.path.UTF8String, "wb");
if (file != NULL)
{
for ( S9xWatchPoint *watchPoint in self->_watchRows)
{
fprintf(file, "address = 0x%x, name = \"?\", size = %d, format = %d\n", watchPoint.address, watchPoint.size, watchPoint.format);
}
fclose(file);
}
}
}];
break;
}
case S9xCheatFinderWatchSegmentsLoad:
{
NSOpenPanel *openPanel = [NSOpenPanel new];
openPanel.allowsMultipleSelection = NO;
openPanel.canChooseDirectories = NO;
[openPanel beginSheetModalForWindow:self.view.window completionHandler:^(NSModalResponse response)
{
FILE *file = fopen(openPanel.URL.path.UTF8String, "rb");
if (file != NULL)
{
self->_watchRows = [NSMutableArray new];
for (NSUInteger i = 0; i < MAX_WATCHES; ++i)
{
uint32_t address;
uint32_t size;
uint32_t format;
char ignore[32];
fscanf(file, "address = 0x%x, name = \"%31[^\"]\", size = %d, format = %d\n", &address, ignore, &size, &format);
if (ferror(file))
{
break;
}
S9xWatchPoint *watchPoint = [S9xWatchPoint new];
watchPoint.address = address;
watchPoint.size = size;
watchPoint.format = format;
[self->_watchRows addObject:watchPoint];
if(feof(file))
{
break;
}
}
fclose(file);
[self.engine setWatchPoints:self->_watchRows];
[self reloadWatchPoints];
}
}];
}
}
}
#pragma mark - Emulation Delegate
- (void)gameLoaded
{
[self resetAll];
[self emulationResumed];
}
- (void)emulationPaused
{
if (!NSThread.isMainThread)
{
dispatch_sync(dispatch_get_main_queue(), ^
{
[self emulationPaused];
});
}
else if (_shouldReopen)
{
[self.view.window makeKeyAndOrderFront:self];
_shouldReopen = NO;
}
}
- (void)emulationResumed
{
if (!NSThread.isMainThread)
{
dispatch_sync(dispatch_get_main_queue(), ^
{
[self emulationResumed];
});
}
else
{
if ([self.view.window isVisible])
{
[self.view.window close];
_shouldReopen = YES;
}
[self reloadData];
}
}
#pragma mark - Table View Delegate
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
if (tableView == self.addressTableView)
{
return _addressRows.count;
}
else
{
return _watchRows.count;
}
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSString *value = [self tableView:tableView objectValueForTableColumn:tableColumn row:row];
NSTableCellView *cell = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
cell.textField.stringValue = value;
return cell;
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
if (tableView == self.addressTableView)
{
S9xCheatFinderEntry *entry = _addressRows[row];
if ([tableColumn.identifier isEqualToString:@"address"])
{
return [NSString stringWithFormat:@"%06X", entry.address + MAIN_MEMORY_BASE];
}
else if ([tableColumn.identifier isEqualToString:@"currentValue"])
{
return [self stringFor:_currentRAM index:entry.address];
}
else if ([tableColumn.identifier isEqualToString:@"previousValue"])
{
if (!_hasPrevious)
{
return @"";
}
return [self stringFor:_previousRAM index:entry.address];
}
else if ( [tableColumn.identifier isEqualToString:@"storedValue"])
{
if (!_hasStored)
{
return @"";
}
return [self stringFor:_storedRAM index:entry.address];
}
return @"";
}
else
{
S9xWatchPoint *watchPoint = _watchRows[row];
NSString *formatString;
switch((S9xCheatFinderValueType)(watchPoint.format + 100))
{
case S9xCheatFinderValueTypeSigned:
formatString = @"s";
break;
case S9xCheatFinderValueTypeUnsigned:
formatString = @"u";
break;
case S9xCheatFinderValueTypeHexadecimal:
formatString = @"x";
break;
}
return [NSString stringWithFormat:@"%06X,%d%@", watchPoint.address, watchPoint.size, formatString];
}
}
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
self.addCheatButton.enabled = self.addressTableView.numberOfSelectedRows == 1;
[self updateWatchButtons];
}
#pragma mark - Text Field Delegate
- (void)controlTextDidChange:(NSNotification *)obj
{
[self updateSearchButton];
}
#pragma mark - Accessors
@dynamic byteSize;
- (S9xCheatFinderByteSize)byteSize
{
return (S9xCheatFinderByteSize)[self.byteSizePopUp selectedTag];
}
- (S9xCheatFinderValueType)valueType
{
S9xCheatFinderValueType valueType;
if (((NSButton *)[self.view viewWithTag:S9xCheatFinderValueTypeUnsigned]).state == NSOnState)
{
valueType = S9xCheatFinderValueTypeUnsigned;
}
else if (((NSButton *)[self.view viewWithTag:S9xCheatFinderValueTypeSigned]).state == NSOnState)
{
valueType = S9xCheatFinderValueTypeSigned;
}
else
{
valueType = S9xCheatFinderValueTypeHexadecimal;
}
return valueType;
}
@dynamic compareType;
- (S9xCheatFinderComparisonType)compareType
{
return (S9xCheatFinderComparisonType)self.comparisonTypePopUp.selectedTag;
}
@dynamic compareTo;
- (S9xCheatFinderCompareTo)compareTo
{
S9xCheatFinderCompareTo compareTo;
if (((NSButton *)[self.view viewWithTag:S9xCheatFinderCompareToCustom]).state == NSOnState)
{
compareTo = S9xCheatFinderCompareToCustom;
}
else if (((NSButton *)[self.view viewWithTag:S9xCheatFinderCompareToStored]).state == NSOnState)
{
compareTo = S9xCheatFinderCompareToStored;
}
else
{
compareTo = S9xCheatFinderCompareToPrevious;
}
return compareTo;
}
@dynamic customValue;
- (NSNumber *)customValue
{
return [((NSNumberFormatter *)self.customValueField.formatter) numberFromString:self.customValueField.stringValue];
}
@end
@implementation S9xCheatFinderTableView
- (void)keyDown:(NSEvent *)event
{
if ( [event.characters isEqualToString:@"\b"] || [event.characters isEqualToString:@"\x7f"] )
{
if (self.deleteBlock != nil && self.numberOfSelectedRows > 0)
{
self.deleteBlock(self.selectedRowIndexes);
}
}
else
{
[super keyDown:event];
}
}
@end
@implementation S9xCheatFinderEntry
@end

View File

@ -0,0 +1,530 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="S9xCheatFinderViewController">
<connections>
<outlet property="addCheatButton" destination="ut3-qV-HGo" id="tjX-Gg-J4f"/>
<outlet property="addressTableView" destination="sYl-gL-DD1" id="8cU-16-9xx"/>
<outlet property="addressTableWidthConstraint" destination="Icm-wc-CD6" id="R2l-by-fFC"/>
<outlet property="byteSizePopUp" destination="cRe-AN-vwd" id="Jsr-J6-K3O"/>
<outlet property="comparisonTypePopUp" destination="8E0-uI-3yG" id="9Pb-eL-qnZ"/>
<outlet property="customValueField" destination="eXx-ny-Tok" id="jOO-1g-ZrX"/>
<outlet property="resetButon" destination="Iue-dD-GsP" id="iZY-so-mm9"/>
<outlet property="searchButton" destination="kaT-sZ-PRb" id="OmJ-QB-kyt"/>
<outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/>
<outlet property="watchButtonsSegmentedControl" destination="rg7-go-Amx" id="adb-5o-3fI"/>
<outlet property="watchTableView" destination="0yj-jc-bsT" id="mxE-U8-j3A"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="Hz6-mo-xeY">
<rect key="frame" x="0.0" y="0.0" width="641" height="504"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ut3-qV-HGo">
<rect key="frame" x="521" y="208" width="107" height="32"/>
<buttonCell key="cell" type="push" title="Add Cheat…" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="s8c-70-5VV">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="addCheat:" target="-2" id="1E5-9d-VrX"/>
</connections>
</button>
<button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Iue-dD-GsP">
<rect key="frame" x="414" y="240" width="108" height="32"/>
<buttonCell key="cell" type="push" title="Reset" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="1IS-Dv-QTo">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="reset:" target="-2" id="tKx-xy-lZs"/>
</connections>
</button>
<scrollView autohidesScrollers="YES" horizontalLineScroll="24" horizontalPageScroll="10" verticalLineScroll="24" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Z8O-p3-OZ8">
<rect key="frame" x="20" y="20" width="393" height="464"/>
<clipView key="contentView" id="85a-zn-2E6">
<rect key="frame" x="1" y="1" width="391" height="462"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" rowHeight="24" rowSizeStyle="automatic" headerView="iN8-VY-ogh" viewBased="YES" id="sYl-gL-DD1" customClass="S9xCheatFinderTableView">
<rect key="frame" x="0.0" y="0.0" width="393" height="434"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="17" height="0.0"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="address" width="68" minWidth="68" maxWidth="68" id="PCE-6l-BBu">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Address">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="Zdc-Os-Bi7">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="address" id="0NR-A5-OjJ">
<rect key="frame" x="8" y="0.0" width="66" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Dgd-on-ZeT">
<rect key="frame" x="0.0" y="4" width="69" height="16"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="00000000" id="cwC-aq-IFr">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="Dgd-on-ZeT" id="WQq-mc-hYk"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="currentValue" width="86" minWidth="86" maxWidth="86" id="Vwl-qJ-uNZ">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Current">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="HkI-7L-JeO">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="currentValue" id="ZOd-kp-vCM">
<rect key="frame" x="91" y="0.0" width="86" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="i95-bi-omC">
<rect key="frame" x="0.0" y="4" width="103" height="16"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="-2147483648" id="psi-UC-PXB">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="i95-bi-omC" id="ggC-ha-GoA"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="previousValue" width="86" minWidth="86" maxWidth="86" id="dJ6-AP-GhI">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Previous">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="kX1-a6-V9h">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="previousValue" id="31E-xj-mDP">
<rect key="frame" x="194" y="0.0" width="86" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Wh7-NY-USM">
<rect key="frame" x="0.0" y="4" width="103" height="16"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="-2147483648" id="qr7-q7-sej">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="Wh7-NY-USM" id="DNK-1e-gIq"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="storedValue" width="90" minWidth="90" maxWidth="1000" id="oWj-Ws-aMa">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Stored">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" identifier="storedValue" title="Text Cell" id="scu-B5-zJ7">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView id="8y9-1G-mD4">
<rect key="frame" x="297" y="0.0" width="87" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iql-ZD-Qi4">
<rect key="frame" x="0.0" y="4" width="104" height="16"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="-2147483648" id="aIg-2X-Ccv">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="iql-ZD-Qi4" id="6ZO-oj-X2D"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="-2" id="Lq4-TH-tMo"/>
<outlet property="delegate" destination="-2" id="BcQ-I0-UPf"/>
</connections>
</tableView>
</subviews>
</clipView>
<constraints>
<constraint firstAttribute="width" constant="393" id="Icm-wc-CD6"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="had-bq-XTh">
<rect key="frame" x="-100" y="-100" width="392" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="FyW-kM-PC8">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" wantsLayer="YES" id="iN8-VY-ogh">
<rect key="frame" x="0.0" y="0.0" width="393" height="28"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="CJT-h8-WOU">
<rect key="frame" x="419" y="468" width="117" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Value Size:" id="OxX-tw-Vqn">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="cRe-AN-vwd">
<rect key="frame" x="539" y="461" width="86" height="25"/>
<popUpButtonCell key="cell" type="push" title="1 Bytes" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" tag="1" imageScaling="proportionallyDown" inset="2" selectedItem="6u8-S0-1HE" id="v4e-cD-Jvg">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="ahy-ao-c12">
<items>
<menuItem title="1 Bytes" tag="1" id="6u8-S0-1HE">
<connections>
<action selector="reload:" target="-2" id="R90-mV-hi2"/>
</connections>
</menuItem>
<menuItem title="2 Bytes" state="on" tag="2" id="cIU-wH-R28">
<connections>
<action selector="reload:" target="-2" id="8nL-gR-C8K"/>
</connections>
</menuItem>
<menuItem title="3 Bytes" tag="3" id="7kS-Oq-ENU">
<connections>
<action selector="reload:" target="-2" id="SbZ-ZM-Wrr"/>
</connections>
</menuItem>
<menuItem title="4 Bytes" tag="4" id="U24-yb-eYi">
<connections>
<action selector="reload:" target="-2" id="4Ur-cc-Gmk"/>
</connections>
</menuItem>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Iwa-5p-7mk">
<rect key="frame" x="419" y="361" width="117" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Comparison:" id="FPt-dO-3ZL">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8E0-uI-3yG">
<rect key="frame" x="539" y="354" width="86" height="25"/>
<popUpButtonCell key="cell" type="push" title="=" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="V0d-DE-Tg8" id="SsD-Ss-ho8">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="3m6-To-Bh8">
<items>
<menuItem title="=" state="on" id="V0d-DE-Tg8"/>
<menuItem title="≠" tag="1" id="GSW-GL-5BE"/>
<menuItem title="&gt;" tag="2" id="xnG-3t-R9N"/>
<menuItem title="≥" tag="3" id="JlT-gc-K9N"/>
<menuItem title="&lt;" tag="4" id="9fT-w3-epd"/>
<menuItem title="≤" tag="5" id="vgd-E3-XFG"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<button verticalHuggingPriority="750" tag="103" translatesAutoresizingMaskIntoConstraints="NO" id="BZc-RO-wiZ">
<rect key="frame" x="419" y="440" width="104" height="18"/>
<buttonCell key="cell" type="radio" title="Hexadecimal" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="d3H-As-fK8">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setFormat:" target="-2" id="h9N-4v-flt"/>
</connections>
</button>
<button verticalHuggingPriority="750" tag="102" translatesAutoresizingMaskIntoConstraints="NO" id="nl2-Ws-C1y">
<rect key="frame" x="419" y="418" width="68" height="18"/>
<buttonCell key="cell" type="radio" title="Signed" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="9Wb-iT-whd">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setFormat:" target="-2" id="f2j-CT-bGL"/>
</connections>
</button>
<button verticalHuggingPriority="750" tag="101" translatesAutoresizingMaskIntoConstraints="NO" id="YSm-pR-xTv">
<rect key="frame" x="419" y="396" width="84" height="18"/>
<buttonCell key="cell" type="radio" title="Unsigned" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="2Y3-aV-xAX">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setFormat:" target="-2" id="eXM-iz-3GL"/>
</connections>
</button>
<button verticalHuggingPriority="750" tag="202" translatesAutoresizingMaskIntoConstraints="NO" id="sOk-o8-x8Y">
<rect key="frame" x="419" y="333" width="115" height="18"/>
<buttonCell key="cell" type="radio" title="Stored Value" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="Jla-qC-IvR">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setCompareTarget:" target="-2" id="pb2-se-c1q"/>
</connections>
</button>
<button verticalHuggingPriority="750" tag="201" translatesAutoresizingMaskIntoConstraints="NO" id="YqM-5N-NYa">
<rect key="frame" x="419" y="311" width="115" height="18"/>
<buttonCell key="cell" type="radio" title="Previous Value" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="06y-36-OK5">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setCompareTarget:" target="-2" id="aKc-J9-6Hc"/>
</connections>
</button>
<button verticalHuggingPriority="750" tag="200" translatesAutoresizingMaskIntoConstraints="NO" id="BeO-08-nTS">
<rect key="frame" x="419" y="289" width="115" height="18"/>
<buttonCell key="cell" type="radio" title="This Value:" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="S1G-ML-fIC">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setCompareTarget:" target="-2" id="bt9-ee-D1M"/>
</connections>
</button>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="eXx-ny-Tok">
<rect key="frame" x="542" y="287" width="79" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="upd-cO-CDd">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<outlet property="delegate" destination="-2" id="oDO-hH-5sb"/>
</connections>
</textField>
<scrollView autohidesScrollers="YES" horizontalLineScroll="24" horizontalPageScroll="10" verticalLineScroll="24" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ibr-Q0-59f">
<rect key="frame" x="421" y="49" width="200" height="149"/>
<clipView key="contentView" id="9bC-Md-S42">
<rect key="frame" x="1" y="1" width="198" height="147"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="24" rowSizeStyle="automatic" headerView="Be9-bB-Nds" viewBased="YES" id="0yj-jc-bsT" customClass="S9xCheatFinderTableView">
<rect key="frame" x="0.0" y="0.0" width="198" height="119"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="17" height="0.0"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="AutomaticTableColumnIdentifier.0" width="185" minWidth="185" maxWidth="185" id="9gb-7H-ZVq">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Watch">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="9kP-XN-WjV">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView id="JsP-6w-4Pj">
<rect key="frame" x="8" y="0.0" width="180" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="EKy-fB-qcf">
<rect key="frame" x="0.0" y="4" width="180" height="16"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="00000000" id="7hn-hd-g4c">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="EKy-fB-qcf" id="m4e-vb-ub0"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="-2" id="rtv-F4-sc4"/>
<outlet property="delegate" destination="-2" id="HZd-Vk-Pih"/>
</connections>
</tableView>
</subviews>
</clipView>
<constraints>
<constraint firstAttribute="height" constant="149" id="Dpk-8G-9tj"/>
<constraint firstAttribute="width" constant="200" id="cs4-sZ-4UP"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="V1J-zT-Szg">
<rect key="frame" x="1" y="132" width="10" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="TMt-m8-lYU">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" wantsLayer="YES" id="Be9-bB-Nds">
<rect key="frame" x="0.0" y="0.0" width="198" height="28"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
<box verticalHuggingPriority="750" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="845-DP-dPF">
<rect key="frame" x="422" y="204" width="199" height="5"/>
</box>
<button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kaT-sZ-PRb">
<rect key="frame" x="520" y="240" width="108" height="32"/>
<buttonCell key="cell" type="push" title="Search" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="uSQ-ca-Uji">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
</buttonCell>
<connections>
<action selector="search:" target="-2" id="ntd-fZ-bbI"/>
</connections>
</button>
<segmentedControl verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="rg7-go-Amx">
<rect key="frame" x="422" y="19" width="169" height="23"/>
<segmentedCell key="cell" borderStyle="border" alignment="left" segmentDistribution="fill" style="smallSquare" trackingMode="momentary" id="X8J-oM-StD">
<font key="font" metaFont="system"/>
<segments>
<segment image="NSAddTemplate" width="25"/>
<segment image="NSRemoveTemplate" width="25" tag="1"/>
<segment label="Save…" tag="2"/>
<segment label="Load…" tag="3"/>
</segments>
</segmentedCell>
<connections>
<action selector="watchesAction:" target="-2" id="2kk-Za-Xbn"/>
</connections>
</segmentedControl>
<button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="afr-7l-W3m">
<rect key="frame" x="414" y="208" width="109" height="32"/>
<buttonCell key="cell" type="push" title="Store Values" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="adn-hg-cHW">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="storeValues:" target="-2" id="Xfx-Ga-KnR"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="YqM-5N-NYa" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="0ae-yj-g2N"/>
<constraint firstItem="ut3-qV-HGo" firstAttribute="centerY" secondItem="afr-7l-W3m" secondAttribute="centerY" id="2QJ-De-4Vs"/>
<constraint firstItem="nl2-Ws-C1y" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="2o3-zm-Ypv"/>
<constraint firstItem="CJT-h8-WOU" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="2uS-a2-ZJJ"/>
<constraint firstItem="BeO-08-nTS" firstAttribute="trailing" secondItem="YqM-5N-NYa" secondAttribute="trailing" id="3FF-yi-Ezx"/>
<constraint firstItem="Ibr-Q0-59f" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="3qS-LJ-zqs"/>
<constraint firstItem="afr-7l-W3m" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="4kb-KH-oVR"/>
<constraint firstItem="sOk-o8-x8Y" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="5MG-qE-AUq"/>
<constraint firstItem="BeO-08-nTS" firstAttribute="top" secondItem="YqM-5N-NYa" secondAttribute="bottom" constant="6" symbolic="YES" id="6bi-Z9-qY7"/>
<constraint firstItem="YSm-pR-xTv" firstAttribute="top" secondItem="nl2-Ws-C1y" secondAttribute="bottom" constant="6" symbolic="YES" id="6mU-Wq-dNg"/>
<constraint firstItem="rg7-go-Amx" firstAttribute="leading" secondItem="0yj-jc-bsT" secondAttribute="leading" id="7rk-68-jdc"/>
<constraint firstItem="eXx-ny-Tok" firstAttribute="leading" secondItem="8E0-uI-3yG" secondAttribute="leading" id="80d-Pd-Ceb"/>
<constraint firstItem="Ibr-Q0-59f" firstAttribute="leading" secondItem="afr-7l-W3m" secondAttribute="leading" id="8El-Nu-kgV"/>
<constraint firstItem="kaT-sZ-PRb" firstAttribute="leading" secondItem="Iue-dD-GsP" secondAttribute="trailing" constant="12" symbolic="YES" id="93E-Hy-aaY"/>
<constraint firstItem="8E0-uI-3yG" firstAttribute="firstBaseline" secondItem="Iwa-5p-7mk" secondAttribute="firstBaseline" id="Ae0-Nz-NAM"/>
<constraint firstItem="ut3-qV-HGo" firstAttribute="leading" secondItem="afr-7l-W3m" secondAttribute="trailing" constant="12" symbolic="YES" id="B3D-4f-RSH"/>
<constraint firstItem="Ibr-Q0-59f" firstAttribute="trailing" secondItem="ut3-qV-HGo" secondAttribute="trailing" id="DWI-Em-mDq"/>
<constraint firstItem="Ibr-Q0-59f" firstAttribute="top" secondItem="845-DP-dPF" secondAttribute="bottom" constant="8" symbolic="YES" id="E9F-N9-JbX"/>
<constraint firstItem="rg7-go-Amx" firstAttribute="top" secondItem="Ibr-Q0-59f" secondAttribute="bottom" constant="8" id="GbR-Aq-I11"/>
<constraint firstItem="cRe-AN-vwd" firstAttribute="firstBaseline" secondItem="CJT-h8-WOU" secondAttribute="firstBaseline" id="MCi-sI-MVD"/>
<constraint firstItem="ut3-qV-HGo" firstAttribute="trailing" secondItem="kaT-sZ-PRb" secondAttribute="trailing" id="P6E-96-Sa1"/>
<constraint firstItem="Iwa-5p-7mk" firstAttribute="trailing" secondItem="CJT-h8-WOU" secondAttribute="trailing" id="PdZ-EZ-MFE"/>
<constraint firstItem="kaT-sZ-PRb" firstAttribute="width" secondItem="Iue-dD-GsP" secondAttribute="width" id="QBN-pl-uJx"/>
<constraint firstItem="ut3-qV-HGo" firstAttribute="width" secondItem="afr-7l-W3m" secondAttribute="width" multiplier="0.976744" id="QcU-EQ-dE1"/>
<constraint firstItem="Z8O-p3-OZ8" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" constant="20" symbolic="YES" id="UEL-k4-8y5"/>
<constraint firstItem="845-DP-dPF" firstAttribute="top" secondItem="ut3-qV-HGo" secondAttribute="bottom" constant="8" id="VMj-sg-Kt1"/>
<constraint firstAttribute="trailing" secondItem="Ibr-Q0-59f" secondAttribute="trailing" constant="20" symbolic="YES" id="Veg-Nn-zNU"/>
<constraint firstItem="YSm-pR-xTv" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="Vyh-5f-U6w"/>
<constraint firstItem="eXx-ny-Tok" firstAttribute="trailing" secondItem="8E0-uI-3yG" secondAttribute="trailing" id="Xlb-u7-BFu"/>
<constraint firstAttribute="trailing" secondItem="845-DP-dPF" secondAttribute="trailing" constant="20" symbolic="YES" id="YM9-q1-Llp"/>
<constraint firstItem="BeO-08-nTS" firstAttribute="trailing" secondItem="sOk-o8-x8Y" secondAttribute="trailing" id="aRG-oR-chG"/>
<constraint firstAttribute="trailing" secondItem="kaT-sZ-PRb" secondAttribute="trailing" constant="20" symbolic="YES" id="akN-hx-yAU"/>
<constraint firstItem="afr-7l-W3m" firstAttribute="leading" secondItem="Iue-dD-GsP" secondAttribute="leading" id="b62-cC-BHf"/>
<constraint firstItem="Iwa-5p-7mk" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="dlv-65-Gpw"/>
<constraint firstItem="BZc-RO-wiZ" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="dmd-yO-P0e"/>
<constraint firstItem="845-DP-dPF" firstAttribute="leading" secondItem="sYl-gL-DD1" secondAttribute="trailing" constant="8" id="fRS-c6-TJH"/>
<constraint firstItem="8E0-uI-3yG" firstAttribute="trailing" secondItem="cRe-AN-vwd" secondAttribute="trailing" id="gJg-Bt-TjU"/>
<constraint firstItem="YqM-5N-NYa" firstAttribute="top" secondItem="sOk-o8-x8Y" secondAttribute="bottom" constant="6" symbolic="YES" id="gvQ-Ce-aV7"/>
<constraint firstAttribute="bottom" secondItem="Z8O-p3-OZ8" secondAttribute="bottom" constant="20" symbolic="YES" id="h7F-0d-wf5"/>
<constraint firstItem="8E0-uI-3yG" firstAttribute="leading" secondItem="Iwa-5p-7mk" secondAttribute="trailing" constant="8" symbolic="YES" id="hEh-E9-3mf"/>
<constraint firstItem="ut3-qV-HGo" firstAttribute="top" secondItem="kaT-sZ-PRb" secondAttribute="bottom" constant="12" symbolic="YES" id="ieU-Cm-0UU"/>
<constraint firstItem="Iue-dD-GsP" firstAttribute="centerY" secondItem="kaT-sZ-PRb" secondAttribute="centerY" id="ioh-tJ-nTg"/>
<constraint firstItem="BZc-RO-wiZ" firstAttribute="top" secondItem="cRe-AN-vwd" secondAttribute="bottom" constant="8" symbolic="YES" id="njJ-FB-0Lx"/>
<constraint firstItem="kaT-sZ-PRb" firstAttribute="top" secondItem="eXx-ny-Tok" secondAttribute="bottom" constant="20" id="oaf-md-6hB"/>
<constraint firstItem="eXx-ny-Tok" firstAttribute="firstBaseline" secondItem="BeO-08-nTS" secondAttribute="firstBaseline" id="owM-3i-WiN"/>
<constraint firstItem="Iue-dD-GsP" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="rAV-sg-f9X"/>
<constraint firstItem="nl2-Ws-C1y" firstAttribute="top" secondItem="BZc-RO-wiZ" secondAttribute="bottom" constant="6" symbolic="YES" id="rWH-Er-qvc"/>
<constraint firstAttribute="bottom" secondItem="rg7-go-Amx" secondAttribute="bottom" constant="20" symbolic="YES" id="sRO-gB-luF"/>
<constraint firstAttribute="trailing" secondItem="ut3-qV-HGo" secondAttribute="trailing" constant="20" symbolic="YES" id="tAS-9v-hS2"/>
<constraint firstItem="CJT-h8-WOU" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" constant="20" symbolic="YES" id="ue1-b9-0Pf"/>
<constraint firstItem="sOk-o8-x8Y" firstAttribute="top" secondItem="8E0-uI-3yG" secondAttribute="bottom" constant="8" symbolic="YES" id="vyx-CZ-GGc"/>
<constraint firstItem="Iwa-5p-7mk" firstAttribute="top" secondItem="YSm-pR-xTv" secondAttribute="bottom" constant="20" id="wUM-tZ-zSl"/>
<constraint firstItem="cRe-AN-vwd" firstAttribute="leading" secondItem="CJT-h8-WOU" secondAttribute="trailing" constant="8" symbolic="YES" id="wfC-Pj-ztm"/>
<constraint firstItem="Z8O-p3-OZ8" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" symbolic="YES" id="xcs-0y-Ngl"/>
<constraint firstItem="BeO-08-nTS" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="z6G-Zq-7Sd"/>
<constraint firstAttribute="trailing" secondItem="cRe-AN-vwd" secondAttribute="trailing" constant="20" symbolic="YES" id="zdu-96-81C"/>
<constraint firstItem="eXx-ny-Tok" firstAttribute="leading" secondItem="BeO-08-nTS" secondAttribute="trailing" constant="8" symbolic="YES" id="zfC-Qb-ttb"/>
</constraints>
<point key="canvasLocation" x="165" y="148"/>
</customView>
<menuItem title="3 Bytes" id="E3F-R1-gur"/>
<userDefaultsController representsSharedInstance="YES" id="DTR-NK-B52"/>
</objects>
<resources>
<image name="NSAddTemplate" width="18" height="16"/>
<image name="NSRemoveTemplate" width="18" height="4"/>
</resources>
</document>

View File

@ -15,13 +15,14 @@
(c) Copyright 2004 Alexander and Sander (c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger (c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt (c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 - 2022 Michael Donald Buckley (c) Copyright 2019 - 2023 Michael Donald Buckley
***********************************************************************************/ ***********************************************************************************/
#import <snes9x_framework/snes9x_framework.h> #import <snes9x_framework/snes9x_framework.h>
#import "S9xCheatsViewController.h" #import "S9xCheatsViewController.h"
#import "S9xCheatEditViewController.h" #import "S9xCheatEditViewController.h"
#import "S9xHexNumberFormatter.h"
@interface S9xCheatsViewController () <NSTableViewDataSource, NSTableViewDelegate> @interface S9xCheatsViewController () <NSTableViewDataSource, NSTableViewDelegate>
@ -48,6 +49,12 @@
[self reloadData]; [self reloadData];
} }
- (void)viewWillAppear
{
[super viewWillAppear];
[self.tableView sizeLastColumnToFit];
}
- (void)deselectAll - (void)deselectAll
{ {
[self.tableView deselectAll:nil]; [self.tableView deselectAll:nil];
@ -165,82 +172,6 @@
@end @end
@interface S9xHexNumberFormatter : NSFormatter
@end
@implementation S9xHexNumberFormatter
+ (NSUInteger)maxLength
{
return NSUIntegerMax;
}
- (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)obj forString:(NSString *)string errorDescription:(out NSString * _Nullable __autoreleasing *)error
{
if (string.length > 0)
{
unsigned int value = 0;
NSScanner *scanner = [NSScanner scannerWithString:string];
[scanner scanHexInt:&value];
*obj = @(value);
return YES;
}
return NO;
}
- (NSNumber *)numberFromString:(NSString *)string
{
unsigned int value = 0;
NSScanner *scanner = [NSScanner scannerWithString:string];
[scanner scanHexInt:&value];
return @(value);
}
- (NSString *)stringForObjectValue:(id)obj
{
if ([obj isKindOfClass:NSNumber.class])
{
return [NSString stringWithFormat:@"%X", ((NSNumber *)obj).unsignedIntValue];
}
else if ([obj isKindOfClass:NSString.class])
{
return obj;
}
return @"";
}
- (BOOL)isPartialStringValid:(NSString * _Nonnull * _Nonnull)partialStringPtr proposedSelectedRange:(nullable NSRangePointer)proposedSelRangePtr originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange errorDescription:(NSString * _Nullable * _Nullable)error
{
static NSCharacterSet *hexCharacterSet;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
hexCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef"] invertedSet];
});
if ( [*partialStringPtr rangeOfCharacterFromSet:hexCharacterSet].location != NSNotFound )
{
*partialStringPtr = nil;
return NO;
}
*partialStringPtr = (*partialStringPtr).uppercaseString;
if ( (*partialStringPtr).length > self.class.maxLength )
{
*partialStringPtr = [*partialStringPtr substringToIndex:self.class.maxLength];
return NO;
}
return YES;
}
@end
@interface S9xAddressFormatter : S9xHexNumberFormatter @interface S9xAddressFormatter : S9xHexNumberFormatter
@end @end

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> <document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies> <dependencies>
<deployment identifier="macosx"/> <deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19529"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<objects> <objects>
@ -243,7 +243,7 @@
</customView> </customView>
</objects> </objects>
<resources> <resources>
<image name="NSAddTemplate" width="15" height="13"/> <image name="NSAddTemplate" width="18" height="16"/>
<image name="NSRemoveTemplate" width="15" height="4"/> <image name="NSRemoveTemplate" width="18" height="4"/>
</resources> </resources>
</document> </document>

View File

@ -1,6 +1,6 @@
/*****************************************************************************\ /*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License. This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory. For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/ \*****************************************************************************/
@ -15,19 +15,15 @@
(c) Copyright 2004 Alexander and Sander (c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger (c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt (c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 Michael Donald Buckley (c) Copyright 2019 - 2023 Michael Donald Buckley
***********************************************************************************/ ***********************************************************************************/
#import <Foundation/Foundation.h>
#ifndef _mac_cheatfinder_h_ NS_ASSUME_NONNULL_BEGIN
#define _mac_cheatfinder_h_
extern Boolean cfIsWatching; @interface S9xHexNumberFormatter : NSNumberFormatter
void CheatFinder (void); @end
void InitCheatFinder (void);
void ResetCheatFinder (void);
void DeinitCheatFinder (void);
void CheatFinderDrawWatchAddr (void);
#endif NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,94 @@
/*****************************************************************************\
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 - 2023 Michael Donald Buckley
***********************************************************************************/
#import "S9xHexNumberFormatter.h"
@implementation S9xHexNumberFormatter
+ (NSUInteger)maxLength
{
return NSUIntegerMax;
}
- (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)obj forString:(NSString *)string errorDescription:(out NSString * _Nullable __autoreleasing *)error
{
if (string.length > 0)
{
unsigned int value = 0;
NSScanner *scanner = [NSScanner scannerWithString:string];
[scanner scanHexInt:&value];
*obj = @(value);
return YES;
}
return NO;
}
- (NSNumber *)numberFromString:(NSString *)string
{
unsigned int value = 0;
NSScanner *scanner = [NSScanner scannerWithString:string];
[scanner scanHexInt:&value];
return @(value);
}
- (NSString *)stringForObjectValue:(id)obj
{
if ([obj isKindOfClass:NSNumber.class])
{
return [NSString stringWithFormat:@"%X", ((NSNumber *)obj).unsignedIntValue];
}
else if ([obj isKindOfClass:NSString.class])
{
return obj;
}
return @"";
}
- (BOOL)isPartialStringValid:(NSString * _Nonnull * _Nonnull)partialStringPtr proposedSelectedRange:(nullable NSRangePointer)proposedSelRangePtr originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange errorDescription:(NSString * _Nullable * _Nullable)error
{
static NSCharacterSet *hexCharacterSet;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
hexCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef"] invertedSet];
});
if ( [*partialStringPtr rangeOfCharacterFromSet:hexCharacterSet].location != NSNotFound )
{
*partialStringPtr = nil;
return NO;
}
*partialStringPtr = (*partialStringPtr).uppercaseString;
if ( (*partialStringPtr).length > self.class.maxLength )
{
*partialStringPtr = [*partialStringPtr substringToIndex:self.class.maxLength];
return NO;
}
return YES;
}
@end

File diff suppressed because it is too large Load Diff

View File

@ -137,8 +137,16 @@ extern bool8 pressedKeys[MAC_MAX_PLAYERS][kNumButtons];
extern bool8 pressedGamepadButtons[MAC_MAX_PLAYERS][kNumButtons]; extern bool8 pressedGamepadButtons[MAC_MAX_PLAYERS][kNumButtons];
extern pthread_mutex_t keyLock; extern pthread_mutex_t keyLock;
@protocol S9xEmulationDelegate <NSObject>
- (void)gameLoaded;
- (void)emulationPaused;
- (void)emulationResumed;
@end
@interface S9xView: MTKView @interface S9xView: MTKView
- (void)updatePauseOverlay; - (void)updatePauseOverlay;
@property (nonatomic, weak) id<S9xEmulationDelegate> emulationDelegate;
@end @end
extern S9xView *s9xView; extern S9xView *s9xView;
@ -166,6 +174,21 @@ void CopyPressedKeys(uint8 keys[MAC_MAX_PLAYERS][kNumButtons], uint8 gamepadButt
@property (nonatomic, assign) S9xButtonCode buttonCode; @property (nonatomic, assign) S9xButtonCode buttonCode;
@end @end
typedef NS_ENUM(uint32_t, S9xWatchPointFormat)
{
S9xWatchPointFormatUnsigned = 1,
S9xWatchPointFormatSigned = 2,
S9xWatchPointFormatHex = 3
};
@interface S9xWatchPoint: NSObject
@property (nonatomic, assign) uint32_t address;
@property (nonatomic, assign) uint32_t size;
@property (nonatomic, assign) S9xWatchPointFormat format;
@end
@protocol S9xInputDelegate <NSObject> @protocol S9xInputDelegate <NSObject>
- (BOOL)handleInput:(S9xJoypadInput *)input fromJoypad:(S9xJoypad *)joypad; - (BOOL)handleInput:(S9xJoypadInput *)input fromJoypad:(S9xJoypad *)joypad;
- (void)deviceSettingChanged:(S9xDeviceSetting)deviceSetting; - (void)deviceSettingChanged:(S9xDeviceSetting)deviceSetting;
@ -173,9 +196,10 @@ void CopyPressedKeys(uint8 keys[MAC_MAX_PLAYERS][kNumButtons], uint8 gamepadButt
extern id<S9xInputDelegate> inputDelegate; extern id<S9xInputDelegate> inputDelegate;
@interface S9xEngine : NSObject @interface S9xEngine : NSObject <S9xEmulationDelegate>
@property (nonatomic, weak) id<S9xInputDelegate> inputDelegate; @property (nonatomic, weak) id<S9xInputDelegate> inputDelegate;
@property (nonatomic, weak) id<S9xEmulationDelegate> emulationDelegate;
@property (nonatomic, assign) BOOL cheatsEnabled; @property (nonatomic, assign) BOOL cheatsEnabled;
@ -221,6 +245,11 @@ extern id<S9xInputDelegate> inputDelegate;
- (void)setSeparateEchoBufferFromRAM:(BOOL)flag; - (void)setSeparateEchoBufferFromRAM:(BOOL)flag;
- (void)setDisableSpriteLimit:(BOOL)flag; - (void)setDisableSpriteLimit:(BOOL)flag;
- (void)copyRAM:(uint8_t *)buffer length:(size_t)length;
- (NSArray<S9xWatchPoint *> *)getWatchPoints;
- (void)setWatchPoints:(NSArray<S9xWatchPoint *> *)watchPoints;
@end @end
#endif #endif

View File

@ -47,7 +47,6 @@
#import "mac-prefix.h" #import "mac-prefix.h"
#import "mac-audio.h" #import "mac-audio.h"
#import "mac-cheat.h" #import "mac-cheat.h"
#import "mac-cheatfinder.h"
#import "mac-cocoatools.h" #import "mac-cocoatools.h"
#import "mac-controls.h" #import "mac-controls.h"
#import "mac-dialog.h" #import "mac-dialog.h"
@ -339,11 +338,15 @@ static inline void EmulationLoop (void)
bool8 olddisplayframerate = false; bool8 olddisplayframerate = false;
int storedMacFrameSkip = macFrameSkip; int storedMacFrameSkip = macFrameSkip;
if (pauseEmulation)
{
[s9xView.emulationDelegate emulationResumed];
}
pauseEmulation = false; pauseEmulation = false;
frameAdvance = false; frameAdvance = false;
[s9xView updatePauseOverlay]; [s9xView updatePauseOverlay];
if (macQTRecord) if (macQTRecord)
{ {
olddisplayframerate = Settings.DisplayFrameRate; olddisplayframerate = Settings.DisplayFrameRate;
@ -2227,6 +2230,16 @@ static void ProcessInput (void)
case ToggleEmulationPause: case ToggleEmulationPause:
pauseEmulation = !pauseEmulation; pauseEmulation = !pauseEmulation;
if (pauseEmulation)
{
[s9xView.emulationDelegate emulationPaused];
}
else
{
[s9xView.emulationDelegate emulationResumed];
}
[s9xView updatePauseOverlay]; [s9xView updatePauseOverlay];
break; break;
@ -2252,6 +2265,16 @@ static void ProcessInput (void)
{ {
escKeyDown = true; escKeyDown = true;
pauseEmulation = !pauseEmulation; pauseEmulation = !pauseEmulation;
if (pauseEmulation)
{
[s9xView.emulationDelegate emulationPaused];
}
else
{
[s9xView.emulationDelegate emulationResumed];
}
[s9xView updatePauseOverlay]; [s9xView updatePauseOverlay];
dispatch_async(dispatch_get_main_queue(), ^ dispatch_async(dispatch_get_main_queue(), ^
@ -2504,6 +2527,7 @@ static void Initialize (void)
Settings.MultiPlayer5Master = true; Settings.MultiPlayer5Master = true;
Settings.FrameTimePAL = 20000; Settings.FrameTimePAL = 20000;
Settings.FrameTimeNTSC = 16667; Settings.FrameTimeNTSC = 16667;
Settings.DisplayWatchedAddresses = true;
Settings.SixteenBitSound = true; Settings.SixteenBitSound = true;
Settings.Stereo = true; Settings.Stereo = true;
Settings.SoundPlaybackRate = 32000; Settings.SoundPlaybackRate = 32000;
@ -2540,7 +2564,6 @@ static void Initialize (void)
InitKeyboard(); InitKeyboard();
InitAutofire(); InitAutofire();
InitCheatFinder();
InitGraphics(); InitGraphics();
InitMacSound(); InitMacSound();
@ -2577,7 +2600,6 @@ static void Deinitialize (void)
DeinitMultiCart(); DeinitMultiCart();
ReleaseHID(); ReleaseHID();
DeinitCheatFinder();
DeinitGraphics(); DeinitGraphics();
DeinitKeyboard(); DeinitKeyboard();
DeinitMacSound(); DeinitMacSound();
@ -2914,6 +2936,8 @@ void QuitWithFatalError ( NSString *message)
else else
{ {
pauseEmulation = true; pauseEmulation = true;
[self.emulationDelegate emulationPaused];
[s9xView updatePauseOverlay]; [s9xView updatePauseOverlay];
} }
} }
@ -3116,6 +3140,7 @@ void QuitWithFatalError ( NSString *message)
[s9xView addConstraint:[NSLayoutConstraint constraintWithItem:s9xView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SNES_WIDTH * 2.0]]; [s9xView addConstraint:[NSLayoutConstraint constraintWithItem:s9xView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SNES_WIDTH * 2.0]];
[s9xView addConstraint:[NSLayoutConstraint constraintWithItem:s9xView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SNES_HEIGHT * 2.0]]; [s9xView addConstraint:[NSLayoutConstraint constraintWithItem:s9xView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SNES_HEIGHT * 2.0]];
s9xView.device = MTLCreateSystemDefaultDevice(); s9xView.device = MTLCreateSystemDefaultDevice();
s9xView.emulationDelegate = self;
S9xInitDisplay(NULL, NULL); S9xInitDisplay(NULL, NULL);
} }
@ -3175,6 +3200,7 @@ void QuitWithFatalError ( NSString *message)
- (void)pause - (void)pause
{ {
pauseEmulation = true; pauseEmulation = true;
[self.emulationDelegate emulationPaused];
[s9xView updatePauseOverlay]; [s9xView updatePauseOverlay];
} }
@ -3187,6 +3213,7 @@ void QuitWithFatalError ( NSString *message)
- (void)resume - (void)resume
{ {
pauseEmulation = false; pauseEmulation = false;
[self.emulationDelegate emulationResumed];
[s9xView updatePauseOverlay]; [s9xView updatePauseOverlay];
} }
@ -3313,6 +3340,8 @@ void QuitWithFatalError ( NSString *message)
if ( SNES9X_OpenCart(fileURL) ) if ( SNES9X_OpenCart(fileURL) )
{ {
[self.emulationDelegate gameLoaded];
SNES9X_Go(); SNES9X_Go();
s9xView.window.title = fileURL.lastPathComponent.stringByDeletingPathExtension; s9xView.window.title = fileURL.lastPathComponent.stringByDeletingPathExtension;
[s9xView.window makeKeyAndOrderFront:nil]; [s9xView.window makeKeyAndOrderFront:nil];
@ -3420,6 +3449,86 @@ void QuitWithFatalError ( NSString *message)
Cheat.enabled = cheatsEnabled; Cheat.enabled = cheatsEnabled;
} }
- (void)copyRAM:(uint8_t *)buffer length:(size_t)length
{
if ( length > 0x20000)
{
length = 0x20000;
}
memcpy(buffer, Memory.RAM, length);
}
- (NSArray<S9xWatchPoint *> *)getWatchPoints
{
NSMutableArray<S9xWatchPoint *> *watchPoints = [NSMutableArray new];
for (NSUInteger i = 0; i < sizeof(watches)/sizeof(*watches); ++i)
{
if (watches[i].on)
{
S9xWatchPoint *watchPoint = [S9xWatchPoint new];
watchPoint.address = watches[i].address;
watchPoint.size = watches[i].size;
watchPoint.format = (S9xWatchPointFormat)watches[i].format;
[watchPoints insertObject:watchPoint atIndex:0];
}
}
return watchPoints;
}
- (void)setWatchPoints:(NSArray<S9xWatchPoint *> *)watchPoints
{
memset(watches, 0, sizeof(watches));
NSUInteger i = 0;
for (S9xWatchPoint *watchPoint in watchPoints.reverseObjectEnumerator)
{
uint32_t address = watchPoint.address;
watches[i].on = true;
watches[i].address = address;
watches[i].size = watchPoint.size;
watches[i].format = watchPoint.format;
if(address < 0x7E0000 + 0x20000)
{
snprintf(watches[i].desc, sizeof(watches[i].desc), "%6X", address);
}
else if(address < 0x7E0000 + 0x30000)
{
snprintf(watches[i].desc, sizeof(watches[i].desc), "s%05X", address - 0x7E0000 - 0x20000);
}
else
{
snprintf(watches[i].desc, sizeof(watches[i].desc), "i%05X", address - 0x7E0000 - 0x30000);
}
++i;
if (i == 16)
{
break;
}
}
}
- (void)gameLoaded
{
[self.emulationDelegate gameLoaded];
}
- (void)emulationPaused
{
[self.emulationDelegate emulationPaused];
}
- (void)emulationResumed
{
[self.emulationDelegate emulationResumed];
}
@end @end
@implementation S9xJoypad @implementation S9xJoypad
@ -3439,3 +3548,6 @@ void QuitWithFatalError ( NSString *message)
@implementation S9xJoypadInput @implementation S9xJoypadInput
@end @end
@implementation S9xWatchPoint
@end

View File

@ -21,6 +21,7 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#include "snes9x.h" #include "snes9x.h"
#include "cheats.h"
#include "memmap.h" #include "memmap.h"
#include "apu.h" #include "apu.h"
#include "display.h" #include "display.h"
@ -29,7 +30,6 @@
#include <sys/time.h> #include <sys/time.h>
#include "mac-prefix.h" #include "mac-prefix.h"
#include "mac-cheatfinder.h"
#include "mac-os.h" #include "mac-os.h"
#include "mac-screenshot.h" #include "mac-screenshot.h"
#include "mac-render.h" #include "mac-render.h"
@ -234,8 +234,29 @@ bool8 S9xContinueUpdate (int width, int height)
void S9xPutImage (int width, int height) void S9xPutImage (int width, int height)
{ {
if (cfIsWatching) for(unsigned int i = 0 ; i < sizeof(watches)/sizeof(*watches) ; i++)
CheatFinderDrawWatchAddr(); {
if(watches[i].on)
{
int address = watches[i].address - 0x7E0000;
const uint8* source;
if(address < 0x20000)
{
source = Memory.RAM + address;
}
else if(address < 0x30000)
{
source = Memory.SRAM + address - 0x20000;
}
else
{
source = Memory.FillRAM + address - 0x30000;
}
memcpy(&(Cheat.CWatchRAM[address]), source, watches[i].size);
}
}
if (Settings.DisplayFrameRate) if (Settings.DisplayFrameRate)
{ {

View File

@ -32,7 +32,6 @@
#include "mac-prefix.h" #include "mac-prefix.h"
#include "mac-audio.h" #include "mac-audio.h"
#include "mac-cart.h" #include "mac-cart.h"
#include "mac-cheatfinder.h"
#include "mac-dialog.h" #include "mac-dialog.h"
#include "mac-file.h" #include "mac-file.h"
#include "mac-multicart.h" #include "mac-multicart.h"
@ -62,8 +61,6 @@ bool8 SNES9X_OpenCart (NSURL *inRef)
S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR)); S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
} }
ResetCheatFinder();
if (!inRef) if (!inRef)
{ {
cartRef = NavOpenROMImage(); cartRef = NavOpenROMImage();
@ -133,8 +130,6 @@ bool8 SNES9X_OpenMultiCart (void)
S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR)); S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
} }
ResetCheatFinder();
if (!MultiCartDialog()) if (!MultiCartDialog())
{ {
cartOpen = false; cartOpen = false;

View File

@ -49,7 +49,6 @@
307C862122D29E29001B879E /* mac-audio.mm in Sources */ = {isa = PBXBuildFile; fileRef = EADE6347052E5C4300A80003 /* mac-audio.mm */; }; 307C862122D29E29001B879E /* mac-audio.mm in Sources */ = {isa = PBXBuildFile; fileRef = EADE6347052E5C4300A80003 /* mac-audio.mm */; };
307C862222D29E29001B879E /* mac-cart.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67004AC7FCE00A80003 /* mac-cart.mm */; }; 307C862222D29E29001B879E /* mac-cart.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67004AC7FCE00A80003 /* mac-cart.mm */; };
307C862322D29E29001B879E /* mac-cheat.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67204AC7FCE00A80003 /* mac-cheat.mm */; }; 307C862322D29E29001B879E /* mac-cheat.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67204AC7FCE00A80003 /* mac-cheat.mm */; };
307C862422D29E29001B879E /* mac-cheatfinder.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67404AC7FCE00A80003 /* mac-cheatfinder.mm */; };
307C862622D29E29001B879E /* mac-cocoatools.mm in Sources */ = {isa = PBXBuildFile; fileRef = EA85C24E0B4EC13300F5F9C9 /* mac-cocoatools.mm */; }; 307C862622D29E29001B879E /* mac-cocoatools.mm in Sources */ = {isa = PBXBuildFile; fileRef = EA85C24E0B4EC13300F5F9C9 /* mac-cocoatools.mm */; };
307C862922D29E29001B879E /* mac-gworld.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67904AC7FCE00A80003 /* mac-gworld.mm */; }; 307C862922D29E29001B879E /* mac-gworld.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67904AC7FCE00A80003 /* mac-gworld.mm */; };
307C862A22D29E29001B879E /* mac-keyboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67D04AC7FCE00A80003 /* mac-keyboard.mm */; }; 307C862A22D29E29001B879E /* mac-keyboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67D04AC7FCE00A80003 /* mac-keyboard.mm */; };
@ -238,6 +237,9 @@
30D709C1236F7E3200AAB7C3 /* S9xPreferencesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 30D709BF236F7E3200AAB7C3 /* S9xPreferencesWindowController.m */; }; 30D709C1236F7E3200AAB7C3 /* S9xPreferencesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 30D709BF236F7E3200AAB7C3 /* S9xPreferencesWindowController.m */; };
30D709C2236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 30D709C0236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib */; }; 30D709C2236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 30D709C0236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib */; };
30D709C5236F90DF00AAB7C3 /* S9xButtonConfigTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 30D709C4236F90DF00AAB7C3 /* S9xButtonConfigTextField.m */; }; 30D709C5236F90DF00AAB7C3 /* S9xButtonConfigTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 30D709C4236F90DF00AAB7C3 /* S9xButtonConfigTextField.m */; };
30F727EE29C7B365000235A8 /* S9xCheatFinderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 30F727EC29C7B365000235A8 /* S9xCheatFinderViewController.m */; };
30F727EF29C7B365000235A8 /* S9xCheatFinderViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 30F727ED29C7B365000235A8 /* S9xCheatFinderViewController.xib */; };
30F72A8E29CCF8E2000235A8 /* S9xHexNumberFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 30F72A8D29CCF8E2000235A8 /* S9xHexNumberFormatter.m */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -347,6 +349,11 @@
30D709C0236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = S9xPreferencesWindowController.xib; sourceTree = "<group>"; }; 30D709C0236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = S9xPreferencesWindowController.xib; sourceTree = "<group>"; };
30D709C3236F90DF00AAB7C3 /* S9xButtonConfigTextField.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S9xButtonConfigTextField.h; sourceTree = "<group>"; }; 30D709C3236F90DF00AAB7C3 /* S9xButtonConfigTextField.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S9xButtonConfigTextField.h; sourceTree = "<group>"; };
30D709C4236F90DF00AAB7C3 /* S9xButtonConfigTextField.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = S9xButtonConfigTextField.m; sourceTree = "<group>"; }; 30D709C4236F90DF00AAB7C3 /* S9xButtonConfigTextField.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = S9xButtonConfigTextField.m; sourceTree = "<group>"; };
30F727EB29C7B365000235A8 /* S9xCheatFinderViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S9xCheatFinderViewController.h; sourceTree = "<group>"; };
30F727EC29C7B365000235A8 /* S9xCheatFinderViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = S9xCheatFinderViewController.m; sourceTree = "<group>"; };
30F727ED29C7B365000235A8 /* S9xCheatFinderViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = S9xCheatFinderViewController.xib; sourceTree = "<group>"; };
30F72A8C29CCF8E2000235A8 /* S9xHexNumberFormatter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S9xHexNumberFormatter.h; sourceTree = "<group>"; };
30F72A8D29CCF8E2000235A8 /* S9xHexNumberFormatter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = S9xHexNumberFormatter.m; sourceTree = "<group>"; };
85FEF90620DDB15B00C038E9 /* bml.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bml.cpp; sourceTree = "<group>"; usesTabs = 1; }; 85FEF90620DDB15B00C038E9 /* bml.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bml.cpp; sourceTree = "<group>"; usesTabs = 1; };
85FEF90720DDB15C00C038E9 /* bml.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bml.h; sourceTree = "<group>"; usesTabs = 1; }; 85FEF90720DDB15C00C038E9 /* bml.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bml.h; sourceTree = "<group>"; usesTabs = 1; };
85FEF90A20DDB18D00C038E9 /* sha256.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sha256.cpp; sourceTree = "<group>"; usesTabs = 1; }; 85FEF90A20DDB18D00C038E9 /* sha256.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sha256.cpp; sourceTree = "<group>"; usesTabs = 1; };
@ -548,8 +555,6 @@
EAECB67104AC7FCE00A80003 /* mac-cart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-cart.h"; sourceTree = "<group>"; }; EAECB67104AC7FCE00A80003 /* mac-cart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-cart.h"; sourceTree = "<group>"; };
EAECB67204AC7FCE00A80003 /* mac-cheat.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-cheat.mm"; sourceTree = "<group>"; }; EAECB67204AC7FCE00A80003 /* mac-cheat.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-cheat.mm"; sourceTree = "<group>"; };
EAECB67304AC7FCE00A80003 /* mac-cheat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-cheat.h"; sourceTree = "<group>"; }; EAECB67304AC7FCE00A80003 /* mac-cheat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-cheat.h"; sourceTree = "<group>"; };
EAECB67404AC7FCE00A80003 /* mac-cheatfinder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-cheatfinder.mm"; sourceTree = "<group>"; };
EAECB67504AC7FCE00A80003 /* mac-cheatfinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-cheatfinder.h"; sourceTree = "<group>"; };
EAECB67904AC7FCE00A80003 /* mac-gworld.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-gworld.mm"; sourceTree = "<group>"; }; EAECB67904AC7FCE00A80003 /* mac-gworld.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-gworld.mm"; sourceTree = "<group>"; };
EAECB67A04AC7FCE00A80003 /* mac-gworld.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-gworld.h"; sourceTree = "<group>"; }; EAECB67A04AC7FCE00A80003 /* mac-gworld.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-gworld.h"; sourceTree = "<group>"; };
EAECB67B04AC7FCE00A80003 /* mac-joypad.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-joypad.mm"; sourceTree = "<group>"; }; EAECB67B04AC7FCE00A80003 /* mac-joypad.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-joypad.mm"; sourceTree = "<group>"; };
@ -715,6 +720,11 @@
30CF849927AF0C61002B37A9 /* S9xCheatEditViewController.h */, 30CF849927AF0C61002B37A9 /* S9xCheatEditViewController.h */,
30CF849A27AF0C61002B37A9 /* S9xCheatEditViewController.m */, 30CF849A27AF0C61002B37A9 /* S9xCheatEditViewController.m */,
30CF849B27AF0C61002B37A9 /* S9xCheatEditViewController.xib */, 30CF849B27AF0C61002B37A9 /* S9xCheatEditViewController.xib */,
30F727EB29C7B365000235A8 /* S9xCheatFinderViewController.h */,
30F727EC29C7B365000235A8 /* S9xCheatFinderViewController.m */,
30F727ED29C7B365000235A8 /* S9xCheatFinderViewController.xib */,
30F72A8C29CCF8E2000235A8 /* S9xHexNumberFormatter.h */,
30F72A8D29CCF8E2000235A8 /* S9xHexNumberFormatter.m */,
); );
path = Cheats; path = Cheats;
sourceTree = "<group>"; sourceTree = "<group>";
@ -998,7 +1008,6 @@
EADE6349052E5C5300A80003 /* mac-audio.h */, EADE6349052E5C5300A80003 /* mac-audio.h */,
EAECB67104AC7FCE00A80003 /* mac-cart.h */, EAECB67104AC7FCE00A80003 /* mac-cart.h */,
EAECB67304AC7FCE00A80003 /* mac-cheat.h */, EAECB67304AC7FCE00A80003 /* mac-cheat.h */,
EAECB67504AC7FCE00A80003 /* mac-cheatfinder.h */,
EA85C24D0B4EC13300F5F9C9 /* mac-cocoatools.h */, EA85C24D0B4EC13300F5F9C9 /* mac-cocoatools.h */,
EA809F9D08F8F2190072CDFB /* mac-controls.h */, EA809F9D08F8F2190072CDFB /* mac-controls.h */,
EA2DBC0A0510ABE700A80003 /* mac-file.h */, EA2DBC0A0510ABE700A80003 /* mac-file.h */,
@ -1021,7 +1030,6 @@
EADE6347052E5C4300A80003 /* mac-audio.mm */, EADE6347052E5C4300A80003 /* mac-audio.mm */,
EAECB67004AC7FCE00A80003 /* mac-cart.mm */, EAECB67004AC7FCE00A80003 /* mac-cart.mm */,
EAECB67204AC7FCE00A80003 /* mac-cheat.mm */, EAECB67204AC7FCE00A80003 /* mac-cheat.mm */,
EAECB67404AC7FCE00A80003 /* mac-cheatfinder.mm */,
EA85C24E0B4EC13300F5F9C9 /* mac-cocoatools.mm */, EA85C24E0B4EC13300F5F9C9 /* mac-cocoatools.mm */,
EA809FA108F8F2420072CDFB /* mac-controls.mm */, EA809FA108F8F2420072CDFB /* mac-controls.mm */,
EA2DBC0C0510ABE700A80003 /* mac-file.mm */, EA2DBC0C0510ABE700A80003 /* mac-file.mm */,
@ -1256,6 +1264,7 @@
306937CB2635EE5800007ABB /* S9xDisplayPreferencesViewController.xib in Resources */, 306937CB2635EE5800007ABB /* S9xDisplayPreferencesViewController.xib in Resources */,
306937E92636365100007ABB /* S9xFilesPreferencesViewController.xib in Resources */, 306937E92636365100007ABB /* S9xFilesPreferencesViewController.xib in Resources */,
30D709B0236F583600AAB7C3 /* Localizable.strings in Resources */, 30D709B0236F583600AAB7C3 /* Localizable.strings in Resources */,
30F727EF29C7B365000235A8 /* S9xCheatFinderViewController.xib in Resources */,
304B364A262E328400F8DC8E /* S9xControlsPreferencesViewController.xib in Resources */, 304B364A262E328400F8DC8E /* S9xControlsPreferencesViewController.xib in Resources */,
30D709B1236F585100AAB7C3 /* Snes9x Help in Resources */, 30D709B1236F585100AAB7C3 /* Snes9x Help in Resources */,
30D709B3236F731B00AAB7C3 /* SRAM.icns in Resources */, 30D709B3236F731B00AAB7C3 /* SRAM.icns in Resources */,
@ -1295,6 +1304,8 @@
309C54802627F3060055DD95 /* S9xControlsPreferencesViewController.m in Sources */, 309C54802627F3060055DD95 /* S9xControlsPreferencesViewController.m in Sources */,
30D709C5236F90DF00AAB7C3 /* S9xButtonConfigTextField.m in Sources */, 30D709C5236F90DF00AAB7C3 /* S9xButtonConfigTextField.m in Sources */,
306937E82636365100007ABB /* S9xFilesPreferencesViewController.m in Sources */, 306937E82636365100007ABB /* S9xFilesPreferencesViewController.m in Sources */,
30F72A8E29CCF8E2000235A8 /* S9xHexNumberFormatter.m in Sources */,
30F727EE29C7B365000235A8 /* S9xCheatFinderViewController.m in Sources */,
30CF849C27AF0C61002B37A9 /* S9xCheatEditViewController.m in Sources */, 30CF849C27AF0C61002B37A9 /* S9xCheatEditViewController.m in Sources */,
306937D02636253900007ABB /* S9xPreferencesTabViewController.m in Sources */, 306937D02636253900007ABB /* S9xPreferencesTabViewController.m in Sources */,
30714721230E379600917F82 /* main.m in Sources */, 30714721230E379600917F82 /* main.m in Sources */,
@ -1315,7 +1326,6 @@
307C862122D29E29001B879E /* mac-audio.mm in Sources */, 307C862122D29E29001B879E /* mac-audio.mm in Sources */,
307C862222D29E29001B879E /* mac-cart.mm in Sources */, 307C862222D29E29001B879E /* mac-cart.mm in Sources */,
307C862322D29E29001B879E /* mac-cheat.mm in Sources */, 307C862322D29E29001B879E /* mac-cheat.mm in Sources */,
307C862422D29E29001B879E /* mac-cheatfinder.mm in Sources */,
307C862622D29E29001B879E /* mac-cocoatools.mm in Sources */, 307C862622D29E29001B879E /* mac-cocoatools.mm in Sources */,
307C862922D29E29001B879E /* mac-gworld.mm in Sources */, 307C862922D29E29001B879E /* mac-gworld.mm in Sources */,
307C862A22D29E29001B879E /* mac-keyboard.mm in Sources */, 307C862A22D29E29001B879E /* mac-keyboard.mm in Sources */,