mirror of https://github.com/snes9xgit/snes9x.git
3583 lines
101 KiB
Plaintext
3583 lines
101 KiB
Plaintext
/*****************************************************************************\
|
|
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 <mach/mach_time.h>
|
|
|
|
#include <OpenGL/OpenGL.h>
|
|
#include <OpenGL/CGLRenderers.h>
|
|
#include <OpenGL/gl.h>
|
|
#include <OpenGL/glu.h>
|
|
#include <OpenGL/glext.h>
|
|
|
|
#import "snes9x.h"
|
|
#import "memmap.h"
|
|
#import "apu.h"
|
|
#import "controls.h"
|
|
#import "crosshairs.h"
|
|
#import "cheats.h"
|
|
#import "movie.h"
|
|
#import "snapshot.h"
|
|
#import "display.h"
|
|
#import "blit.h"
|
|
|
|
#ifdef DEBUGGER
|
|
#import "debug.h"
|
|
#endif
|
|
|
|
#import <pthread.h>
|
|
|
|
#import "mac-prefix.h"
|
|
#import "mac-audio.h"
|
|
#import "mac-cheat.h"
|
|
#import "mac-cocoatools.h"
|
|
#import "mac-controls.h"
|
|
#import "mac-dialog.h"
|
|
#import "mac-file.h"
|
|
#import "mac-gworld.h"
|
|
#import "mac-joypad.h"
|
|
#import "mac-keyboard.h"
|
|
#import "mac-musicbox.h"
|
|
#import "mac-netplay.h"
|
|
#import "mac-render.h"
|
|
#import "mac-screenshot.h"
|
|
#import "mac-snes9x.h"
|
|
#import "mac-stringtools.h"
|
|
#import "mac-os.h"
|
|
|
|
#define kRecentMenu_MAX 20
|
|
|
|
volatile bool8 running = false;
|
|
volatile bool8 s9xthreadrunning = false;
|
|
|
|
volatile bool8 windowExtend = true;
|
|
|
|
uint32 controlPad[MAC_MAX_PLAYERS];
|
|
|
|
uint8 romDetect = 0,
|
|
interleaveDetect = 0,
|
|
videoDetect = 0,
|
|
headerDetect = 0;
|
|
|
|
WindowRef gWindow = NULL;
|
|
uint32 glScreenW,
|
|
glScreenH;
|
|
CGRect glScreenBounds;
|
|
|
|
CGFloat rawMouseX, rawMouseY = 0;
|
|
int16 mouseX, mouseY = 0;
|
|
|
|
CGImageRef macIconImage[118];
|
|
int macPadIconIndex,
|
|
macLegendIconIndex,
|
|
macMusicBoxIconIndex,
|
|
macFunctionIconIndex;
|
|
|
|
int macFrameSkip = -1;
|
|
int32 skipFrames = 3;
|
|
int64 lastFrame = 0;
|
|
|
|
int64 machTimeNumerator = 0;
|
|
int64 machTimeDenominator = 0;
|
|
|
|
int macFastForwardRate = 5,
|
|
macFrameAdvanceRate = 1000000;
|
|
|
|
unsigned long spcFileCount = 0,
|
|
pngFileCount = 0;
|
|
|
|
bool8 cartOpen = false,
|
|
autofire = false;
|
|
|
|
bool8 autoRes = false,
|
|
glstretch = true,
|
|
gl32bit = true,
|
|
vsync = true,
|
|
drawoverscan = false;
|
|
int videoMode = VIDEOMODE_BLOCKY;
|
|
|
|
SInt32 macSoundVolume = 80; // %
|
|
uint32 macSoundBuffer_ms = 80; // ms
|
|
uint32 macSoundInterval_ms = 16; // ms
|
|
bool8 macSoundLagEnable = false;
|
|
uint16 aueffect = 0;
|
|
|
|
uint8 saveInROMFolder = 2; // 0 : Snes9x 1 : ROM 2 : Application Support
|
|
NSString *saveFolderPath;
|
|
|
|
int macCurvatureWarp = 15,
|
|
macAspectRatio = 0;
|
|
|
|
bool8 startopendlog = false,
|
|
showtimeinfrz = false,
|
|
enabletoggle = true,
|
|
savewindowpos = false,
|
|
onscreeninfo = true;
|
|
int inactiveMode = 2;
|
|
int musicboxmode = kMBXSoundEmulation;
|
|
|
|
bool8 applycheat = false;
|
|
S9xDeviceSetting deviceSetting = Gamepads,
|
|
deviceSettingMaster = Gamepads;
|
|
int macControllerOption = SNES_JOYPAD;
|
|
AutoFireState autofireRec[MAC_MAX_PLAYERS];
|
|
|
|
bool8 macQTRecord = false;
|
|
uint16 macQTMovFlag = 0;
|
|
|
|
uint16 macRecordFlag = 0x3,
|
|
macPlayFlag = 0x1;
|
|
wchar_t macRecordWChar[MOVIE_MAX_METADATA];
|
|
|
|
char npServerIP[256],
|
|
npName[256];
|
|
|
|
bool8 lastoverscan = false;
|
|
|
|
CGPoint unlimitedCursor;
|
|
|
|
#ifdef MAC_PANTHER_SUPPORT
|
|
IconRef macIconRef[118];
|
|
#endif
|
|
|
|
id<S9xInputDelegate> inputDelegate = nil;
|
|
|
|
typedef enum
|
|
{
|
|
ToggleBG0,
|
|
ToggleBG1,
|
|
ToggleBG2,
|
|
ToggleBG3,
|
|
ToggleSprites,
|
|
SwapJoypads,
|
|
SoundChannel0,
|
|
SoundChannel1,
|
|
SoundChannel2,
|
|
SoundChannel3,
|
|
SoundChannel4,
|
|
SoundChannel5,
|
|
SoundChannel6,
|
|
SoundChannel7,
|
|
SoundChannelsOn,
|
|
ToggleDisplayPressedKeys,
|
|
ToggleDisplayMovieFrame,
|
|
IncreaseFrameAdvanceRate,
|
|
DecreaseFrameAdvanceRate,
|
|
ToggleEmulationPause,
|
|
AdvanceFrame,
|
|
kNumFunctionButtons
|
|
} S9xFunctionButtonCommand;
|
|
|
|
uint8 functionButtons[kNumFunctionButtons] = {
|
|
kVK_F1,
|
|
kVK_F2,
|
|
kVK_F3,
|
|
kVK_F4,
|
|
kVK_F5,
|
|
kVK_F6,
|
|
kVK_ANSI_1,
|
|
kVK_ANSI_2,
|
|
kVK_ANSI_3,
|
|
kVK_ANSI_4,
|
|
kVK_ANSI_5,
|
|
kVK_ANSI_6,
|
|
kVK_ANSI_7,
|
|
kVK_ANSI_8,
|
|
kVK_ANSI_9,
|
|
kVK_ANSI_0,
|
|
kVK_ANSI_Minus,
|
|
kVK_ANSI_Q,
|
|
kVK_ANSI_W,
|
|
kVK_ANSI_O,
|
|
kVK_ANSI_P
|
|
};
|
|
|
|
bool8 pressedKeys[MAC_MAX_PLAYERS][kNumButtons] = { 0 };
|
|
bool8 pressedGamepadButtons[MAC_MAX_PLAYERS][kNumButtons] = { 0 };
|
|
bool8 pressedFunctionButtons[kNumFunctionButtons] = { 0 };
|
|
bool8 pressedRawKeyboardButtons[MAC_NUM_KEYCODES] = { 0 };
|
|
bool8 heldFunctionButtons[kNumFunctionButtons] = { 0 };
|
|
pthread_mutex_t keyLock;
|
|
|
|
S9xView *s9xView;
|
|
|
|
enum
|
|
{
|
|
mApple = 128,
|
|
iAbout = 1,
|
|
|
|
mFile = 129,
|
|
iOpen = 1,
|
|
iOpenMulti = 2,
|
|
iOpenRecent = 3,
|
|
iClose = 5,
|
|
iRomInfo = 7,
|
|
|
|
mControl = 134,
|
|
iKeyboardLayout = 1,
|
|
iISpLayout = 2,
|
|
iAutoFire = 4,
|
|
iISpPreset = 6,
|
|
|
|
mEdit = 130,
|
|
|
|
mEmulation = 131,
|
|
iResume = 1,
|
|
iSoftReset = 3,
|
|
iReset = 4,
|
|
iDevice = 6,
|
|
|
|
mCheat = 132,
|
|
iApplyCheats = 1,
|
|
iGameGenie = 3,
|
|
iCheatFinder = 4,
|
|
|
|
mOption = 133,
|
|
iFreeze = 1,
|
|
iDefrost = 2,
|
|
iFreezeTo = 4,
|
|
iDefrostFrom = 5,
|
|
iRecordMovie = 7,
|
|
iPlayMovie = 8,
|
|
iQTMovie = 10,
|
|
iSaveSPC = 12,
|
|
iSaveSRAM = 13,
|
|
iCIFilter = 15,
|
|
iMusicBox = 17,
|
|
|
|
mNetplay = 135,
|
|
iServer = 1,
|
|
iClient = 2,
|
|
|
|
mPresets = 201,
|
|
|
|
mDevice = 202,
|
|
|
|
mRecentItem = 203
|
|
};
|
|
|
|
struct GameViewInfo
|
|
{
|
|
int globalLeft;
|
|
int globalTop;
|
|
int width;
|
|
int height;
|
|
};
|
|
|
|
static volatile bool8 rejectinput = false;
|
|
|
|
static bool8 pauseEmulation = false,
|
|
escKeyDown = false,
|
|
frameAdvance = false,
|
|
useMouse = false;
|
|
|
|
static int frameCount = 0;
|
|
|
|
static bool8 frzselecting = false;
|
|
|
|
static uint16 changeAuto[2] = { 0x0000, 0x0000 };
|
|
|
|
static void Initialize (void);
|
|
static void Deinitialize (void);
|
|
static void InitAutofire (void);
|
|
static void ProcessInput (void);
|
|
static void ChangeAutofireSettings (int, int);
|
|
static void ChangeTurboRate (int);
|
|
static void UpdateFreezeDefrostScreen (int, CGImageRef, uint8 *, CGContextRef);
|
|
static void * MacSnes9xThread (void *);
|
|
static inline void EmulationLoop (void);
|
|
|
|
int main (int argc, const char *argv[])
|
|
{
|
|
return NSApplicationMain(argc, argv);
|
|
}
|
|
|
|
static void * MacSnes9xThread (void *)
|
|
{
|
|
Settings.StopEmulation = false;
|
|
s9xthreadrunning = true;
|
|
|
|
EmulationLoop();
|
|
|
|
s9xthreadrunning = false;
|
|
Settings.StopEmulation = true;
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
void CopyPressedKeys(bool8 keys[MAC_MAX_PLAYERS][kNumButtons], bool8 gamepadButtons[MAC_MAX_PLAYERS][kNumButtons])
|
|
{
|
|
pthread_mutex_lock(&keyLock);
|
|
memcpy(keys, pressedKeys, sizeof(pressedKeys));
|
|
memcpy(gamepadButtons, pressedGamepadButtons, sizeof(pressedGamepadButtons));
|
|
pthread_mutex_unlock(&keyLock);
|
|
}
|
|
|
|
static inline void EmulationLoop (void)
|
|
{
|
|
bool8 olddisplayframerate = false;
|
|
int storedMacFrameSkip = macFrameSkip;
|
|
|
|
if (pauseEmulation)
|
|
{
|
|
[s9xView.emulationDelegate emulationResumed];
|
|
}
|
|
|
|
pauseEmulation = false;
|
|
frameAdvance = false;
|
|
[s9xView updatePauseOverlay];
|
|
|
|
if (macQTRecord)
|
|
{
|
|
olddisplayframerate = Settings.DisplayFrameRate;
|
|
Settings.DisplayFrameRate = false;
|
|
}
|
|
|
|
MacStartSound();
|
|
|
|
if (Settings.NetPlay)
|
|
{
|
|
// if (Settings.NetPlayServer)
|
|
// {
|
|
// NPServerDetachNetPlayThread();
|
|
// NPServerStartClients();
|
|
//
|
|
// while (running)
|
|
// {
|
|
// NPServerProcessInput();
|
|
// S9xMainLoop();
|
|
// }
|
|
//
|
|
// NPServerStopNetPlayThread();
|
|
// NPServerStopServer();
|
|
// }
|
|
// else
|
|
// {
|
|
// NPClientDetachNetPlayThread();
|
|
// NPClientNetPlayWaitStart();
|
|
//
|
|
// while (running)
|
|
// {
|
|
// NPClientProcessInput();
|
|
// S9xMainLoop();
|
|
// }
|
|
//
|
|
// NPClientStopNetPlayThread();
|
|
// NPClientDisconnect();
|
|
//
|
|
// NPClientRestoreConfig();
|
|
// }
|
|
}
|
|
else
|
|
{
|
|
while (running)
|
|
{
|
|
ProcessInput();
|
|
|
|
if (!pauseEmulation)
|
|
{
|
|
S9xMainLoop();
|
|
}
|
|
else
|
|
{
|
|
if (frameAdvance)
|
|
{
|
|
macFrameSkip = 1;
|
|
skipFrames = 1;
|
|
frameAdvance = false;
|
|
S9xMainLoop();
|
|
macFrameSkip = storedMacFrameSkip;
|
|
}
|
|
|
|
usleep(Settings.FrameTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
MacStopSound();
|
|
|
|
if (macQTRecord)
|
|
{
|
|
// MacQTStopRecording();
|
|
// macQTRecord = false;
|
|
|
|
Settings.DisplayFrameRate = olddisplayframerate;
|
|
}
|
|
|
|
S9xMovieShutdown();
|
|
}
|
|
//
|
|
//static OSStatus MainEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
|
|
//{
|
|
// OSStatus err, result = eventNotHandledErr;
|
|
// Boolean done = false;
|
|
//
|
|
// if (frzselecting)
|
|
// return (result);
|
|
//
|
|
// switch (GetEventClass(inEvent))
|
|
// {
|
|
// case kEventClassCommand:
|
|
// switch (GetEventKind(inEvent))
|
|
// {
|
|
// HICommand cmd;
|
|
//
|
|
// case kEventCommandUpdateStatus:
|
|
// err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &cmd);
|
|
// if (err == noErr && cmd.commandID == 'clos')
|
|
// {
|
|
// UpdateMenuCommandStatus(false);
|
|
// result = noErr;
|
|
// }
|
|
//
|
|
// break;
|
|
//
|
|
// case kEventCommandProcess:
|
|
// err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &cmd);
|
|
// if (err == noErr)
|
|
// {
|
|
// UInt32 modifierkey;
|
|
//
|
|
// err = GetEventParameter(inEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifierkey);
|
|
// if (err == noErr)
|
|
// {
|
|
// if ((cmd.commandID == 'pref') && (modifierkey & optionKey))
|
|
// cmd.commandID = 'EXTR';
|
|
//
|
|
// result = HandleMenuChoice(cmd.commandID, &done);
|
|
//
|
|
// if (done)
|
|
// QuitApplicationEventLoop();
|
|
// }
|
|
// }
|
|
//
|
|
// break;
|
|
// }
|
|
//
|
|
// break;
|
|
// }
|
|
//
|
|
// return (result);
|
|
//}
|
|
//
|
|
//static OSStatus SubEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
|
|
//{
|
|
// OSStatus err, result = eventNotHandledErr;
|
|
//
|
|
// if (frzselecting)
|
|
// return (result);
|
|
//
|
|
// switch (GetEventClass(inEvent))
|
|
// {
|
|
// case kEventClassCommand:
|
|
// switch (GetEventKind(inEvent))
|
|
// {
|
|
// HICommand cmd;
|
|
//
|
|
// case kEventCommandUpdateStatus:
|
|
// err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &cmd);
|
|
// if (err == noErr && cmd.commandID == 'clos')
|
|
// {
|
|
// UpdateMenuCommandStatus(false);
|
|
// result = noErr;
|
|
// }
|
|
//
|
|
// break;
|
|
//
|
|
// case kEventCommandProcess:
|
|
// err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &cmd);
|
|
// if (err == noErr)
|
|
// {
|
|
// switch (cmd.commandID)
|
|
// {
|
|
// case 'Erun': // Pause
|
|
// case 'SubQ': // Queue from emulation thread
|
|
// running = false;
|
|
// while (s9xthreadrunning)
|
|
// sleep(0);
|
|
// QuitApplicationEventLoop();
|
|
// result = noErr;
|
|
// break;
|
|
//
|
|
// case 'Ocif': // Core Image Filter
|
|
// HiliteMenu(0);
|
|
// ConfigureCoreImageFilter();
|
|
// result = noErr;
|
|
// break;
|
|
// }
|
|
// }
|
|
//
|
|
// break;
|
|
// }
|
|
//
|
|
// break;
|
|
//
|
|
// case kEventClassMouse:
|
|
// if (fullscreen)
|
|
// {
|
|
// if ((macControllerOption == SNES_JOYPAD) || (macControllerOption == SNES_MULTIPLAYER5) || (macControllerOption == SNES_MULTIPLAYER5_2))
|
|
// {
|
|
// if (!(Settings.NetPlay && !Settings.NetPlayServer))
|
|
// {
|
|
// switch (GetEventKind(inEvent))
|
|
// {
|
|
// case kEventMouseUp:
|
|
// HIPoint hipt;
|
|
//
|
|
// err = GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(HIPoint), NULL, &hipt);
|
|
// if (err == noErr)
|
|
// {
|
|
// if (CGRectContainsPoint(glScreenBounds, hipt))
|
|
// {
|
|
// running = false;
|
|
// while (s9xthreadrunning)
|
|
// sleep(0);
|
|
// QuitApplicationEventLoop();
|
|
// result = noErr;
|
|
// }
|
|
// }
|
|
//
|
|
// break;
|
|
// }
|
|
// }
|
|
// }
|
|
// else
|
|
// if ((macControllerOption == SNES_MOUSE) || (macControllerOption == SNES_MOUSE_SWAPPED))
|
|
// {
|
|
// switch (GetEventKind(inEvent))
|
|
// {
|
|
// case kEventMouseMoved:
|
|
// case kEventMouseDragged:
|
|
// HIPoint hipt;
|
|
//
|
|
// err = GetEventParameter(inEvent, kEventParamMouseDelta, typeHIPoint, NULL, sizeof(HIPoint), NULL, &hipt);
|
|
// if (err == noErr)
|
|
// {
|
|
// unlimitedCursor.x += hipt.x;
|
|
// unlimitedCursor.y += hipt.y;
|
|
// }
|
|
//
|
|
// break;
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// break;
|
|
// }
|
|
//
|
|
// return (result);
|
|
//}
|
|
//
|
|
//void PostQueueToSubEventLoop (void)
|
|
//{
|
|
// OSStatus err;
|
|
// EventRef event;
|
|
//
|
|
// err = CreateEvent(kCFAllocatorDefault, kEventClassCommand, kEventCommandProcess, 0, kEventAttributeUserEvent, &event);
|
|
// if (err == noErr)
|
|
// {
|
|
// HICommand cmd;
|
|
//
|
|
// cmd.commandID = 'SubQ';
|
|
// cmd.attributes = kEventAttributeUserEvent;
|
|
// cmd.menu.menuRef = NULL;
|
|
// cmd.menu.menuItemIndex = 0;
|
|
//
|
|
// err = SetEventParameter(event, kEventParamDirectObject, typeHICommand, sizeof(HICommand), &cmd);
|
|
// if (err == noErr)
|
|
// err = PostEventToQueue(GetMainEventQueue(), event, kEventPriorityStandard);
|
|
//
|
|
// ReleaseEvent(event);
|
|
// }
|
|
//}
|
|
//
|
|
//void InitGameWindow (void)
|
|
//{
|
|
// OSStatus err;
|
|
// IBNibRef nibRef;
|
|
// WindowAttributes attr;
|
|
// CFStringRef ref;
|
|
// HIViewRef ctl;
|
|
// HIViewID cid = { 'Pict', 0 };
|
|
// Rect rct;
|
|
// char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], fname[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
|
|
// EventTypeSpec wupaneEvents[] = { { kEventClassControl, kEventControlClick },
|
|
// { kEventClassControl, kEventControlDraw } },
|
|
// windowEvents[] = { { kEventClassWindow, kEventWindowDeactivated },
|
|
// { kEventClassWindow, kEventWindowActivated },
|
|
// { kEventClassWindow, kEventWindowBoundsChanging },
|
|
// { kEventClassWindow, kEventWindowBoundsChanged },
|
|
// { kEventClassWindow, kEventWindowZoom },
|
|
// { kEventClassWindow, kEventWindowToolbarSwitchMode } };
|
|
//
|
|
// if (gWindow)
|
|
// return;
|
|
//
|
|
// err = CreateNibReference(kMacS9XCFString, &nibRef);
|
|
// if (err)
|
|
// QuitWithFatalError(err, "os 02");
|
|
//
|
|
// err = CreateWindowFromNib(nibRef, CFSTR("GameWindow"), &gWindow);
|
|
// if (err)
|
|
// QuitWithFatalError(err, "os 03");
|
|
//
|
|
// DisposeNibReference(nibRef);
|
|
//
|
|
// HIViewFindByID(HIViewGetRoot(gWindow), cid, &ctl);
|
|
//
|
|
// gameWindowUPP = NewEventHandlerUPP(GameWindowEventHandler);
|
|
// err = InstallWindowEventHandler(gWindow, gameWindowUPP, GetEventTypeCount(windowEvents), windowEvents, (void *) gWindow, &gameWindowEventRef);
|
|
//
|
|
// gameWUPaneUPP = NewEventHandlerUPP(GameWindowUserPaneEventHandler);
|
|
// err = InstallControlEventHandler(ctl, gameWUPaneUPP, GetEventTypeCount(wupaneEvents), wupaneEvents, (void *) gWindow, &gameWUPaneEventRef);
|
|
//
|
|
// _splitpath(Memory.ROMFilename, drive, dir, fname, ext);
|
|
// ref = CFStringCreateWithCString(kCFAllocatorDefault, fname, kCFStringEncodingUTF8);
|
|
// if (ref)
|
|
// {
|
|
// SetWindowTitleWithCFString(gWindow, ref);
|
|
// CFRelease(ref);
|
|
// }
|
|
//
|
|
// attr = kWindowFullZoomAttribute | kWindowResizableAttribute | kWindowLiveResizeAttribute;
|
|
// err = ChangeWindowAttributes(gWindow, attr, kWindowNoAttributes);
|
|
//
|
|
// attr = kWindowToolbarButtonAttribute;
|
|
// if (!drawoverscan)
|
|
// err = ChangeWindowAttributes(gWindow, attr, kWindowNoAttributes);
|
|
// else
|
|
// err = ChangeWindowAttributes(gWindow, kWindowNoAttributes, attr);
|
|
//
|
|
// if (savewindowpos)
|
|
// {
|
|
// MoveWindow(gWindow, windowPos[kWindowScreen].h, windowPos[kWindowScreen].v, false);
|
|
//
|
|
// if ((windowSize[kWindowScreen].width <= 0) || (windowSize[kWindowScreen].height <= 0))
|
|
// {
|
|
// windowExtend = true;
|
|
// windowSize[kWindowScreen].width = 512;
|
|
// windowSize[kWindowScreen].height = kMacWindowHeight;
|
|
// }
|
|
//
|
|
// if (!lastoverscan && !windowExtend && drawoverscan)
|
|
// {
|
|
// windowExtend = true;
|
|
// windowSize[kWindowScreen].height = (int) ((float) (windowSize[kWindowScreen].height + 0.5) * SNES_HEIGHT_EXTENDED / SNES_HEIGHT);
|
|
// }
|
|
//
|
|
// SizeWindow(gWindow, (short) windowSize[kWindowScreen].width, (short) windowSize[kWindowScreen].height, false);
|
|
// }
|
|
// else
|
|
// {
|
|
// if (drawoverscan)
|
|
// windowExtend = true;
|
|
//
|
|
// SizeWindow(gWindow, 512, (windowExtend ? kMacWindowHeight : (SNES_HEIGHT << 1)), false);
|
|
// RepositionWindow(gWindow, NULL, kWindowCenterOnMainScreen);
|
|
// }
|
|
//
|
|
// windowZoomCount = 0;
|
|
//
|
|
// GetWindowBounds(gWindow, kWindowContentRgn, &rct);
|
|
// gWindowRect = CGRectMake((float) rct.left, (float) rct.top, (float) (rct.right - rct.left), (float) (rct.bottom - rct.top));
|
|
//
|
|
// ActivateWindow(gWindow, true);
|
|
//}
|
|
//
|
|
//void UpdateGameWindow (void)
|
|
//{
|
|
// OSStatus err;
|
|
// HIViewRef ctl;
|
|
// HIViewID cid = { 'Pict', 0 };
|
|
//
|
|
// if (!gWindow)
|
|
// return;
|
|
//
|
|
// HIViewFindByID(HIViewGetRoot(gWindow), cid, &ctl);
|
|
// err = HIViewSetNeedsDisplay(ctl, true);
|
|
//}
|
|
//
|
|
//static void ResizeGameWindow (void)
|
|
//{
|
|
// Rect rct;
|
|
// int ww, wh;
|
|
//
|
|
// if (!gWindow)
|
|
// return;
|
|
//
|
|
// GetWindowBounds(gWindow, kWindowContentRgn, &rct);
|
|
//
|
|
// wh = (windowExtend ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT) * ((windowZoomCount >> 1) + 1);
|
|
//
|
|
// if (windowZoomCount % 2)
|
|
// ww = SNES_NTSC_OUT_WIDTH(SNES_WIDTH) * ((windowZoomCount >> 1) + 1) / 2;
|
|
// else
|
|
// ww = SNES_WIDTH * ((windowZoomCount >> 1) + 1);
|
|
//
|
|
// rct.right = rct.left + ww;
|
|
// rct.bottom = rct.top + wh;
|
|
//
|
|
// SetWindowBounds(gWindow, kWindowContentRgn, &rct);
|
|
//
|
|
// printf("Window Size: %d, %d\n", ww, wh);
|
|
//
|
|
// windowZoomCount++;
|
|
// if (windowZoomCount == 8)
|
|
// windowZoomCount = 0;
|
|
//}
|
|
//
|
|
//void DeinitGameWindow (void)
|
|
//{
|
|
// OSStatus err;
|
|
//
|
|
// if (!gWindow)
|
|
// return;
|
|
//
|
|
// SaveWindowPosition(gWindow, kWindowScreen);
|
|
// lastoverscan = drawoverscan;
|
|
//
|
|
// err = RemoveEventHandler(gameWUPaneEventRef);
|
|
// DisposeEventHandlerUPP(gameWUPaneUPP);
|
|
//
|
|
// err = RemoveEventHandler(gameWindowEventRef);
|
|
// DisposeEventHandlerUPP(gameWindowUPP);
|
|
//
|
|
// CFRelease(gWindow);
|
|
// gWindow = NULL;
|
|
//}
|
|
//
|
|
//static OSStatus GameWindowEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
|
|
//{
|
|
// OSStatus err, result = eventNotHandledErr;
|
|
// HIRect rct;
|
|
// Rect r;
|
|
// UInt32 attr;
|
|
//
|
|
// switch (GetEventClass(inEvent))
|
|
// {
|
|
// case kEventClassWindow:
|
|
// switch (GetEventKind(inEvent))
|
|
// {
|
|
// case kEventWindowDeactivated:
|
|
// if (running)
|
|
// {
|
|
// if (!(Settings.NetPlay && !Settings.NetPlayServer))
|
|
// {
|
|
// if (inactiveMode == 3)
|
|
// {
|
|
// running = false;
|
|
// while (s9xthreadrunning)
|
|
// sleep(0);
|
|
// QuitApplicationEventLoop();
|
|
// result = noErr;
|
|
// }
|
|
// else
|
|
// if (inactiveMode == 2)
|
|
// {
|
|
// rejectinput = true;
|
|
// result = noErr;
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// break;
|
|
//
|
|
// case kEventWindowActivated:
|
|
// if (running)
|
|
// {
|
|
// if (!(Settings.NetPlay && !Settings.NetPlayServer))
|
|
// {
|
|
// ForceChangingKeyScript();
|
|
//
|
|
// if (inactiveMode == 2)
|
|
// {
|
|
// rejectinput = false;
|
|
// result = noErr;
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// break;
|
|
//
|
|
// case kEventWindowBoundsChanging:
|
|
// windowResizeCount = 0x7FFFFFFF;
|
|
//
|
|
// err = GetEventParameter(inEvent, kEventParamAttributes, typeUInt32, NULL, sizeof(UInt32), NULL, &attr);
|
|
// if ((err == noErr) && (attr & kWindowBoundsChangeSizeChanged))
|
|
// {
|
|
// err = GetEventParameter(inEvent, kEventParamCurrentBounds, typeHIRect, NULL, sizeof(HIRect), NULL, &rct);
|
|
// if (err == noErr)
|
|
// {
|
|
// if (GetCurrentEventKeyModifiers() & shiftKey)
|
|
// {
|
|
// HIRect origRct;
|
|
//
|
|
// err = GetEventParameter(inEvent, kEventParamOriginalBounds, typeHIRect, NULL, sizeof(HIRect), NULL, &origRct);
|
|
// if (err == noErr)
|
|
// {
|
|
// rct.size.width = (float) (int) (origRct.size.width * rct.size.height / origRct.size.height);
|
|
// err = SetEventParameter(inEvent, kEventParamCurrentBounds, typeHIRect, sizeof(HIRect), &rct);
|
|
// }
|
|
// }
|
|
//
|
|
// gWindowRect = rct;
|
|
// }
|
|
// }
|
|
//
|
|
// result = noErr;
|
|
// break;
|
|
//
|
|
// case kEventWindowBoundsChanged:
|
|
// windowResizeCount = 3;
|
|
// result = noErr;
|
|
// break;
|
|
//
|
|
// case kEventWindowZoom:
|
|
// ResizeGameWindow();
|
|
// result = noErr;
|
|
// break;
|
|
//
|
|
// case kEventWindowToolbarSwitchMode:
|
|
// windowExtend = !windowExtend;
|
|
//
|
|
// GetWindowBounds(gWindow, kWindowContentRgn, &r);
|
|
//
|
|
// if (windowExtend)
|
|
// r.bottom = r.top + (int) (((float) (r.bottom - r.top) + 0.5) * SNES_HEIGHT_EXTENDED / SNES_HEIGHT);
|
|
// else
|
|
// r.bottom = r.top + (int) (((float) (r.bottom - r.top) + 0.5) * SNES_HEIGHT / SNES_HEIGHT_EXTENDED);
|
|
//
|
|
// SetWindowBounds(gWindow, kWindowContentRgn, &r);
|
|
//
|
|
// result = noErr;
|
|
// break;
|
|
// }
|
|
//
|
|
// break;
|
|
// }
|
|
//
|
|
// return (result);
|
|
//}
|
|
//
|
|
//static OSStatus GameWindowUserPaneEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
|
|
//{
|
|
// OSStatus err, result = eventNotHandledErr;
|
|
//
|
|
// switch (GetEventClass(inEvent))
|
|
// {
|
|
// case kEventClassControl:
|
|
// switch (GetEventKind(inEvent))
|
|
// {
|
|
// case kEventControlClick:
|
|
// if (running)
|
|
// {
|
|
// if ((macControllerOption == SNES_JOYPAD) || (macControllerOption == SNES_MULTIPLAYER5) || (macControllerOption == SNES_MULTIPLAYER5_2))
|
|
// {
|
|
// if (!(Settings.NetPlay && !Settings.NetPlayServer))
|
|
// {
|
|
// if (!frzselecting)
|
|
// {
|
|
// running = false;
|
|
// while (s9xthreadrunning)
|
|
// sleep(0);
|
|
// QuitApplicationEventLoop();
|
|
// result = noErr;
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// UInt32 count;
|
|
//
|
|
// err = GetEventParameter(inEvent, kEventParamClickCount, typeUInt32, NULL, sizeof(UInt32), NULL, &count);
|
|
// if ((err == noErr) && (count == 2))
|
|
// {
|
|
// SNES9X_Go();
|
|
// QuitApplicationEventLoop();
|
|
// result = noErr;
|
|
// }
|
|
// }
|
|
//
|
|
// break;
|
|
//
|
|
// case kEventControlDraw:
|
|
// CGContextRef ctx;
|
|
// HIViewRef view;
|
|
// HIRect bounds;
|
|
//
|
|
// err = GetEventParameter(inEvent, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &view);
|
|
// if (err == noErr)
|
|
// {
|
|
// err = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(CGContextRef), NULL, &ctx);
|
|
// if (err == noErr)
|
|
// {
|
|
// if (!running)
|
|
// {
|
|
// HIViewGetBounds(view, &bounds);
|
|
// CGContextTranslateCTM(ctx, 0, bounds.size.height);
|
|
// CGContextScaleCTM(ctx, 1.0f, -1.0f);
|
|
// DrawPauseScreen(ctx, bounds);
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// result = noErr;
|
|
// break;
|
|
// }
|
|
//
|
|
// break;
|
|
// }
|
|
//
|
|
// return (result);
|
|
//}
|
|
//
|
|
//
|
|
//static void InitRecentMenu (void)
|
|
//{
|
|
// OSStatus err;
|
|
//
|
|
// err = CreateNewMenu(mRecentItem, 0, &recentMenu);
|
|
// err = SetMenuItemHierarchicalMenu(GetMenuRef(mFile), iOpenRecent, recentMenu);
|
|
//}
|
|
//
|
|
//static void DeinitRecentMenu (void)
|
|
//{
|
|
// CFRelease(recentMenu);
|
|
//}
|
|
//
|
|
//void BuildRecentMenu (void)
|
|
//{
|
|
// OSStatus err;
|
|
// CFStringRef str;
|
|
//
|
|
// err = DeleteMenuItems(recentMenu, 1, CountMenuItems(recentMenu));
|
|
//
|
|
// for (int i = 0; i < kRecentMenu_MAX; i++)
|
|
// {
|
|
// if (!recentItem[i])
|
|
// break;
|
|
//
|
|
// Boolean r;
|
|
// char path[PATH_MAX + 1];
|
|
//
|
|
// r = CFStringGetCString(recentItem[i], path, PATH_MAX, kCFStringEncodingUTF8);
|
|
// if (r)
|
|
// {
|
|
// CFStringRef nameRef;
|
|
// char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], fname[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
|
|
//
|
|
// _splitpath(path, drive, dir, fname, ext);
|
|
// snprintf(path, PATH_MAX + 1, "%s%s", fname, ext);
|
|
// nameRef = CFStringCreateWithCString(kCFAllocatorDefault, path, kCFStringEncodingUTF8);
|
|
// if (nameRef)
|
|
// {
|
|
// err = AppendMenuItemTextWithCFString(recentMenu, nameRef, 0, 'FRe0' + i, NULL);
|
|
// CFRelease(nameRef);
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// err = AppendMenuItemTextWithCFString(recentMenu, NULL, kMenuItemAttrSeparator, 'FR__', NULL);
|
|
//
|
|
// str = CFCopyLocalizedString(CFSTR("ClearMenu"), "ClearMenu");
|
|
// if (str)
|
|
// {
|
|
// err = AppendMenuItemTextWithCFString(recentMenu, str, 0, 'FRcr', NULL);
|
|
// CFRelease(str);
|
|
// }
|
|
//}
|
|
//
|
|
//void AdjustMenus (void)
|
|
//{
|
|
// OSStatus err;
|
|
// MenuRef menu;
|
|
// CFStringRef str;
|
|
//
|
|
// if (running)
|
|
// {
|
|
// menu = GetMenuRef(mApple);
|
|
// DisableMenuItem(menu, iAbout);
|
|
// DisableMenuCommand(NULL, kHICommandPreferences);
|
|
// DisableMenuCommand(NULL, kHICommandQuit);
|
|
//
|
|
// menu = GetMenuRef(mFile);
|
|
// DisableMenuItem(menu, iOpen);
|
|
// DisableMenuItem(menu, iOpenMulti);
|
|
// DisableMenuItem(menu, iOpenRecent);
|
|
// DisableMenuItem(menu, iRomInfo);
|
|
//
|
|
// menu = GetMenuRef(mControl);
|
|
// DisableMenuItem(menu, iKeyboardLayout);
|
|
// DisableMenuItem(menu, iISpLayout);
|
|
// DisableMenuItem(menu, iAutoFire);
|
|
// DisableMenuItem(menu, iISpPreset);
|
|
//
|
|
// menu = GetMenuRef(mEmulation);
|
|
// str = CFCopyLocalizedString(CFSTR("PauseMenu"), "pause");
|
|
// err = SetMenuItemTextWithCFString(menu, iResume, str);
|
|
// CFRelease(str);
|
|
// DisableMenuItem(menu, iSoftReset);
|
|
// DisableMenuItem(menu, iReset);
|
|
// DisableMenuItem(menu, iDevice);
|
|
//
|
|
// if (Settings.NetPlay)
|
|
// {
|
|
// if (Settings.NetPlayServer)
|
|
// EnableMenuItem(menu, iResume);
|
|
// else
|
|
// DisableMenuItem(menu, iResume);
|
|
// }
|
|
// else
|
|
// EnableMenuItem(menu, iResume);
|
|
//
|
|
// menu = GetMenuRef(mCheat);
|
|
// DisableMenuItem(menu, iApplyCheats);
|
|
// DisableMenuItem(menu, iGameGenie);
|
|
// DisableMenuItem(menu, iCheatFinder);
|
|
//
|
|
// menu = GetMenuRef(mOption);
|
|
// DisableMenuItem(menu, iFreeze);
|
|
// DisableMenuItem(menu, iDefrost);
|
|
// DisableMenuItem(menu, iFreezeTo);
|
|
// DisableMenuItem(menu, iDefrostFrom);
|
|
// DisableMenuItem(menu, iRecordMovie);
|
|
// DisableMenuItem(menu, iPlayMovie);
|
|
// DisableMenuItem(menu, iQTMovie);
|
|
// DisableMenuItem(menu, iSaveSPC);
|
|
// DisableMenuItem(menu, iSaveSRAM);
|
|
// DisableMenuItem(menu, iMusicBox);
|
|
// if (ciFilterEnable)
|
|
// EnableMenuItem(menu, iCIFilter);
|
|
// else
|
|
// DisableMenuItem(menu, iCIFilter);
|
|
//
|
|
// menu = GetMenuRef(mNetplay);
|
|
// DisableMenuItem(menu, iServer);
|
|
// DisableMenuItem(menu, iClient);
|
|
// }
|
|
// else
|
|
// {
|
|
// menu = GetMenuRef(mApple);
|
|
// EnableMenuItem(menu, iAbout);
|
|
// EnableMenuCommand(NULL, kHICommandPreferences);
|
|
// EnableMenuCommand(NULL, kHICommandQuit);
|
|
//
|
|
// menu = GetMenuRef(mFile);
|
|
// EnableMenuItem(menu, iOpen);
|
|
// EnableMenuItem(menu, iOpenMulti);
|
|
// EnableMenuItem(menu, iOpenRecent);
|
|
// if (cartOpen)
|
|
// EnableMenuItem(menu, iRomInfo);
|
|
// else
|
|
// DisableMenuItem(menu, iRomInfo);
|
|
//
|
|
// menu = GetMenuRef(mControl);
|
|
// EnableMenuItem(menu, iKeyboardLayout);
|
|
// EnableMenuItem(menu, iAutoFire);
|
|
//
|
|
// menu = GetMenuRef(mEmulation);
|
|
// str = CFCopyLocalizedString(CFSTR("RunMenu"), "run");
|
|
// err = SetMenuItemTextWithCFString(menu, iResume, str);
|
|
// CFRelease(str);
|
|
// EnableMenuItem(menu, iDevice);
|
|
// if (cartOpen)
|
|
// {
|
|
// EnableMenuItem(menu, iResume);
|
|
// EnableMenuItem(menu, iSoftReset);
|
|
// EnableMenuItem(menu, iReset);
|
|
// }
|
|
// else
|
|
// {
|
|
// DisableMenuItem(menu, iResume);
|
|
// DisableMenuItem(menu, iSoftReset);
|
|
// DisableMenuItem(menu, iReset);
|
|
// }
|
|
//
|
|
// menu = GetMenuRef(mCheat);
|
|
// if (cartOpen)
|
|
// {
|
|
// EnableMenuItem(menu, iApplyCheats);
|
|
// EnableMenuItem(menu, iGameGenie);
|
|
// EnableMenuItem(menu, iCheatFinder);
|
|
// }
|
|
// else
|
|
// {
|
|
// DisableMenuItem(menu, iApplyCheats);
|
|
// DisableMenuItem(menu, iGameGenie);
|
|
// DisableMenuItem(menu, iCheatFinder);
|
|
// }
|
|
//
|
|
// menu = GetMenuRef(mOption);
|
|
// DisableMenuItem(menu, iCIFilter);
|
|
// if (cartOpen)
|
|
// {
|
|
// EnableMenuItem(menu, iFreeze);
|
|
// EnableMenuItem(menu, iDefrost);
|
|
// EnableMenuItem(menu, iFreezeTo);
|
|
// EnableMenuItem(menu, iDefrostFrom);
|
|
// EnableMenuItem(menu, iRecordMovie);
|
|
// EnableMenuItem(menu, iPlayMovie);
|
|
// EnableMenuItem(menu, iQTMovie);
|
|
// EnableMenuItem(menu, iSaveSPC);
|
|
// EnableMenuItem(menu, iSaveSRAM);
|
|
// EnableMenuItem(menu, iMusicBox);
|
|
// }
|
|
// else
|
|
// {
|
|
// DisableMenuItem(menu, iFreeze);
|
|
// DisableMenuItem(menu, iDefrost);
|
|
// DisableMenuItem(menu, iFreezeTo);
|
|
// DisableMenuItem(menu, iDefrostFrom);
|
|
// DisableMenuItem(menu, iRecordMovie);
|
|
// DisableMenuItem(menu, iPlayMovie);
|
|
// DisableMenuItem(menu, iQTMovie);
|
|
// DisableMenuItem(menu, iSaveSPC);
|
|
// DisableMenuItem(menu, iSaveSRAM);
|
|
// DisableMenuItem(menu, iMusicBox);
|
|
// }
|
|
//
|
|
// menu = GetMenuRef(mNetplay);
|
|
// EnableMenuItem(menu, iClient);
|
|
// if (cartOpen)
|
|
// EnableMenuItem(menu, iServer);
|
|
// else
|
|
// DisableMenuItem(menu, iServer);
|
|
// }
|
|
//
|
|
// DrawMenuBar();
|
|
//}
|
|
//
|
|
//void UpdateMenuCommandStatus (Boolean closeMenu)
|
|
//{
|
|
// if (closeMenu)
|
|
// EnableMenuItem(GetMenuRef(mFile), iClose);
|
|
// else
|
|
// DisableMenuItem(GetMenuRef(mFile), iClose);
|
|
//}
|
|
//
|
|
//static OSStatus HandleMenuChoice (UInt32 command, Boolean *done)
|
|
//{
|
|
// OSStatus err, result = noErr;
|
|
// MenuRef mh;
|
|
// int item;
|
|
// bool8 isok = true;
|
|
//
|
|
// if ((command & 0xFFFFFF00) == 'FRe\0')
|
|
// {
|
|
// Boolean r;
|
|
// int index;
|
|
// char path[PATH_MAX + 1];
|
|
//
|
|
// index = (int) (command & 0x000000FF) - (int) '0';
|
|
// r = CFStringGetCString(recentItem[index], path, PATH_MAX, kCFStringEncodingUTF8);
|
|
// if (r)
|
|
// {
|
|
// FSRef ref;
|
|
//
|
|
// err = FSPathMakeRef((unsigned char *) path, &ref, NULL);
|
|
// if (err == noErr)
|
|
// {
|
|
// if (SNES9X_OpenCart(&ref))
|
|
// {
|
|
// SNES9X_Go();
|
|
// *done = true;
|
|
// }
|
|
// else
|
|
// AdjustMenus();
|
|
// }
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// switch (command)
|
|
// {
|
|
// case 'abou': // About SNES9X
|
|
// StartCarbonModalDialog();
|
|
// AboutDialog();
|
|
// FinishCarbonModalDialog();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'pref': // Preferences...
|
|
// StartCarbonModalDialog();
|
|
// ConfigurePreferences();
|
|
// FinishCarbonModalDialog();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'EXTR': // Extra Options...
|
|
// StartCarbonModalDialog();
|
|
// ConfigureExtraOptions();
|
|
// FinishCarbonModalDialog();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'quit': // Quit SNES9X
|
|
// SNES9X_Quit();
|
|
// *done = true;
|
|
//
|
|
// break;
|
|
//
|
|
// case 'open': // Open ROM Image...
|
|
// if (SNES9X_OpenCart(NULL))
|
|
// {
|
|
// SNES9X_Go();
|
|
// *done = true;
|
|
// }
|
|
// else
|
|
// AdjustMenus();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Mult': // Open Multiple ROM Images...
|
|
// if (SNES9X_OpenMultiCart())
|
|
// {
|
|
// SNES9X_Go();
|
|
// *done = true;
|
|
// }
|
|
// else
|
|
// AdjustMenus();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'FRcr': // Clear Menu
|
|
// ClearRecentItems();
|
|
// BuildRecentMenu();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Finf': // ROM Information
|
|
// StartCarbonModalDialog();
|
|
// RomInfoDialog();
|
|
// FinishCarbonModalDialog();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Ckey': // Configure Keyboard...
|
|
// StartCarbonModalDialog();
|
|
// ConfigureKeyboard();
|
|
// FinishCarbonModalDialog();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Cpad': // Configure Controllers...
|
|
// StartCarbonModalDialog();
|
|
// ConfigureHID();
|
|
// FinishCarbonModalDialog();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Caut': // Automatic Fire...
|
|
// StartCarbonModalDialog();
|
|
// ConfigureAutofire();
|
|
// FinishCarbonModalDialog();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Hapl': // Apply Cheat Entries
|
|
// mh = GetMenuRef(mCheat);
|
|
// applycheat = !applycheat;
|
|
// CheckMenuItem(mh, iApplyCheats, applycheat);
|
|
// Settings.ApplyCheats = applycheat;
|
|
//
|
|
// if (!Settings.ApplyCheats)
|
|
// S9xCheatsDisable();
|
|
// else
|
|
// S9xCheatsEnable();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Hent': // Cheat Entry...
|
|
// StartCarbonModalDialog();
|
|
// ConfigureCheat();
|
|
// FinishCarbonModalDialog();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Hfnd': // Cheat Finder...
|
|
// StartCarbonModalDialog();
|
|
// CheatFinder();
|
|
// FinishCarbonModalDialog();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Erun': // Run
|
|
// SNES9X_Go();
|
|
// *done = true;
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Esrs': // Software Reset
|
|
// SNES9X_SoftReset();
|
|
// SNES9X_Go();
|
|
// *done = true;
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Erst': // Hardware Reset
|
|
// SNES9X_Reset();
|
|
// SNES9X_Go();
|
|
// *done = true;
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Ofrz': // Freeze State
|
|
// isok = SNES9X_Freeze();
|
|
// *done = true;
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Odfr': // Defrost state
|
|
// isok = SNES9X_Defrost();
|
|
// *done = true;
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Ofrd': // Freeze State to...
|
|
// StartCarbonModalDialog();
|
|
// isok = SNES9X_FreezeTo();
|
|
// FinishCarbonModalDialog();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Odfd': // Defrost State From...
|
|
// StartCarbonModalDialog();
|
|
// isok = SNES9X_DefrostFrom();
|
|
// if (gWindow)
|
|
// ActivateWindow(gWindow, true);
|
|
// FinishCarbonModalDialog();
|
|
// *done = true;
|
|
//
|
|
// break;
|
|
//
|
|
// case 'MVrc': // Record Movie...
|
|
// StartCarbonModalDialog();
|
|
// isok = SNES9X_RecordMovie();
|
|
// if (gWindow)
|
|
// ActivateWindow(gWindow, true);
|
|
// FinishCarbonModalDialog();
|
|
// *done = true;
|
|
//
|
|
// break;
|
|
//
|
|
// case 'MVpl': // Play Movie...
|
|
// StartCarbonModalDialog();
|
|
// isok = SNES9X_PlayMovie();
|
|
// if (isok && (macPlayFlag & 0x2))
|
|
// {
|
|
// running = false;
|
|
// isok = SNES9X_QTMovieRecord();
|
|
// running = true;
|
|
// }
|
|
//
|
|
// if (gWindow)
|
|
// ActivateWindow(gWindow, true);
|
|
// FinishCarbonModalDialog();
|
|
// *done = true;
|
|
//
|
|
// break;
|
|
//
|
|
// case 'QTmv': // Record QuickTime Movie...
|
|
// StartCarbonModalDialog();
|
|
// isok = SNES9X_QTMovieRecord();
|
|
// if (gWindow)
|
|
// ActivateWindow(gWindow, true);
|
|
// FinishCarbonModalDialog();
|
|
// *done = true;
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Ospc': // Save SPC File at Next Note-on
|
|
// S9xDumpSPCSnapshot();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Osrm': // Save SRAM Now
|
|
// SNES9X_SaveSRAM();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Ombx': // Music Box
|
|
// StartCarbonModalDialog();
|
|
// MusicBoxDialog();
|
|
// FinishCarbonModalDialog();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Nser': // Server...
|
|
// bool8 sr;
|
|
//
|
|
// Settings.NetPlay = false;
|
|
// Settings.NetPlayServer = false;
|
|
//
|
|
// NPServerInit();
|
|
//
|
|
// if (!NPServerStartServer(NP_PORT))
|
|
// {
|
|
// NPServerStopServer();
|
|
// break;
|
|
// }
|
|
//
|
|
// StartCarbonModalDialog();
|
|
// sr = NPServerDialog();
|
|
// FinishCarbonModalDialog();
|
|
//
|
|
// if (sr)
|
|
// {
|
|
// SNES9X_Reset();
|
|
// SNES9X_Go();
|
|
// Settings.NetPlay = true;
|
|
// Settings.NetPlayServer = true;
|
|
//
|
|
// *done = true;
|
|
// }
|
|
// else
|
|
// NPServerStopServer();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'Ncli': // Client...
|
|
// bool8 cr;
|
|
//
|
|
// Settings.NetPlay = false;
|
|
// Settings.NetPlayServer = false;
|
|
//
|
|
// NPClientInit();
|
|
//
|
|
// StartCarbonModalDialog();
|
|
// cr = NPClientDialog();
|
|
// FinishCarbonModalDialog();
|
|
//
|
|
// if (cr)
|
|
// {
|
|
// SNES9X_Go();
|
|
// Settings.NetPlay = true;
|
|
// Settings.NetPlayServer = false;
|
|
//
|
|
// *done = true;
|
|
// }
|
|
// else
|
|
// AdjustMenus();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'CPr1': // Controller Preset
|
|
// case 'CPr2':
|
|
// case 'CPr3':
|
|
// case 'CPr4':
|
|
// case 'CPr5':
|
|
// item = (int) (command & 0x000000FF) - (int) '0';
|
|
// err = GetMenuItemHierarchicalMenu(GetMenuRef(mControl), iISpPreset, &mh);
|
|
// CheckMenuItem(mh, padSetting, false);
|
|
// padSetting = item;
|
|
// CheckMenuItem(mh, padSetting, true);
|
|
// ClearPadSetting();
|
|
// LoadControllerSettings();
|
|
//
|
|
// break;
|
|
//
|
|
// case 'EIp1': // Input Device
|
|
// case 'EIp2':
|
|
// case 'EIp3':
|
|
// case 'EIp4':
|
|
// case 'EIp5':
|
|
// case 'EIp6':
|
|
// case 'EIp7':
|
|
// case 'EIp8':
|
|
// item = (int) (command & 0x000000FF) - (int) '0';
|
|
// err = GetMenuItemHierarchicalMenu(GetMenuRef(mEmulation), iDevice, &mh);
|
|
// CheckMenuItem(mh, deviceSetting, false);
|
|
// deviceSetting = item;
|
|
// deviceSettingMaster = deviceSetting;
|
|
// CheckMenuItem(mh, deviceSetting, true);
|
|
// ChangeInputDevice();
|
|
//
|
|
// break;
|
|
//
|
|
// default:
|
|
// result = eventNotHandledErr;
|
|
// break;
|
|
// }
|
|
// }
|
|
//
|
|
// return (result);
|
|
//}
|
|
//
|
|
void ChangeInputDevice (void)
|
|
{
|
|
switch (deviceSetting)
|
|
{
|
|
case Gamepads:
|
|
S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);
|
|
S9xSetController(1, CTL_JOYPAD, 1, 0, 0, 0);
|
|
macControllerOption = SNES_JOYPAD;
|
|
useMouse = false;
|
|
break;
|
|
|
|
case Mouse:
|
|
S9xSetController(0, CTL_MOUSE, 0, 0, 0, 0);
|
|
S9xSetController(1, CTL_JOYPAD, 1, 0, 0, 0);
|
|
macControllerOption = SNES_MOUSE;
|
|
useMouse = true;
|
|
break;
|
|
|
|
case Mouse2:
|
|
S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);
|
|
S9xSetController(1, CTL_MOUSE, 1, 0, 0, 0);
|
|
macControllerOption = SNES_MOUSE_SWAPPED;
|
|
useMouse = true;
|
|
break;
|
|
|
|
case SuperScope:
|
|
S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);
|
|
S9xSetController(1, CTL_SUPERSCOPE, 0, 0, 0, 0);
|
|
macControllerOption = SNES_SUPERSCOPE;
|
|
useMouse = true;
|
|
break;
|
|
|
|
case MultiTap:
|
|
S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);
|
|
S9xSetController(1, CTL_MP5, 1, 2, 3, 4);
|
|
macControllerOption = SNES_MULTIPLAYER5;
|
|
useMouse = false;
|
|
break;
|
|
|
|
case DoubleMultiTap:
|
|
S9xSetController(0, CTL_MP5, 0, 1, 2, 3);
|
|
S9xSetController(1, CTL_MP5, 4, 5, 6, 7);
|
|
macControllerOption = SNES_MULTIPLAYER5_2;
|
|
useMouse = false;
|
|
break;
|
|
|
|
case Justifier1:
|
|
S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);
|
|
S9xSetController(1, CTL_JUSTIFIER, 0, 0, 0, 0);
|
|
macControllerOption = SNES_JUSTIFIER;
|
|
useMouse = true;
|
|
break;
|
|
|
|
case Justifier2:
|
|
S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);
|
|
S9xSetController(1, CTL_JUSTIFIER, 1, 0, 0, 0);
|
|
macControllerOption = SNES_JUSTIFIER_2;
|
|
useMouse = true;
|
|
break;
|
|
}
|
|
|
|
[inputDelegate deviceSettingChanged:deviceSetting];
|
|
}
|
|
|
|
void ApplyNSRTHeaderControllers (void)
|
|
{
|
|
uint32 valid = 0;
|
|
deviceSetting = deviceSettingMaster;
|
|
|
|
if (!strncmp((const char *) Memory.NSRTHeader + 24, "NSRT", 4))
|
|
{
|
|
switch (Memory.NSRTHeader[29])
|
|
{
|
|
case 0x00: // Everything goes
|
|
deviceSetting = Gamepads;
|
|
valid = (1 << Gamepads);
|
|
break;
|
|
|
|
case 0x10: // Mouse in Port 0
|
|
deviceSetting = Mouse;
|
|
valid = (1 << Mouse);
|
|
break;
|
|
|
|
case 0x01: // Mouse in Port 1
|
|
deviceSetting = Mouse2;
|
|
valid = (1 << Mouse2);
|
|
break;
|
|
|
|
case 0x03: // Super Scope in Port 1
|
|
deviceSetting = SuperScope;
|
|
valid = (1 << SuperScope);
|
|
break;
|
|
|
|
case 0x06: // Multitap in Port 1
|
|
deviceSetting = MultiTap;
|
|
valid = (1 << Gamepads) | (1 << MultiTap);
|
|
break;
|
|
|
|
case 0x66: // Multitap in Ports 0 and 1
|
|
deviceSetting = DoubleMultiTap;
|
|
valid = (1 << Gamepads) | (1 << MultiTap) | (1 << DoubleMultiTap);
|
|
break;
|
|
|
|
case 0x08: // Multitap in Port 1, Mouse in new Port 1
|
|
deviceSetting = Mouse;
|
|
valid = (1 << Gamepads) | (1 << Mouse2) | (1 << MultiTap);
|
|
break;
|
|
|
|
case 0x04: // Pad or Super Scope in Port 1
|
|
deviceSetting = SuperScope;
|
|
valid = (1 << Gamepads) | (1 << SuperScope);
|
|
break;
|
|
|
|
case 0x05: // Justifier - Must ask user...
|
|
deviceSetting = Justifier1;
|
|
valid = (1 << Justifier1) | (1 << Justifier2);
|
|
break;
|
|
|
|
case 0x20: // Pad or Mouse in Port 0
|
|
deviceSetting = Mouse;
|
|
valid = (1 << Gamepads) | (1 << Mouse);
|
|
break;
|
|
|
|
case 0x22: // Pad or Mouse in Port 0 & 1
|
|
deviceSetting = Mouse;
|
|
valid = (1 << Gamepads) | (1 << Mouse) | (1 << Mouse2);
|
|
break;
|
|
|
|
case 0x24: // Pad or Mouse in Port 0, Pad or Super Scope in Port 1
|
|
deviceSetting = SuperScope;
|
|
valid = (1 << Gamepads) | (1 << Mouse) | (1 << SuperScope);
|
|
break;
|
|
|
|
case 0x27: // Pad or Mouse in Port 0, Pad or Mouse or Super Scope in Port 1
|
|
deviceSetting = SuperScope;
|
|
valid = (1 << Gamepads) | (1 << Mouse) | (1 << Mouse2) | (1 << SuperScope);
|
|
break;
|
|
|
|
case 0x99: // Lasabirdie
|
|
break;
|
|
|
|
case 0x0A: // Barcode Battler
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
ChangeInputDevice();
|
|
}
|
|
|
|
void DrawString(CGContextRef ctx, NSString *string, CGFloat size, CGFloat x, CGFloat y)
|
|
{
|
|
NSAttributedString *astr = [[NSAttributedString alloc] initWithString:string attributes:@{NSFontAttributeName: [NSFont fontWithName:@"Helvetica" size:size], NSForegroundColorAttributeName: NSColor.whiteColor}];
|
|
|
|
CTLineRef line = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)astr);
|
|
CGFloat ascent = 0.0;
|
|
CGFloat descent = 0.0;
|
|
CGFloat leading = 0.0;
|
|
CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
|
|
|
|
// Draw the text in the new CoreGraphics Context
|
|
CGContextSetTextPosition(ctx, x, y + descent);
|
|
CTLineDraw(line, ctx);
|
|
CFRelease(line);
|
|
}
|
|
|
|
int PromptFreezeDefrost (Boolean freezing)
|
|
{
|
|
OSStatus err;
|
|
CGContextRef ctx;
|
|
CGColorSpaceRef color;
|
|
CGDataProviderRef prov;
|
|
CGImageRef image;
|
|
CGRect rct;
|
|
CFURLRef url;
|
|
FSCatalogInfo info;
|
|
bool8 keys[MAC_MAX_PLAYERS][kNumButtons];
|
|
bool8 gamepadButtons[MAC_MAX_PLAYERS][kNumButtons];
|
|
CFAbsoluteTime newestDate, currentDate;
|
|
int64 startTime;
|
|
float x, y;
|
|
int result, newestIndex, current_selection, oldInactiveMode;
|
|
char dateC[256];
|
|
uint8 *back, *draw;
|
|
|
|
const UInt32 repeatDelay = 200000;
|
|
const int w = SNES_WIDTH << 1, h = SNES_HEIGHT << 1;
|
|
const char letters[] = "123456789ABC", *filename;
|
|
|
|
frzselecting = true;
|
|
[s9xView updatePauseOverlay];
|
|
oldInactiveMode = inactiveMode;
|
|
if (inactiveMode == 3)
|
|
inactiveMode = 2;
|
|
|
|
S9xSetSoundMute(true);
|
|
|
|
back = (uint8 *) malloc(w * h * 2);
|
|
draw = (uint8 *) malloc(w * h * 2);
|
|
if (!back || !draw)
|
|
QuitWithFatalError(@"os 04");
|
|
|
|
color = CGColorSpaceCreateDeviceRGB();
|
|
if (!color)
|
|
QuitWithFatalError(@"os 05");
|
|
|
|
ctx = CGBitmapContextCreate(back, w, h, 5, w * 2, color, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder16Host);
|
|
if (!ctx)
|
|
QuitWithFatalError(@"os 06");
|
|
|
|
rct = CGRectMake(0.0f, 0.0f, (float) w, (float) h);
|
|
CGContextClearRect(ctx, rct);
|
|
|
|
image = NULL;
|
|
CFBundleRef bundle = CFBundleGetBundleWithIdentifier(CFSTR("com.snes9x.macos.snes9x-framework"));
|
|
|
|
if (freezing)
|
|
url = CFBundleCopyResourceURL(bundle, CFSTR("logo_freeze"), CFSTR("png"), NULL);
|
|
else
|
|
url = CFBundleCopyResourceURL(bundle, CFSTR("logo_defrost"), CFSTR("png"), NULL);
|
|
if (url)
|
|
{
|
|
prov = CGDataProviderCreateWithURL(url);
|
|
if (prov)
|
|
{
|
|
image = CGImageCreateWithPNGDataProvider(prov, NULL, true, kCGRenderingIntentDefault);
|
|
CGDataProviderRelease(prov);
|
|
}
|
|
|
|
CFRelease(url);
|
|
}
|
|
|
|
if (image)
|
|
{
|
|
rct = CGRectMake(0.0f, (float) h - 88.0f, w, 88.0f);
|
|
CGContextDrawImage(ctx, rct, image);
|
|
CGImageRelease(image);
|
|
}
|
|
|
|
newestDate = 0;
|
|
newestIndex = -1;
|
|
|
|
CGContextSetLineJoin(ctx, kCGLineJoinRound);
|
|
|
|
rct = CGRectMake(0.0f, (float) h - 208.0f, 128.0f, 120.0f);
|
|
|
|
for (int count = 0; count < 12; count++)
|
|
{
|
|
url = nil;
|
|
filename = S9xGetFreezeFilename(count);
|
|
CFStringRef cfFilename = CFStringCreateWithCString(kCFAllocatorDefault, filename, kCFStringEncodingUTF8);
|
|
|
|
if (cfFilename != NULL)
|
|
{
|
|
url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfFilename, kCFURLPOSIXPathStyle, false);
|
|
CFRelease(cfFilename);
|
|
}
|
|
|
|
if (url != NULL)
|
|
{
|
|
CFDateRef date = NULL;
|
|
if (CFURLCopyResourcePropertyForKey(url, kCFURLAttributeModificationDateKey, &date, NULL))
|
|
{
|
|
currentDate = CFDateGetAbsoluteTime(date);
|
|
CFRelease(date);
|
|
}
|
|
else
|
|
{
|
|
currentDate = DBL_MIN;
|
|
}
|
|
|
|
if (currentDate > newestDate)
|
|
{
|
|
newestIndex = count;
|
|
newestDate = currentDate;
|
|
}
|
|
|
|
DrawThumbnailFromExtendedAttribute(filename, ctx, rct);
|
|
|
|
CGContextSetShouldAntialias(ctx, false);
|
|
CGContextSetLineWidth(ctx, 1.0f);
|
|
|
|
CGContextSetRGBStrokeColor(ctx, 0.0f, 0.0f, 0.0f, 1.0f);
|
|
x = rct.origin.x + 127.0f;
|
|
y = rct.origin.y + 119.0f;
|
|
CGContextBeginPath(ctx);
|
|
CGContextMoveToPoint(ctx, x, y);
|
|
CGContextAddLineToPoint(ctx, x, y - 119.0f);
|
|
CGContextAddLineToPoint(ctx, x - 127.0f, y - 119.0f);
|
|
CGContextStrokePath(ctx);
|
|
|
|
CGContextSetShouldAntialias(ctx, true);
|
|
CGContextSetLineWidth(ctx, 3.0f);
|
|
|
|
CGContextSetRGBFillColor(ctx, 1.0, 0.7, 0.7, 1.0);
|
|
x = rct.origin.x + 5.0f;
|
|
y = rct.origin.y + 102.0f;
|
|
DrawString(ctx, [NSString stringWithFormat:@"%c", letters[count]], 12.0, x, y);
|
|
|
|
if (showtimeinfrz)
|
|
{
|
|
CFAbsoluteTime at;
|
|
CFDateFormatterRef format;
|
|
CFLocaleRef locale;
|
|
CFStringRef datstr;
|
|
Boolean r;
|
|
|
|
err = UCConvertUTCDateTimeToCFAbsoluteTime(&(info.contentModDate), &at);
|
|
locale = CFLocaleCopyCurrent();
|
|
format = CFDateFormatterCreate(kCFAllocatorDefault, locale, kCFDateFormatterShortStyle, kCFDateFormatterMediumStyle);
|
|
datstr = CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault, format, at);
|
|
r = CFStringGetCString(datstr, dateC, sizeof(dateC), CFStringGetSystemEncoding());
|
|
CFRelease(datstr);
|
|
CFRelease(format);
|
|
CFRelease(locale);
|
|
|
|
x = rct.origin.x + 20.0f;
|
|
y = rct.origin.y + 102.0f;
|
|
DrawString(ctx, [NSString stringWithUTF8String:dateC], 10.0, x, y);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
x = rct.origin.x + 5.0f;
|
|
y = rct.origin.y + 102.0f;
|
|
DrawString(ctx, [NSString stringWithFormat:@"%c", letters[count]], 12.0, x, y);
|
|
}
|
|
|
|
if ((count % 4) == 3)
|
|
rct = CGRectOffset(rct, -128.0f * 3.0f, -120.0f);
|
|
else
|
|
rct = CGRectOffset(rct, 128.0f, 0.0f);
|
|
}
|
|
|
|
if (newestIndex < 0)
|
|
newestIndex = 0;
|
|
|
|
CGContextRelease(ctx);
|
|
|
|
image = NULL;
|
|
|
|
prov = CGDataProviderCreateWithData(NULL, back, w * h * 2, NULL);
|
|
if (prov)
|
|
{
|
|
image = CGImageCreate(w, h, 5, 16, w * 2, color, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder16Host, prov, NULL, 0, kCGRenderingIntentDefault);
|
|
CGDataProviderRelease(prov);
|
|
}
|
|
|
|
if (!image)
|
|
QuitWithFatalError(@"os 07");
|
|
|
|
ctx = CGBitmapContextCreate(draw, w, h, 5, w * 2, color, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder16Host);
|
|
if (!ctx)
|
|
QuitWithFatalError(@"os 08");
|
|
|
|
CGContextSetShouldAntialias(ctx, false);
|
|
|
|
UpdateFreezeDefrostScreen(newestIndex, image, draw, ctx);
|
|
|
|
CocoaPlayFreezeDefrostSound();
|
|
|
|
result = -2;
|
|
current_selection = newestIndex;
|
|
|
|
do
|
|
{
|
|
if (!rejectinput)
|
|
{
|
|
CopyPressedKeys(keys, gamepadButtons);
|
|
|
|
while (pressedRawKeyboardButtons[kVK_ANSI_1])
|
|
{
|
|
result = 0;
|
|
usleep(repeatDelay);
|
|
}
|
|
|
|
while (pressedRawKeyboardButtons[kVK_ANSI_2])
|
|
{
|
|
result = 1;
|
|
usleep(repeatDelay);
|
|
}
|
|
|
|
while (pressedRawKeyboardButtons[kVK_ANSI_3])
|
|
{
|
|
result = 2;
|
|
usleep(repeatDelay);
|
|
}
|
|
|
|
while (pressedRawKeyboardButtons[kVK_ANSI_4])
|
|
{
|
|
result = 3;
|
|
usleep(repeatDelay);
|
|
}
|
|
|
|
while (pressedRawKeyboardButtons[kVK_ANSI_5])
|
|
{
|
|
result = 4;
|
|
usleep(repeatDelay);
|
|
}
|
|
|
|
while (pressedRawKeyboardButtons[kVK_ANSI_6])
|
|
{
|
|
result = 5;
|
|
usleep(repeatDelay);
|
|
}
|
|
|
|
while (pressedRawKeyboardButtons[kVK_ANSI_7])
|
|
{
|
|
result = 6;
|
|
usleep(repeatDelay);
|
|
}
|
|
|
|
while (pressedRawKeyboardButtons[kVK_ANSI_8])
|
|
{
|
|
result = 7;
|
|
usleep(repeatDelay);
|
|
}
|
|
|
|
while (pressedRawKeyboardButtons[kVK_ANSI_9])
|
|
{
|
|
result = 8;
|
|
usleep(repeatDelay);
|
|
}
|
|
|
|
while (pressedRawKeyboardButtons[kVK_ANSI_A])
|
|
{
|
|
result = 9;
|
|
usleep(repeatDelay);
|
|
}
|
|
|
|
while (pressedRawKeyboardButtons[kVK_ANSI_B])
|
|
{
|
|
result = 10;
|
|
usleep(repeatDelay);
|
|
}
|
|
|
|
while (pressedRawKeyboardButtons[kVK_ANSI_C])
|
|
{
|
|
result = 11;
|
|
usleep(repeatDelay);
|
|
}
|
|
|
|
while (pressedRawKeyboardButtons[kVK_Return] || pressedRawKeyboardButtons[kVK_ANSI_KeypadEnter])
|
|
{
|
|
result = current_selection;
|
|
usleep(repeatDelay);
|
|
}
|
|
|
|
while (KeyIsPressed(keys, gamepadButtons, 0, kRight))
|
|
{
|
|
startTime = mach_absolute_time();
|
|
current_selection += 1;
|
|
if (current_selection > 11)
|
|
current_selection -= 12;
|
|
UpdateFreezeDefrostScreen(current_selection, image, draw, ctx);
|
|
usleep(repeatDelay);
|
|
CopyPressedKeys(keys, gamepadButtons);
|
|
}
|
|
|
|
while (KeyIsPressed(keys, gamepadButtons, 0, kLeft))
|
|
{
|
|
startTime = mach_absolute_time();
|
|
current_selection -= 1;
|
|
if (current_selection < 0)
|
|
current_selection += 12;
|
|
UpdateFreezeDefrostScreen(current_selection, image, draw, ctx);
|
|
usleep(repeatDelay);
|
|
CopyPressedKeys(keys, gamepadButtons);
|
|
}
|
|
|
|
while (KeyIsPressed(keys, gamepadButtons, 0, kDown))
|
|
{
|
|
startTime = mach_absolute_time();
|
|
current_selection += 4;
|
|
if (current_selection > 11)
|
|
current_selection -= 12;
|
|
UpdateFreezeDefrostScreen(current_selection, image, draw, ctx);
|
|
usleep(repeatDelay);
|
|
CopyPressedKeys(keys, gamepadButtons);
|
|
}
|
|
|
|
while (KeyIsPressed(keys, gamepadButtons, 0, kUp))
|
|
{
|
|
startTime = mach_absolute_time();
|
|
current_selection -= 4;
|
|
if (current_selection < 0)
|
|
current_selection += 12;
|
|
UpdateFreezeDefrostScreen(current_selection, image, draw, ctx);
|
|
usleep(repeatDelay);
|
|
CopyPressedKeys(keys, gamepadButtons);
|
|
}
|
|
|
|
while (ISpKeyIsPressed(keys, gamepadButtons, kISpEsc))
|
|
{
|
|
result = -1;
|
|
usleep(repeatDelay);
|
|
CopyPressedKeys(keys, gamepadButtons);
|
|
}
|
|
|
|
while (KeyIsPressed(keys, gamepadButtons, 0, kA) ||
|
|
KeyIsPressed(keys, gamepadButtons, 1, kA) ||
|
|
KeyIsPressed(keys, gamepadButtons, 0, kB) ||
|
|
KeyIsPressed(keys, gamepadButtons, 1, kB) ||
|
|
KeyIsPressed(keys, gamepadButtons, 0, kX) ||
|
|
KeyIsPressed(keys, gamepadButtons, 1, kX) ||
|
|
KeyIsPressed(keys, gamepadButtons, 0, kY) ||
|
|
KeyIsPressed(keys, gamepadButtons, 1, kY))
|
|
{
|
|
result = current_selection;
|
|
usleep(repeatDelay);
|
|
CopyPressedKeys(keys, gamepadButtons);
|
|
}
|
|
}
|
|
|
|
usleep(30000);
|
|
|
|
UpdateFreezeDefrostScreen(current_selection, image, draw, ctx);
|
|
} while (result == -2 && frzselecting);
|
|
|
|
CocoaPlayFreezeDefrostSound();
|
|
|
|
CGContextRelease(ctx);
|
|
CGImageRelease(image);
|
|
CGColorSpaceRelease(color);
|
|
free(draw);
|
|
free(back);
|
|
|
|
S9xSetSoundMute(false);
|
|
|
|
inactiveMode = oldInactiveMode;
|
|
frzselecting = false;
|
|
pauseEmulation = false;
|
|
|
|
[s9xView updatePauseOverlay];
|
|
|
|
return (result);
|
|
}
|
|
|
|
static void UpdateFreezeDefrostScreen (int newIndex, CGImageRef image, uint8 *draw, CGContextRef ctx)
|
|
{
|
|
if (newIndex >= 0 && newIndex < 12)
|
|
{
|
|
CGRect rct;
|
|
const int w = SNES_WIDTH << 1, h = SNES_HEIGHT << 1;
|
|
|
|
CGContextSetLineWidth(ctx, 1.0f);
|
|
|
|
rct = CGRectMake(0.0f, 0.0f, (float) w, (float) h);
|
|
CGContextDrawImage(ctx, rct, image);
|
|
|
|
rct = CGRectMake(0.0f, (float) h - 208.0f, 128.0f, 120.0f);
|
|
rct = CGRectOffset(rct, (float) (128 * (newIndex % 4)), (float) (-120 * (newIndex / 4)));
|
|
rct.size.width -= 1.0f;
|
|
rct.size.height -= 1.0f;
|
|
|
|
CGContextSetRGBStrokeColor(ctx, 1.0f, 1.0f, 0.0f, 1.0f);
|
|
CGContextStrokeRect(ctx, rct);
|
|
rct = CGRectInset(rct, 1.0f, 1.0f);
|
|
CGContextSetRGBStrokeColor(ctx, 0.0f, 0.0f, 0.0f, 1.0f);
|
|
CGContextStrokeRect(ctx, rct);
|
|
}
|
|
|
|
DrawFreezeDefrostScreen(draw);
|
|
}
|
|
|
|
static void ProcessInput (void)
|
|
{
|
|
bool8 keys[MAC_MAX_PLAYERS][kNumButtons];
|
|
bool8 gamepadButtons[MAC_MAX_PLAYERS][kNumButtons];
|
|
bool8 isok, fnbtn, altbtn, tcbtn;
|
|
static bool8 toggleff = false, lastTimeTT = false, lastTimeFn = false, ffUp = false, ffDown = false;
|
|
|
|
if (rejectinput)
|
|
return;
|
|
|
|
CopyPressedKeys(keys, gamepadButtons);
|
|
|
|
fnbtn = ISpKeyIsPressed(keys, gamepadButtons, kISpFunction);
|
|
altbtn = ISpKeyIsPressed(keys, gamepadButtons, kISpAlt);
|
|
|
|
if (fnbtn)
|
|
{
|
|
if (!lastTimeFn)
|
|
{
|
|
memset(heldFunctionButtons, 0, kNumFunctionButtons);
|
|
}
|
|
|
|
lastTimeFn = true;
|
|
lastTimeTT = false;
|
|
ffUp = ffDown = false;
|
|
|
|
for (unsigned int i = 0; i < kNumFunctionButtons; i++)
|
|
{
|
|
if (pressedFunctionButtons[i])
|
|
{
|
|
if (!heldFunctionButtons[i])
|
|
{
|
|
s9xcommand_t s9xcmd;
|
|
static char msg[64];
|
|
|
|
heldFunctionButtons[i] = true;
|
|
|
|
switch ((S9xFunctionButtonCommand) i)
|
|
{
|
|
case ToggleBG0:
|
|
s9xcmd = S9xGetCommandT("ToggleBG0");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case ToggleBG1:
|
|
s9xcmd = S9xGetCommandT("ToggleBG1");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case ToggleBG2:
|
|
s9xcmd = S9xGetCommandT("ToggleBG2");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case ToggleBG3:
|
|
s9xcmd = S9xGetCommandT("ToggleBG3");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case ToggleSprites:
|
|
s9xcmd = S9xGetCommandT("ToggleSprites");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case SwapJoypads:
|
|
s9xcmd = S9xGetCommandT("SwapJoypads");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case SoundChannel0:
|
|
s9xcmd = S9xGetCommandT("SoundChannel0");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case SoundChannel1:
|
|
s9xcmd = S9xGetCommandT("SoundChannel1");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case SoundChannel2:
|
|
s9xcmd = S9xGetCommandT("SoundChannel2");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case SoundChannel3:
|
|
s9xcmd = S9xGetCommandT("SoundChannel3");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case SoundChannel4:
|
|
s9xcmd = S9xGetCommandT("SoundChannel4");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case SoundChannel5:
|
|
s9xcmd = S9xGetCommandT("SoundChannel5");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case SoundChannel6:
|
|
s9xcmd = S9xGetCommandT("SoundChannel6");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case SoundChannel7:
|
|
s9xcmd = S9xGetCommandT("SoundChannel7");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case SoundChannelsOn:
|
|
s9xcmd = S9xGetCommandT("SoundChannelsOn");
|
|
S9xApplyCommand(s9xcmd, 1, 0);
|
|
break;
|
|
|
|
case ToggleDisplayPressedKeys:
|
|
Settings.DisplayPressedKeys = !Settings.DisplayPressedKeys;
|
|
break;
|
|
|
|
case ToggleDisplayMovieFrame:
|
|
if (S9xMovieActive())
|
|
Settings.DisplayMovieFrame = !Settings.DisplayMovieFrame;
|
|
break;
|
|
|
|
case IncreaseFrameAdvanceRate:
|
|
if (macFrameAdvanceRate < 5000000)
|
|
macFrameAdvanceRate += 100000;
|
|
sprintf(msg, "Emulation Speed: 100/%d", macFrameAdvanceRate / 10000);
|
|
S9xSetInfoString(msg);
|
|
break;
|
|
|
|
case DecreaseFrameAdvanceRate:
|
|
if (macFrameAdvanceRate > 500000)
|
|
macFrameAdvanceRate -= 100000;
|
|
sprintf(msg, "Emulation Speed: 100/%d", macFrameAdvanceRate / 10000);
|
|
S9xSetInfoString(msg);
|
|
break;
|
|
|
|
case ToggleEmulationPause:
|
|
pauseEmulation = !pauseEmulation;
|
|
|
|
if (pauseEmulation)
|
|
{
|
|
[s9xView.emulationDelegate emulationPaused];
|
|
}
|
|
else
|
|
{
|
|
[s9xView.emulationDelegate emulationResumed];
|
|
}
|
|
|
|
[s9xView updatePauseOverlay];
|
|
break;
|
|
|
|
case AdvanceFrame:
|
|
frameAdvance = true;
|
|
break;
|
|
|
|
case kNumFunctionButtons:
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lastTimeFn = false;
|
|
|
|
if (ISpKeyIsPressed(keys, gamepadButtons, kISpEsc))
|
|
{
|
|
if (!escKeyDown)
|
|
{
|
|
escKeyDown = true;
|
|
pauseEmulation = !pauseEmulation;
|
|
|
|
if (pauseEmulation)
|
|
{
|
|
[s9xView.emulationDelegate emulationPaused];
|
|
}
|
|
else
|
|
{
|
|
[s9xView.emulationDelegate emulationResumed];
|
|
}
|
|
|
|
[s9xView updatePauseOverlay];
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^
|
|
{
|
|
[s9xView setNeedsDisplay:YES];
|
|
});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
escKeyDown = false;
|
|
}
|
|
|
|
if (ISpKeyIsPressed(keys, gamepadButtons, kISpFreeze))
|
|
{
|
|
MacStopSound();
|
|
while (ISpKeyIsPressed(keys, gamepadButtons, kISpFreeze))
|
|
CopyPressedKeys(keys, gamepadButtons);
|
|
|
|
isok = SNES9X_Freeze();
|
|
return;
|
|
}
|
|
|
|
if (ISpKeyIsPressed(keys, gamepadButtons, kISpDefrost))
|
|
{
|
|
MacStopSound();
|
|
while (ISpKeyIsPressed(keys, gamepadButtons, kISpDefrost))
|
|
CopyPressedKeys(keys, gamepadButtons);
|
|
|
|
isok = SNES9X_Defrost();
|
|
return;
|
|
}
|
|
|
|
if (ISpKeyIsPressed(keys, gamepadButtons, kISpScreenshot))
|
|
{
|
|
Settings.TakeScreenshot = true;
|
|
while (ISpKeyIsPressed(keys, gamepadButtons, kISpScreenshot))
|
|
CopyPressedKeys(keys, gamepadButtons);
|
|
}
|
|
|
|
if (ISpKeyIsPressed(keys, gamepadButtons, kISpSPC))
|
|
{
|
|
S9xDumpSPCSnapshot();
|
|
while (ISpKeyIsPressed(keys, gamepadButtons, kISpSPC))
|
|
CopyPressedKeys(keys, gamepadButtons);
|
|
}
|
|
|
|
if (ISpKeyIsPressed(keys, gamepadButtons, kISpFFUp))
|
|
{
|
|
if (!ffUp)
|
|
{
|
|
ChangeTurboRate(+1);
|
|
ffUp = true;
|
|
}
|
|
}
|
|
else
|
|
ffUp = false;
|
|
|
|
if (ISpKeyIsPressed(keys, gamepadButtons, kISpFFDown))
|
|
{
|
|
if (!ffDown)
|
|
{
|
|
ChangeTurboRate(-1);
|
|
ffDown = true;
|
|
}
|
|
}
|
|
else
|
|
ffDown = false;
|
|
|
|
for (int i = 0; i < MAC_MAX_PLAYERS; ++i)
|
|
{
|
|
controlPad[i] = 0;
|
|
if (KeyIsPressed(keys, gamepadButtons, i, kR )) controlPad[i] |= 0x0010;
|
|
if (KeyIsPressed(keys, gamepadButtons, i, kL )) controlPad[i] |= 0x0020;
|
|
if (KeyIsPressed(keys, gamepadButtons, i, kX )) controlPad[i] |= 0x0040;
|
|
if (KeyIsPressed(keys, gamepadButtons, i, kA )) controlPad[i] |= 0x0080;
|
|
if (KeyIsPressed(keys, gamepadButtons, i, kRight )) controlPad[i] |= 0x0100;
|
|
if (KeyIsPressed(keys, gamepadButtons, i, kLeft )) controlPad[i] |= 0x0200;
|
|
if (KeyIsPressed(keys, gamepadButtons, i, kDown )) controlPad[i] |= 0x0400;
|
|
if (KeyIsPressed(keys, gamepadButtons, i, kUp )) controlPad[i] |= 0x0800;
|
|
if (KeyIsPressed(keys, gamepadButtons, i, kStart )) controlPad[i] |= 0x1000;
|
|
if (KeyIsPressed(keys, gamepadButtons, i, kSelect)) controlPad[i] |= 0x2000;
|
|
if (KeyIsPressed(keys, gamepadButtons, i, kY )) controlPad[i] |= 0x4000;
|
|
if (KeyIsPressed(keys, gamepadButtons, i, kB )) controlPad[i] |= 0x8000;
|
|
}
|
|
|
|
if (altbtn)
|
|
{
|
|
if (!lastTimeTT)
|
|
changeAuto[0] = changeAuto[1] = 0;
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
for (int j = 0; j < 12; j++)
|
|
{
|
|
uint16 mask = 0x0010 << j;
|
|
|
|
if (controlPad[i] & mask & autofireRec[i].toggleMask)
|
|
{
|
|
controlPad[i] &= ~mask;
|
|
|
|
if (!(changeAuto[i] & mask))
|
|
{
|
|
changeAuto[i] |= mask;
|
|
ChangeAutofireSettings(i, j);
|
|
}
|
|
}
|
|
else
|
|
changeAuto[i] &= ~mask;
|
|
}
|
|
}
|
|
|
|
lastTimeTT = true;
|
|
}
|
|
else
|
|
lastTimeTT = false;
|
|
}
|
|
|
|
if (enabletoggle)
|
|
{
|
|
if (ISpKeyIsPressed(keys, gamepadButtons, kISpFastForward) && !fnbtn)
|
|
{
|
|
if (!toggleff)
|
|
{
|
|
toggleff = true;
|
|
Settings.TurboMode = !Settings.TurboMode;
|
|
S9xSetInfoString(Settings.TurboMode ? "Turbo mode on" : "Turbo mode off");
|
|
if (!Settings.TurboMode)
|
|
S9xClearSamples();
|
|
}
|
|
}
|
|
else
|
|
toggleff = false;
|
|
}
|
|
else
|
|
{
|
|
bool8 old = Settings.TurboMode;
|
|
Settings.TurboMode = (ISpKeyIsPressed(keys, gamepadButtons, kISpFastForward) && !fnbtn) ? true : false;
|
|
if (!Settings.TurboMode && old)
|
|
S9xClearSamples();
|
|
}
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
controlPad[i] ^= autofireRec[i].invertMask;
|
|
|
|
if (autofire)
|
|
{
|
|
long long currentTime;
|
|
uint16 changeMask;
|
|
|
|
currentTime = GetMicroseconds();
|
|
tcbtn = (ISpKeyIsPressed(keys, gamepadButtons, kISpTC));
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
changeMask = (lastTimeTT ? (~changeAuto[i]) : 0xFFFF);
|
|
|
|
for (int j = 0; j < 12; j++)
|
|
{
|
|
uint16 mask = (0x0010 << j) & changeMask;
|
|
|
|
if (autofireRec[i].tcMask & mask)
|
|
{
|
|
if (!tcbtn)
|
|
continue;
|
|
}
|
|
|
|
if (autofireRec[i].buttonMask & mask)
|
|
{
|
|
if (controlPad[i] & mask)
|
|
{
|
|
if (currentTime > autofireRec[i].nextTime[j])
|
|
{
|
|
if (Settings.TurboMode)
|
|
autofireRec[i].nextTime[j] = currentTime + (long long) ((1.0 / (float) autofireRec[i].frequency) * 1000000.0 / macFastForwardRate);
|
|
else
|
|
autofireRec[i].nextTime[j] = currentTime + (long long) ((1.0 / (float) autofireRec[i].frequency) * 1000000.0);
|
|
}
|
|
else
|
|
controlPad[i] &= ~mask;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < MAC_MAX_PLAYERS; ++i)
|
|
{
|
|
ControlPadFlagsToS9xReportButtons(i, controlPad[i]);
|
|
}
|
|
|
|
if (macControllerOption == SNES_JUSTIFIER_2)
|
|
{
|
|
ControlPadFlagsToS9xPseudoPointer(controlPad[1]);
|
|
}
|
|
}
|
|
|
|
static void ChangeAutofireSettings (int player, int btn)
|
|
{
|
|
static char msg[64];
|
|
uint16 mask, m;
|
|
|
|
mask = 0x0010 << btn;
|
|
autofireRec[player].buttonMask ^= mask;
|
|
autofire = (autofireRec[0].buttonMask || autofireRec[1].buttonMask);
|
|
|
|
m = autofireRec[player].buttonMask;
|
|
if (m)
|
|
snprintf(msg, sizeof(msg), "Autofire %d:%s%s%s%s%s%s%s%s%s%s%s%s%s", player + 1,
|
|
(m & 0xC0F0 ? " " : ""),
|
|
(m & 0x0080 ? "A" : ""),
|
|
(m & 0x8000 ? "B" : ""),
|
|
(m & 0x0040 ? "X" : ""),
|
|
(m & 0x4000 ? "Y" : ""),
|
|
(m & 0x0020 ? "L" : ""),
|
|
(m & 0x0010 ? "R" : ""),
|
|
(m & 0x0800 ? " Up" : ""),
|
|
(m & 0x0400 ? " Dn" : ""),
|
|
(m & 0x0200 ? " Lf" : ""),
|
|
(m & 0x0100 ? " Rt" : ""),
|
|
(m & 0x1000 ? " St" : ""),
|
|
(m & 0x2000 ? " Se" : ""));
|
|
else
|
|
snprintf(msg, sizeof(msg), "Autofire %d: Off", player + 1);
|
|
|
|
S9xSetInfoString(msg);
|
|
}
|
|
|
|
static void ChangeTurboRate (int d)
|
|
{
|
|
static char msg[64];
|
|
|
|
macFastForwardRate += d;
|
|
if (macFastForwardRate < 1)
|
|
macFastForwardRate = 1;
|
|
else
|
|
if (macFastForwardRate > 15)
|
|
macFastForwardRate = 15;
|
|
|
|
snprintf(msg, sizeof(msg), "Turbo Rate: %d", macFastForwardRate);
|
|
S9xSetInfoString(msg);
|
|
}
|
|
|
|
static void Initialize (void)
|
|
{
|
|
bzero(&Settings, sizeof(Settings));
|
|
Settings.MouseMaster = true;
|
|
Settings.SuperScopeMaster = true;
|
|
Settings.JustifierMaster = true;
|
|
Settings.MultiPlayer5Master = true;
|
|
Settings.FrameTimePAL = 20000;
|
|
Settings.FrameTimeNTSC = 16667;
|
|
Settings.DisplayWatchedAddresses = true;
|
|
Settings.SixteenBitSound = true;
|
|
Settings.Stereo = true;
|
|
Settings.SoundPlaybackRate = 32000;
|
|
Settings.SoundInputRate = 31950;
|
|
Settings.Transparency = true;
|
|
Settings.AutoDisplayMessages = true;
|
|
Settings.InitialInfoStringTimeout = 120;
|
|
Settings.HDMATimingHack = 100;
|
|
Settings.BlockInvalidVRAMAccessMaster = true;
|
|
Settings.StopEmulation = true;
|
|
Settings.WrongMovieStateProtection = true;
|
|
Settings.DumpStreamsMaxFrames = -1;
|
|
Settings.StretchScreenshots = 1;
|
|
Settings.SnapshotScreenshots = true;
|
|
Settings.SuperFXClockMultiplier = 100;
|
|
Settings.InterpolationMethod = DSP_INTERPOLATION_GAUSSIAN;
|
|
Settings.MaxSpriteTilesPerLine = 34;
|
|
Settings.OneClockCycle = 6;
|
|
Settings.OneSlowClockCycle = 8;
|
|
Settings.TwoClockCycles = 12;
|
|
|
|
mach_timebase_info_data_t info;
|
|
mach_timebase_info(&info);
|
|
|
|
machTimeNumerator = info.numer;
|
|
machTimeDenominator = info.denom * 1000;
|
|
|
|
npServerIP[0] = 0;
|
|
npName[0] = 0;
|
|
|
|
saveFolderPath = NULL;
|
|
|
|
CreateIconImages();
|
|
|
|
InitKeyboard();
|
|
InitAutofire();
|
|
|
|
InitGraphics();
|
|
InitMacSound();
|
|
SetUpHID();
|
|
|
|
autofire = (autofireRec[0].buttonMask || autofireRec[1].buttonMask) ? true : false;
|
|
for (int a = 0; a < MAC_MAX_PLAYERS; a++)
|
|
for (int b = 0; b < 12; b++)
|
|
autofireRec[a].nextTime[b] = 0;
|
|
|
|
S9xMovieInit();
|
|
|
|
S9xUnmapAllControls();
|
|
S9xSetupDefaultKeymap();
|
|
ChangeInputDevice();
|
|
|
|
if (!Memory.Init() || !S9xInitAPU() || !S9xGraphicsInit())
|
|
{
|
|
|
|
}
|
|
|
|
frzselecting = false;
|
|
[s9xView updatePauseOverlay];
|
|
|
|
S9xSetControllerCrosshair(X_MOUSE1, 0, NULL, NULL);
|
|
S9xSetControllerCrosshair(X_MOUSE2, 0, NULL, NULL);
|
|
}
|
|
|
|
static void Deinitialize (void)
|
|
{
|
|
deviceSetting = deviceSettingMaster;
|
|
|
|
ReleaseHID();
|
|
DeinitGraphics();
|
|
DeinitKeyboard();
|
|
DeinitMacSound();
|
|
ReleaseIconImages();
|
|
|
|
S9xGraphicsDeinit();
|
|
S9xDeinitAPU();
|
|
Memory.Deinit();
|
|
|
|
pthread_mutex_destroy(&keyLock);
|
|
}
|
|
|
|
uint64 GetMicroseconds(void)
|
|
{
|
|
uint64 ms = mach_absolute_time();
|
|
ms *= machTimeNumerator;
|
|
ms /= machTimeDenominator;
|
|
|
|
return ms;
|
|
}
|
|
|
|
static void InitAutofire (void)
|
|
{
|
|
autofire = false;
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
for (int j = 0; j < 12; j++)
|
|
autofireRec[i].nextTime[j] = 0;
|
|
|
|
autofireRec[i].buttonMask = 0x0000;
|
|
autofireRec[i].toggleMask = 0xFFF0;
|
|
autofireRec[i].tcMask = 0x0000;
|
|
autofireRec[i].invertMask = 0x0000;
|
|
autofireRec[i].frequency = 10;
|
|
}
|
|
}
|
|
|
|
void S9xSyncSpeed (void)
|
|
{
|
|
long long currentFrame, adjustment;
|
|
|
|
if (Settings.SoundSync)
|
|
{
|
|
while (!S9xSyncSound())
|
|
usleep(0);
|
|
}
|
|
|
|
if (!macQTRecord)
|
|
{
|
|
if (macFrameSkip < 0) // auto skip
|
|
{
|
|
skipFrames--;
|
|
|
|
if (skipFrames <= 0)
|
|
{
|
|
adjustment = (Settings.TurboMode ? (macFrameAdvanceRate / macFastForwardRate) : macFrameAdvanceRate) / Memory.ROMFramesPerSecond;
|
|
currentFrame = GetMicroseconds();
|
|
|
|
skipFrames = (int32) ((currentFrame - lastFrame) / adjustment);
|
|
lastFrame += frameCount * adjustment;
|
|
|
|
if (skipFrames < 1)
|
|
skipFrames = 1;
|
|
else
|
|
if (skipFrames > 7)
|
|
{
|
|
skipFrames = 7;
|
|
lastFrame = GetMicroseconds();
|
|
}
|
|
|
|
frameCount = skipFrames;
|
|
|
|
if (lastFrame > currentFrame)
|
|
usleep((useconds_t) (lastFrame - currentFrame));
|
|
|
|
IPPU.RenderThisFrame = true;
|
|
}
|
|
else
|
|
IPPU.RenderThisFrame = false;
|
|
}
|
|
else // constant
|
|
{
|
|
skipFrames--;
|
|
|
|
if (skipFrames <= 0)
|
|
{
|
|
adjustment = macFrameAdvanceRate * macFrameSkip / Memory.ROMFramesPerSecond;
|
|
currentFrame = GetMicroseconds();
|
|
|
|
if (currentFrame - lastFrame < adjustment)
|
|
{
|
|
usleep((useconds_t) (adjustment + lastFrame - currentFrame));
|
|
currentFrame = GetMicroseconds();
|
|
}
|
|
|
|
lastFrame = currentFrame;
|
|
skipFrames = macFrameSkip;
|
|
if (Settings.TurboMode)
|
|
skipFrames *= macFastForwardRate;
|
|
|
|
IPPU.RenderThisFrame = true;
|
|
}
|
|
else
|
|
IPPU.RenderThisFrame = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//MacQTRecordFrame(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight);
|
|
|
|
adjustment = macFrameAdvanceRate / Memory.ROMFramesPerSecond;
|
|
currentFrame = GetMicroseconds();
|
|
|
|
if (currentFrame - lastFrame < adjustment)
|
|
usleep((useconds_t) (adjustment + lastFrame - currentFrame));
|
|
|
|
lastFrame = currentFrame;
|
|
|
|
IPPU.RenderThisFrame = true;
|
|
}
|
|
}
|
|
|
|
void S9xAutoSaveSRAM (void)
|
|
{
|
|
SNES9X_SaveSRAM();
|
|
}
|
|
|
|
void S9xMessage (int type, int number, const char *message)
|
|
{
|
|
static char mes[256];
|
|
|
|
if (!onscreeninfo)
|
|
{
|
|
printf("%s\n", message);
|
|
|
|
// if ((type == S9X_INFO) && (number == S9X_ROM_INFO))
|
|
// if (strstr(message, "checksum ok") == NULL)
|
|
// AppearanceAlert(kAlertCautionAlert, kS9xMacAlertkBadRom, kS9xMacAlertkBadRomHint);
|
|
}
|
|
else
|
|
{
|
|
strncpy(mes, message, 255);
|
|
S9xSetInfoString(mes);
|
|
}
|
|
}
|
|
|
|
const char * S9xStringInput (const char *s)
|
|
{
|
|
return (NULL);
|
|
}
|
|
|
|
void S9xToggleSoundChannel (int c)
|
|
{
|
|
static int channel_enable = 255;
|
|
|
|
if (c == 8)
|
|
channel_enable = 255;
|
|
else
|
|
channel_enable ^= 1 << c;
|
|
|
|
S9xSetSoundControl(channel_enable);
|
|
}
|
|
|
|
void S9xExit (void)
|
|
{
|
|
NSBeep();
|
|
|
|
running = false;
|
|
cartOpen = false;
|
|
}
|
|
|
|
void QuitWithFatalError ( NSString *message)
|
|
{
|
|
NSError *error = [NSError errorWithDomain:@"com.snes9x" code:0 userInfo:@{ NSLocalizedFailureReasonErrorKey: message }];
|
|
NSAlert *alert = [NSAlert alertWithError:error];
|
|
[alert runModal];
|
|
[NSApp terminate:nil];
|
|
}
|
|
|
|
@implementation S9xView
|
|
|
|
+ (void)initialize
|
|
{
|
|
pthread_mutex_init(&keyLock, NULL);
|
|
}
|
|
|
|
- (instancetype)initWithFrame:(NSRect)frameRect
|
|
{
|
|
self = [super initWithFrame:frameRect];
|
|
|
|
if (self)
|
|
{
|
|
NSView *dimmedView = [[NSView alloc] initWithFrame:frameRect];
|
|
dimmedView.wantsLayer = YES;
|
|
dimmedView.layer.backgroundColor = NSColor.blackColor.CGColor;
|
|
dimmedView.layer.opacity = 0.5;
|
|
dimmedView.layer.zPosition = 100.0;
|
|
dimmedView.translatesAutoresizingMaskIntoConstraints = NO;
|
|
[self addSubview:dimmedView];
|
|
|
|
[dimmedView.topAnchor constraintEqualToAnchor:self.topAnchor].active = YES;
|
|
[dimmedView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor].active = YES;
|
|
[dimmedView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor].active = YES;
|
|
[dimmedView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor].active = YES;
|
|
|
|
dimmedView.hidden = YES;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)viewWillMoveToWindow:(NSWindow *)newWindow
|
|
{
|
|
newWindow.acceptsMouseMovedEvents = YES;
|
|
}
|
|
|
|
- (void)keyDown:(NSEvent *)event
|
|
{
|
|
if (!NSApp.isActive)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pthread_mutex_lock(&keyLock);
|
|
S9xButton button = keyCodes[event.keyCode];
|
|
if ( button.buttonCode >= 0 && button.buttonCode < kNumButtons && button.player >= 0 && button.player <= MAC_MAX_PLAYERS)
|
|
{
|
|
pressedKeys[button.player][button.buttonCode] = true;
|
|
}
|
|
|
|
for ( NSUInteger i = 0; i < kNumFunctionButtons; ++i )
|
|
{
|
|
if ( event.keyCode == functionButtons[i])
|
|
{
|
|
pressedFunctionButtons[i] = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pressedRawKeyboardButtons[event.keyCode] = true;
|
|
|
|
pthread_mutex_unlock(&keyLock);
|
|
}
|
|
|
|
- (void)keyUp:(NSEvent *)event
|
|
{
|
|
if (!NSApp.isActive)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pthread_mutex_lock(&keyLock);
|
|
S9xButton button = keyCodes[event.keyCode];
|
|
if ( button.buttonCode >= 0 && button.buttonCode < kNumButtons && button.player >= 0 && button.player <= MAC_MAX_PLAYERS)
|
|
{
|
|
pressedKeys[button.player][button.buttonCode] = false;
|
|
}
|
|
|
|
for ( NSUInteger i = 0; i < kNumFunctionButtons; ++i )
|
|
{
|
|
if ( event.keyCode == functionButtons[i])
|
|
{
|
|
pressedFunctionButtons[i] = false;
|
|
heldFunctionButtons[i] = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pressedRawKeyboardButtons[event.keyCode] = false;
|
|
|
|
pthread_mutex_unlock(&keyLock);
|
|
}
|
|
|
|
- (void)flagsChanged:(NSEvent *)event
|
|
{
|
|
if (!NSApp.isActive)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pthread_mutex_lock(&keyLock);
|
|
|
|
NSEventModifierFlags flags = event.modifierFlags;
|
|
|
|
struct S9xButton button = keyCodes[kVK_Shift];
|
|
if (button.buttonCode >= 0 && button.buttonCode < kNumButtons && button.player >= 0 && button.player < MAC_MAX_PLAYERS)
|
|
{
|
|
pressedKeys[button.player][button.buttonCode] = (flags & NSEventModifierFlagShift) != 0;
|
|
}
|
|
|
|
button = keyCodes[kVK_Command];
|
|
if (button.buttonCode >= 0 && button.buttonCode < kNumButtons && button.player >= 0 && button.player < MAC_MAX_PLAYERS)
|
|
{
|
|
pressedKeys[button.player][button.buttonCode] = (flags & NSEventModifierFlagCommand) != 0;
|
|
}
|
|
|
|
button = keyCodes[kVK_Control];
|
|
if (button.buttonCode >= 0 && button.buttonCode < kNumButtons && button.player >= 0 && button.player < MAC_MAX_PLAYERS)
|
|
{
|
|
pressedKeys[button.player][button.buttonCode] = (flags & NSEventModifierFlagControl) != 0;
|
|
}
|
|
|
|
button = keyCodes[kVK_Option];
|
|
if (button.buttonCode >= 0 && button.buttonCode < kNumButtons && button.player >= 0 && button.player < MAC_MAX_PLAYERS)
|
|
{
|
|
pressedKeys[button.player][button.buttonCode] = (flags & NSEventModifierFlagOption) != 0;
|
|
}
|
|
|
|
pthread_mutex_unlock(&keyLock);
|
|
}
|
|
|
|
- (void)mouseDown:(NSEvent *)event
|
|
{
|
|
if ( useMouse )
|
|
{
|
|
switch (deviceSetting)
|
|
{
|
|
case Mouse:
|
|
case SuperScope:
|
|
case Justifier1:
|
|
pressedKeys[0][kKeyMouseLeft] = true;
|
|
break;
|
|
|
|
case Mouse2:
|
|
case Justifier2:
|
|
pressedKeys[1][kKeyMouseLeft] = true;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pauseEmulation = true;
|
|
[self.emulationDelegate emulationPaused];
|
|
|
|
[s9xView updatePauseOverlay];
|
|
}
|
|
}
|
|
|
|
- (void)mouseUp:(NSEvent *)event
|
|
{
|
|
if ( useMouse )
|
|
{
|
|
switch (deviceSetting)
|
|
{
|
|
case Mouse:
|
|
case SuperScope:
|
|
case Justifier1:
|
|
pressedKeys[0][kKeyMouseLeft] = false;
|
|
break;
|
|
|
|
case Mouse2:
|
|
case Justifier2:
|
|
pressedKeys[1][kKeyMouseLeft] = false;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)rightMouseDown:(NSEvent *)event
|
|
{
|
|
if ( useMouse )
|
|
{
|
|
switch (deviceSetting)
|
|
{
|
|
case Mouse:
|
|
case SuperScope:
|
|
case Justifier1:
|
|
pressedKeys[0][kKeyMouseRight] = true;
|
|
break;
|
|
|
|
case Mouse2:
|
|
case Justifier2:
|
|
pressedKeys[1][kKeyMouseRight] = true;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)rightMouseUp:(NSEvent *)event
|
|
{
|
|
if ( useMouse )
|
|
{
|
|
switch (deviceSetting)
|
|
{
|
|
case Mouse:
|
|
case SuperScope:
|
|
case Justifier1:
|
|
pressedKeys[0][kKeyMouseRight] = false;
|
|
break;
|
|
|
|
case Mouse2:
|
|
case Justifier2:
|
|
pressedKeys[1][kKeyMouseRight] = false;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)mouseMoved:(NSEvent *)event
|
|
{
|
|
if ( useMouse && running && !pauseEmulation )
|
|
{
|
|
rawMouseX += event.deltaX;
|
|
rawMouseY += event.deltaY;
|
|
CGRect bounds = self.bounds;
|
|
|
|
if (rawMouseX < 0)
|
|
{
|
|
rawMouseX = 0;
|
|
}
|
|
else if (rawMouseX > bounds.size.width)
|
|
{
|
|
rawMouseX = bounds.size.width;
|
|
}
|
|
|
|
if (rawMouseY < 0)
|
|
{
|
|
rawMouseY = 0;
|
|
}
|
|
else if ( rawMouseY > bounds.size.height)
|
|
{
|
|
rawMouseY = bounds.size.height;
|
|
}
|
|
|
|
mouseX = (int16) (rawMouseX / ((float) bounds.size.width ) * (float) IPPU.RenderedScreenWidth);
|
|
mouseY = (int16) (rawMouseY / ((float) bounds.size.height) * (float) IPPU.RenderedScreenHeight);
|
|
}
|
|
}
|
|
|
|
- (void)mouseDragged:(NSEvent *)event
|
|
{
|
|
[self mouseMoved:event];
|
|
}
|
|
|
|
- (void)rightMouseDragged:(NSEvent *)event
|
|
{
|
|
[self mouseMoved:event];
|
|
}
|
|
|
|
- (void)otherMouseDragged:(NSEvent *)event
|
|
{
|
|
[self mouseMoved:event];
|
|
}
|
|
|
|
- (void)updatePauseOverlay
|
|
{
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
self.subviews[0].hidden = (frzselecting || !pauseEmulation);
|
|
CGFloat scaleFactor = MAX(self.window.backingScaleFactor, 1.0);
|
|
glScreenW = self.frame.size.width * scaleFactor;
|
|
glScreenH = self.frame.size.height * scaleFactor;
|
|
|
|
BOOL showMouse = !useMouse || !running || pauseEmulation;
|
|
CGAssociateMouseAndMouseCursorPosition(showMouse);
|
|
|
|
if (showMouse)
|
|
{
|
|
[NSCursor unhide];
|
|
}
|
|
else
|
|
{
|
|
CGRect frame = self.frame;
|
|
CGPoint point = CGPointMake(frame.size.width / 2.0, frame.size.height / 2.0);
|
|
point = [self convertPoint:point toView:nil];
|
|
point = [self.window convertPointToScreen:point];
|
|
point.y = self.window.screen.frame.size.height - point.y;
|
|
CGWarpMouseCursorPosition(point);
|
|
[NSCursor hide];
|
|
}
|
|
});
|
|
}
|
|
|
|
- (void)setFrame:(NSRect)frame
|
|
{
|
|
if ( !NSEqualRects(frame, self.frame) )
|
|
{
|
|
[super setFrame:frame];
|
|
}
|
|
}
|
|
|
|
- (BOOL)acceptsFirstResponder
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL)canBecomeKeyView
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
|
|
{
|
|
return !( running && !pauseEmulation);
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation S9xEngine
|
|
|
|
- (instancetype)init
|
|
{
|
|
if (self = [super init])
|
|
{
|
|
Initialize();
|
|
[self recreateS9xView];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
Deinitialize();
|
|
}
|
|
|
|
- (void)recreateS9xView
|
|
{
|
|
[s9xView removeFromSuperview];
|
|
S9xDeinitDisplay();
|
|
CGRect frame = NSMakeRect(0, 0, SNES_WIDTH * 2, SNES_HEIGHT * 2);
|
|
s9xView = [[S9xView alloc] initWithFrame:frame];
|
|
s9xView.translatesAutoresizingMaskIntoConstraints = NO;
|
|
s9xView.autoresizingMask = NSViewWidthSizable|NSViewHeightSizable;
|
|
[s9xView addConstraint:[NSLayoutConstraint constraintWithItem:s9xView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:s9xView attribute:NSLayoutAttributeWidth multiplier:(CGFloat)SNES_HEIGHT/(CGFloat)SNES_WIDTH constant:0.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.device = MTLCreateSystemDefaultDevice();
|
|
s9xView.emulationDelegate = self;
|
|
S9xInitDisplay(NULL, NULL);
|
|
}
|
|
|
|
- (void)start
|
|
{
|
|
#ifdef DEBUGGER
|
|
CPU.Flags |= DEBUG_MODE_FLAG;
|
|
S9xDoDebug();
|
|
#endif
|
|
|
|
lastFrame = GetMicroseconds();
|
|
frameCount = 0;
|
|
if (macFrameSkip < 0)
|
|
skipFrames = 3;
|
|
else
|
|
skipFrames = macFrameSkip;
|
|
|
|
S9xInitDisplay(NULL, NULL);
|
|
|
|
[NSThread detachNewThreadWithBlock:^
|
|
{
|
|
MacSnes9xThread(NULL);
|
|
}];
|
|
}
|
|
|
|
- (void)stop
|
|
{
|
|
SNES9X_Quit();
|
|
S9xExit();
|
|
}
|
|
|
|
- (void)softwareReset
|
|
{
|
|
SNES9X_SoftReset();
|
|
SNES9X_Go();
|
|
[self resume];
|
|
}
|
|
|
|
|
|
- (void)hardwareReset
|
|
{
|
|
SNES9X_Reset();
|
|
SNES9X_Go();
|
|
[self resume];
|
|
}
|
|
|
|
- (BOOL)isRunning
|
|
{
|
|
return running;
|
|
}
|
|
|
|
- (BOOL)isPaused
|
|
{
|
|
return running && pauseEmulation;
|
|
}
|
|
|
|
- (void)pause
|
|
{
|
|
pauseEmulation = true;
|
|
[self.emulationDelegate emulationPaused];
|
|
[s9xView updatePauseOverlay];
|
|
}
|
|
|
|
- (void)quit
|
|
{
|
|
SNES9X_Quit();
|
|
[self pause];
|
|
}
|
|
|
|
- (void)resume
|
|
{
|
|
pauseEmulation = false;
|
|
[self.emulationDelegate emulationResumed];
|
|
[s9xView updatePauseOverlay];
|
|
}
|
|
|
|
- (NSArray<S9xJoypad *> *)listJoypads
|
|
{
|
|
pthread_mutex_lock(&keyLock);
|
|
NSMutableArray<S9xJoypad *> *joypads = [NSMutableArray new];
|
|
for (auto joypadStruct : ListJoypads())
|
|
{
|
|
S9xJoypad *joypad = [S9xJoypad new];
|
|
joypad.vendorID = joypadStruct.vendorID;
|
|
joypad.productID = joypadStruct.productID;
|
|
joypad.index = joypadStruct.index;
|
|
joypad.name = [[NSString alloc] initWithUTF8String:NameForDevice(joypadStruct).c_str()];
|
|
|
|
[joypads addObject:joypad];
|
|
}
|
|
|
|
[joypads sortUsingComparator:^NSComparisonResult(S9xJoypad *a, S9xJoypad *b)
|
|
{
|
|
NSComparisonResult result = [a.name compare:b.name];
|
|
|
|
if ( result == NSOrderedSame )
|
|
{
|
|
result = [@(a.vendorID) compare:@(b.vendorID)];
|
|
}
|
|
|
|
if ( result == NSOrderedSame )
|
|
{
|
|
result = [@(a.productID) compare:@(b.productID)];
|
|
}
|
|
|
|
if ( result == NSOrderedSame )
|
|
{
|
|
result = [@(a.index) compare:@(b.index)];
|
|
}
|
|
|
|
return result;
|
|
}];
|
|
pthread_mutex_unlock(&keyLock);
|
|
|
|
return joypads;
|
|
}
|
|
|
|
- (void)setPlayer:(int8)player forVendorID:(uint32)vendorID productID:(uint32)productID index:(uint32)index oldPlayer:(int8 *)oldPlayer
|
|
{
|
|
pthread_mutex_lock(&keyLock);
|
|
SetPlayerForJoypad(player, vendorID, productID, index, oldPlayer);
|
|
pthread_mutex_unlock(&keyLock);
|
|
}
|
|
|
|
- (BOOL)setButton:(S9xButtonCode)button forVendorID:(uint32)vendorID productID:(uint32)productID index:(uint32)index cookie:(uint32)cookie value:(int32)value oldButton:(S9xButtonCode *)oldButton
|
|
{
|
|
BOOL result = NO;
|
|
pthread_mutex_lock(&keyLock);
|
|
result = SetButtonCodeForJoypadControl(vendorID, productID, index, cookie, value, button, true, oldButton);
|
|
pthread_mutex_unlock(&keyLock);
|
|
return result;
|
|
}
|
|
|
|
- (void)clearJoypadForVendorID:(uint32)vendorID productID:(uint32)productID index:(uint32)index
|
|
{
|
|
pthread_mutex_lock(&keyLock);
|
|
ClearJoypad(vendorID, productID, index);
|
|
pthread_mutex_unlock(&keyLock);
|
|
}
|
|
|
|
- (void)clearJoypadForVendorID:(uint32)vendorID productID:(uint32)productID index:(uint32)index buttonCode:(S9xButtonCode)buttonCode
|
|
{
|
|
pthread_mutex_lock(&keyLock);
|
|
ClearButtonCodeForJoypad(vendorID, productID, index, buttonCode);
|
|
pthread_mutex_unlock(&keyLock);
|
|
}
|
|
|
|
- (NSArray<S9xJoypadInput *> *)getInputsForVendorID:(uint32)vendorID productID:(uint32)productID index:(uint32)index
|
|
{
|
|
pthread_mutex_lock(&keyLock);
|
|
NSMutableArray<S9xJoypadInput *> *inputs = [NSMutableArray new];
|
|
std::unordered_map<struct JoypadInput, S9xButtonCode> buttonCodeMap = GetJuypadButtons(vendorID, productID, index);
|
|
for (auto it = buttonCodeMap.begin(); it != buttonCodeMap.end(); ++it)
|
|
{
|
|
S9xJoypadInput *input = [S9xJoypadInput new];
|
|
input.cookie = it->first.cookie.cookie;
|
|
input.value = it->first.value;
|
|
input.buttonCode = it->second;
|
|
|
|
[inputs addObject:input];
|
|
}
|
|
pthread_mutex_unlock(&keyLock);
|
|
|
|
return inputs;
|
|
}
|
|
|
|
- (NSString *)labelForVendorID:(uint32)vendorID productID:(uint32)productID cookie:(uint32)cookie value:(int32)value
|
|
{
|
|
return [NSString stringWithUTF8String:LabelForInput(vendorID, productID, cookie, value).c_str()];
|
|
}
|
|
|
|
- (BOOL)setButton:(S9xButtonCode)button forKey:(int16)key player:(int8)player oldButton:(S9xButtonCode *)oldButton oldPlayer:(int8 *)oldPlayer oldKey:(int16 *)oldKey
|
|
{
|
|
BOOL result = NO;
|
|
pthread_mutex_lock(&keyLock);
|
|
result = SetKeyCode(key, button, player, oldKey, oldButton, oldPlayer);
|
|
pthread_mutex_unlock(&keyLock);
|
|
return result;
|
|
}
|
|
|
|
- (void)clearButton:(S9xButtonCode)button forPlayer:(int8)player
|
|
{
|
|
pthread_mutex_lock(&keyLock);
|
|
ClearKeyCode(button, player);
|
|
pthread_mutex_unlock(&keyLock);
|
|
}
|
|
|
|
- (BOOL)loadROM:(NSURL *)fileURL
|
|
{
|
|
running = false;
|
|
frzselecting = false;
|
|
|
|
while (!Settings.StopEmulation)
|
|
{
|
|
usleep(Settings.FrameTime);
|
|
}
|
|
|
|
if ( SNES9X_OpenCart(fileURL) )
|
|
{
|
|
[self.emulationDelegate gameLoaded];
|
|
|
|
SNES9X_Go();
|
|
s9xView.window.title = fileURL.lastPathComponent.stringByDeletingPathExtension;
|
|
[s9xView.window makeKeyAndOrderFront:nil];
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^
|
|
{
|
|
[s9xView.window makeFirstResponder:s9xView];
|
|
});
|
|
|
|
[self start];
|
|
return YES;
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (BOOL)loadMultiple:(NSArray<NSURL *> *)fileURLs
|
|
{
|
|
if (fileURLs.count == 0)
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
running = false;
|
|
frzselecting = false;
|
|
|
|
while (!Settings.StopEmulation)
|
|
{
|
|
usleep(Settings.FrameTime);
|
|
}
|
|
|
|
if (SNES9X_OpenMultiCart(fileURLs.firstObject, fileURLs.lastObject))
|
|
{
|
|
[self.emulationDelegate gameLoaded];
|
|
|
|
SNES9X_Go();
|
|
s9xView.window.title = fileURLs.firstObject.lastPathComponent.stringByDeletingPathExtension;
|
|
[s9xView.window makeKeyAndOrderFront:nil];
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^
|
|
{
|
|
[s9xView.window makeFirstResponder:s9xView];
|
|
});
|
|
|
|
[self start];
|
|
return YES;
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (void)setShowFPS:(BOOL)showFPS
|
|
{
|
|
Settings.DisplayFrameRate = showFPS;
|
|
}
|
|
|
|
- (void)setVideoMode:(int)mode
|
|
{
|
|
videoMode = mode;
|
|
}
|
|
|
|
- (void)setMacFrameSkip:(int)_macFrameSkip
|
|
{
|
|
macFrameSkip = _macFrameSkip;
|
|
|
|
// contrains to -1 to 200
|
|
if (macFrameSkip < -1)
|
|
macFrameSkip = -1;
|
|
if (macFrameSkip > 200)
|
|
macFrameSkip = 200;
|
|
}
|
|
|
|
- (void)setDeviceSetting:(S9xDeviceSetting)_deviceSetting
|
|
{
|
|
deviceSetting = _deviceSetting;
|
|
ChangeInputDevice();
|
|
}
|
|
|
|
- (void)setSuperFXClockSpeedPercent:(uint32_t)clockSpeed
|
|
{
|
|
Settings.SuperFXClockMultiplier = clockSpeed;
|
|
}
|
|
|
|
- (void)setSoundInterpolationType:(int)type
|
|
{
|
|
Settings.InterpolationMethod = type;
|
|
}
|
|
|
|
- (void)setCPUOverclockMode:(int)mode
|
|
{
|
|
Settings.OverclockMode = mode;
|
|
}
|
|
|
|
- (void)setApplySpecificGameHacks:(BOOL)flag
|
|
{
|
|
Settings.DisableGameSpecificHacks = !flag;
|
|
}
|
|
|
|
- (void)setAllowInvalidVRAMAccess:(BOOL)flag
|
|
{
|
|
Settings.BlockInvalidVRAMAccessMaster = !flag;
|
|
}
|
|
|
|
- (void)setSeparateEchoBufferFromRAM:(BOOL)flag
|
|
{
|
|
Settings.SeparateEchoBuffer = false;
|
|
}
|
|
|
|
- (void)setDisableSpriteLimit:(BOOL)flag
|
|
{
|
|
if ( flag )
|
|
{
|
|
Settings.MaxSpriteTilesPerLine = 128;
|
|
}
|
|
else
|
|
{
|
|
Settings.MaxSpriteTilesPerLine = 34;
|
|
}
|
|
}
|
|
|
|
@dynamic inputDelegate;
|
|
- (void)setInputDelegate:(id<S9xInputDelegate>)delegate
|
|
{
|
|
inputDelegate = delegate;
|
|
}
|
|
|
|
- (id<S9xInputDelegate>)inputDelegate
|
|
{
|
|
return inputDelegate;
|
|
}
|
|
|
|
@dynamic cheatsEnabled;
|
|
- (BOOL)cheatsEnabled
|
|
{
|
|
return Cheat.enabled;
|
|
}
|
|
|
|
- (void)setCheatsEnabled:(BOOL)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
|
|
|
|
@implementation S9xJoypad
|
|
|
|
- (BOOL)isEqual:(id)object
|
|
{
|
|
if (![object isKindOfClass:[self class]])
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
S9xJoypad *other = (S9xJoypad *)object;
|
|
return (self.vendorID == other.vendorID && self.productID == other.productID && self.index == other.index);
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation S9xJoypadInput
|
|
@end
|
|
|
|
@implementation S9xWatchPoint
|
|
@end
|