1/*********************************************************************************** 2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. 3 4 (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), 5 Jerremy Koot (jkoot@snes9x.com) 6 7 (c) Copyright 2002 - 2004 Matthew Kendora 8 9 (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) 10 11 (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) 12 13 (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) 14 15 (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), 16 Kris Bleakley (codeviolation@hotmail.com) 17 18 (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), 19 Nach (n-a-c-h@users.sourceforge.net), 20 21 (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) 22 23 (c) Copyright 2006 - 2007 nitsuja 24 25 (c) Copyright 2009 - 2016 BearOso, 26 OV2 27 28 29 BS-X C emulator code 30 (c) Copyright 2005 - 2006 Dreamer Nom, 31 zones 32 33 C4 x86 assembler and some C emulation code 34 (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), 35 Nach, 36 zsKnight (zsknight@zsnes.com) 37 38 C4 C++ code 39 (c) Copyright 2003 - 2006 Brad Jorsch, 40 Nach 41 42 DSP-1 emulator code 43 (c) Copyright 1998 - 2006 _Demo_, 44 Andreas Naive (andreasnaive@gmail.com), 45 Gary Henderson, 46 Ivar (ivar@snes9x.com), 47 John Weidman, 48 Kris Bleakley, 49 Matthew Kendora, 50 Nach, 51 neviksti (neviksti@hotmail.com) 52 53 DSP-2 emulator code 54 (c) Copyright 2003 John Weidman, 55 Kris Bleakley, 56 Lord Nightmare (lord_nightmare@users.sourceforge.net), 57 Matthew Kendora, 58 neviksti 59 60 DSP-3 emulator code 61 (c) Copyright 2003 - 2006 John Weidman, 62 Kris Bleakley, 63 Lancer, 64 z80 gaiden 65 66 DSP-4 emulator code 67 (c) Copyright 2004 - 2006 Dreamer Nom, 68 John Weidman, 69 Kris Bleakley, 70 Nach, 71 z80 gaiden 72 73 OBC1 emulator code 74 (c) Copyright 2001 - 2004 zsKnight, 75 pagefault (pagefault@zsnes.com), 76 Kris Bleakley 77 Ported from x86 assembler to C by sanmaiwashi 78 79 SPC7110 and RTC C++ emulator code used in 1.39-1.51 80 (c) Copyright 2002 Matthew Kendora with research by 81 zsKnight, 82 John Weidman, 83 Dark Force 84 85 SPC7110 and RTC C++ emulator code used in 1.52+ 86 (c) Copyright 2009 byuu, 87 neviksti 88 89 S-DD1 C emulator code 90 (c) Copyright 2003 Brad Jorsch with research by 91 Andreas Naive, 92 John Weidman 93 94 S-RTC C emulator code 95 (c) Copyright 2001 - 2006 byuu, 96 John Weidman 97 98 ST010 C++ emulator code 99 (c) Copyright 2003 Feather, 100 John Weidman, 101 Kris Bleakley, 102 Matthew Kendora 103 104 Super FX x86 assembler emulator code 105 (c) Copyright 1998 - 2003 _Demo_, 106 pagefault, 107 zsKnight 108 109 Super FX C emulator code 110 (c) Copyright 1997 - 1999 Ivar, 111 Gary Henderson, 112 John Weidman 113 114 Sound emulator code used in 1.5-1.51 115 (c) Copyright 1998 - 2003 Brad Martin 116 (c) Copyright 1998 - 2006 Charles Bilyue' 117 118 Sound emulator code used in 1.52+ 119 (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) 120 121 S-SMP emulator code used in 1.54+ 122 (c) Copyright 2016 byuu 123 124 SH assembler code partly based on x86 assembler code 125 (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 126 127 2xSaI filter 128 (c) Copyright 1999 - 2001 Derek Liauw Kie Fa 129 130 HQ2x, HQ3x, HQ4x filters 131 (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) 132 133 NTSC filter 134 (c) Copyright 2006 - 2007 Shay Green 135 136 GTK+ GUI code 137 (c) Copyright 2004 - 2016 BearOso 138 139 Win32 GUI code 140 (c) Copyright 2003 - 2006 blip, 141 funkyass, 142 Matthew Kendora, 143 Nach, 144 nitsuja 145 (c) Copyright 2009 - 2016 OV2 146 147 Mac OS GUI code 148 (c) Copyright 1998 - 2001 John Stiles 149 (c) Copyright 2001 - 2011 zones 150 151 152 Specific ports contains the works of other authors. See headers in 153 individual files. 154 155 156 Snes9x homepage: http://www.snes9x.com/ 157 158 Permission to use, copy, modify and/or distribute Snes9x in both binary 159 and source form, for non-commercial purposes, is hereby granted without 160 fee, providing that this license information and copyright notice appear 161 with all copies and any derived work. 162 163 This software is provided 'as-is', without any express or implied 164 warranty. In no event shall the authors be held liable for any damages 165 arising from the use of this software or it's derivatives. 166 167 Snes9x is freeware for PERSONAL USE only. Commercial users should 168 seek permission of the copyright holders first. Commercial use includes, 169 but is not limited to, charging money for Snes9x or software derived from 170 Snes9x, including Snes9x or derivatives in commercial game bundles, and/or 171 using Snes9x as a promotion for your commercial product. 172 173 The copyright holders request that bug fixes and improvements to the code 174 should be forwarded to them so everyone can benefit from the modifications 175 in future versions. 176 177 Super NES and Super Nintendo Entertainment System are trademarks of 178 Nintendo Co., Limited and its subsidiary companies. 179 ***********************************************************************************/ 180 181/*********************************************************************************** 182 SNES9X for Mac OS (c) Copyright John Stiles 183 184 Snes9x for Mac OS X 185 186 (c) Copyright 2001 - 2011 zones 187 (c) Copyright 2002 - 2005 107 188 (c) Copyright 2002 PB1400c 189 (c) Copyright 2004 Alexander and Sander 190 (c) Copyright 2004 - 2005 Steven Seeger 191 (c) Copyright 2005 Ryan Vogt 192 ***********************************************************************************/ 193 194 195#import "snes9x.h" 196#import "memmap.h" 197#import "apu.h" 198#import "controls.h" 199#import "crosshairs.h" 200#import "cheats.h" 201#import "movie.h" 202#import "snapshot.h" 203#import "display.h" 204#import "blit.h" 205 206#ifdef DEBUGGER 207#import "debug.h" 208#endif 209 210#import <Cocoa/Cocoa.h> 211#import <QuickTime/QuickTime.h> 212#import <pthread.h> 213 214#import "mac-prefix.h" 215#import "mac-appleevent.h" 216#import "mac-audio.h" 217#import "mac-cheat.h" 218#import "mac-cheatfinder.h" 219#import "mac-client.h" 220#import "mac-cocoatools.h" 221#import "mac-controls.h" 222#import "mac-coreimage.h" 223#import "mac-dialog.h" 224#import "mac-file.h" 225#import "mac-gworld.h" 226#import "mac-joypad.h" 227#import "mac-keyboard.h" 228#import "mac-multicart.h" 229#import "mac-musicbox.h" 230#import "mac-netplay.h" 231#import "mac-prefs.h" 232#import "mac-quicktime.h" 233#import "mac-render.h" 234#import "mac-screenshot.h" 235#import "mac-server.h" 236#import "mac-snes9x.h" 237#import "mac-stringtools.h" 238#import "mac-os.h" 239 240#define kRecentMenu_MAX 20 241#define KeyIsPressed(km, k) (1 & (((unsigned char *) km) [(k) >> 3] >> ((k) & 7))) 242 243volatile bool8 running = false; 244volatile bool8 s9xthreadrunning = false; 245 246volatile bool8 eventQueued = false; 247 248volatile int windowResizeCount = 1; 249volatile bool8 windowExtend = true; 250 251SInt32 systemVersion; 252 253uint32 controlPad[MAC_MAX_PLAYERS]; 254 255uint8 romDetect = 0, 256 interleaveDetect = 0, 257 videoDetect = 0, 258 headerDetect = 0; 259 260WindowRef gWindow = NULL; 261HIRect gWindowRect; 262int glScreenW, 263 glScreenH; 264CGRect glScreenBounds; 265Point windowPos[kWindowCount]; 266CGSize windowSize[kWindowCount]; 267 268CGImageRef macIconImage[118]; 269int macPadIconIndex, 270 macLegendIconIndex, 271 macMusicBoxIconIndex, 272 macFunctionIconIndex; 273 274int macFrameSkip = -1; 275int32 skipFrames = 3; 276int64 lastFrame = 0; 277 278int macFastForwardRate = 5, 279 macFrameAdvanceRate = 1000000; 280 281unsigned long spcFileCount = 0, 282 pngFileCount = 0; 283 284bool8 finished = false, 285 cartOpen = false, 286 autofire = false, 287 hidExist = true, 288 directDisplay = false; 289 290bool8 fullscreen = false, 291 autoRes = false, 292 glstretch = true, 293 gl32bit = true, 294 vsync = true, 295 drawoverscan = false, 296 screencurvature = false, 297 multiprocessor = false, 298 ciFilterEnable = false; 299long drawingMethod = kDrawingOpenGL; 300int videoMode = VIDEOMODE_SMOOTH; 301 302SInt32 macSoundVolume = 80; // % 303uint32 macSoundBuffer_ms = 100; // ms 304uint32 macSoundInterval_ms = 16; // ms 305bool8 macSoundLagEnable = false; 306uint16 aueffect = 0; 307 308uint8 saveInROMFolder = 2; // 0 : Snes9x 1 : ROM 2 : Application Support 309CFStringRef saveFolderPath; 310 311int macCurvatureWarp = 15, 312 macAspectRatio = 0; 313 314bool8 startopendlog = false, 315 showtimeinfrz = true, 316 enabletoggle = true, 317 savewindowpos = false, 318 onscreeninfo = true; 319int inactiveMode = 2; 320int musicboxmode = kMBXSoundEmulation; 321 322bool8 applycheat = false; 323int padSetting = 1, 324 deviceSetting = 1, 325 deviceSettingMaster = 1; 326int macControllerOption = SNES_JOYPAD; 327AutoFireState autofireRec[MAC_MAX_PLAYERS]; 328 329bool8 macQTRecord = false; 330uint16 macQTMovFlag = 0; 331 332uint16 macRecordFlag = 0x3, 333 macPlayFlag = 0x1; 334wchar_t macRecordWChar[MOVIE_MAX_METADATA]; 335 336char npServerIP[256], 337 npName[256]; 338 339bool8 lastoverscan = false; 340 341CGPoint unlimitedCursor; 342 343ExtraOption extraOptions; 344 345CFStringRef multiCartPath[2]; 346 347#ifdef MAC_PANTHER_SUPPORT 348IconRef macIconRef[118]; 349#endif 350 351enum 352{ 353 mApple = 128, 354 iAbout = 1, 355 356 mFile = 129, 357 iOpen = 1, 358 iOpenMulti = 2, 359 iOpenRecent = 3, 360 iClose = 5, 361 iRomInfo = 7, 362 363 mControl = 134, 364 iKeyboardLayout = 1, 365 iISpLayout = 2, 366 iAutoFire = 4, 367 iISpPreset = 6, 368 369 mEdit = 130, 370 371 mEmulation = 131, 372 iResume = 1, 373 iSoftReset = 3, 374 iReset = 4, 375 iDevice = 6, 376 377 mCheat = 132, 378 iApplyCheats = 1, 379 iGameGenie = 3, 380 iCheatFinder = 4, 381 382 mOption = 133, 383 iFreeze = 1, 384 iDefrost = 2, 385 iFreezeTo = 4, 386 iDefrostFrom = 5, 387 iRecordMovie = 7, 388 iPlayMovie = 8, 389 iQTMovie = 10, 390 iSaveSPC = 12, 391 iSaveSRAM = 13, 392 iCIFilter = 15, 393 iMusicBox = 17, 394 395 mNetplay = 135, 396 iServer = 1, 397 iClient = 2, 398 399 mPresets = 201, 400 401 mDevice = 202, 402 iPad = 1, 403 iMouse = 2, 404 iMouse2 = 3, 405 iSuperScope = 4, 406 iMultiPlayer5 = 5, 407 iMultiPlayer5_2 = 6, 408 iJustifier1 = 7, 409 iJustifier2 = 8, 410 411 mRecentItem = 203 412}; 413 414enum 415{ 416 kmF1Key = 0x7A, 417 kmF2Key = 0x78, 418 kmF3Key = 0x63, 419 kmF4Key = 0x76, 420 kmF5Key = 0x60, 421 kmF6Key = 0x61, 422 km0Key = 0x1D, 423 km1Key = 0x12, 424 km2Key = 0x13, 425 km3Key = 0x14, 426 km4Key = 0x15, 427 km5Key = 0x17, 428 km6Key = 0x16, 429 km7Key = 0x1A, 430 km8Key = 0x1C, 431 km9Key = 0x19, 432 kmAKey = 0x00, 433 kmBKey = 0x0B, 434 kmCKey = 0x08, 435 kmEscKey = 0x35, 436 kmCtrKey = 0x3B, 437 kmMinusKey = 0x1B, 438 kmQKey = 0x0C, 439 kmWKey = 0x0D, 440 kmOKey = 0x1F, 441 kmPKey = 0x23 442}; 443 444struct ButtonCommand 445{ 446 char command[16]; 447 uint8 keycode; 448 bool8 held; 449}; 450 451struct GameViewInfo 452{ 453 int globalLeft; 454 int globalTop; 455 int width; 456 int height; 457}; 458 459static volatile bool8 rejectinput = false; 460 461static bool8 pauseEmulation = false, 462 frameAdvance = false; 463 464static pthread_t s9xthread; 465 466static MenuRef recentMenu; 467static CFStringRef recentItem[kRecentMenu_MAX + 1]; 468 469static EventHandlerUPP gameWindowUPP, 470 gameWUPaneUPP; 471static EventHandlerRef gameWindowEventRef, 472 gameWUPaneEventRef; 473 474static int windowZoomCount = 0; 475 476static int frameCount = 0; 477 478static bool8 frzselecting = false; 479 480static uint16 changeAuto[2] = { 0x0000, 0x0000 }; 481 482static GameViewInfo scopeViewInfo; 483 484static ButtonCommand btncmd[] = 485{ 486 { "ToggleBG0", kmF1Key, false }, 487 { "ToggleBG1", kmF2Key, false }, 488 { "ToggleBG2", kmF3Key, false }, 489 { "ToggleBG3", kmF4Key, false }, 490 { "ToggleSprites", kmF5Key, false }, 491 { "SwapJoypads", kmF6Key, false }, 492 { "SoundChannel0", km1Key, false }, 493 { "SoundChannel1", km2Key, false }, 494 { "SoundChannel2", km3Key, false }, 495 { "SoundChannel3", km4Key, false }, 496 { "SoundChannel4", km5Key, false }, 497 { "SoundChannel5", km6Key, false }, 498 { "SoundChannel6", km7Key, false }, 499 { "SoundChannel7", km8Key, false }, 500 { "SoundChannelsOn", km9Key, false }, 501 { "_mac1", km0Key, false }, 502 { "_mac2", kmMinusKey, false }, 503 { "_mac3", kmQKey, false }, 504 { "_mac4", kmWKey, false }, 505 { "_mac5", kmOKey, false }, 506 { "_mac6", kmPKey, false } 507}; 508 509#define kCommandListSize (sizeof(btncmd) / sizeof(btncmd[0])) 510 511static void Initialize (void); 512static void Deinitialize (void); 513static void InitAutofire (void); 514static void InitRecentItems (void); 515static void DeinitRecentItems (void); 516static void ClearRecentItems (void); 517static void InitRecentMenu (void); 518static void DeinitRecentMenu (void); 519static void ProcessInput (void); 520static void ResizeGameWindow (void); 521static void ChangeAutofireSettings (int, int); 522static void ChangeTurboRate (int); 523static void ForceChangingKeyScript (void); 524static void CFTimerCallback (CFRunLoopTimerRef, void *); 525static void UpdateFreezeDefrostScreen (int, CGImageRef, uint8 *, CGContextRef); 526static void * MacSnes9xThread (void *); 527static OSStatus HandleMenuChoice (UInt32, Boolean *); 528static inline void EmulationLoop (void); 529static pascal OSStatus MainEventHandler (EventHandlerCallRef, EventRef, void *); 530static pascal OSStatus SubEventHandler (EventHandlerCallRef, EventRef, void *); 531static pascal OSStatus GameWindowEventHandler (EventHandlerCallRef, EventRef, void *); 532static pascal OSStatus GameWindowUserPaneEventHandler (EventHandlerCallRef, EventRef, void *); 533 534 535int main (int argc, char **argv) 536{ 537#ifdef MAC_PANTHER_SUPPORT 538 NSAutoreleasePool *pool; 539#endif 540 OSStatus err; 541 EventHandlerRef eref; 542 EventHandlerUPP eUPP; 543 EventTypeSpec mEvents[] = { { kEventClassCommand, kEventCommandProcess }, 544 { kEventClassCommand, kEventCommandUpdateStatus } }, 545 sEvents[] = { { kEventClassCommand, kEventCommandProcess }, 546 { kEventClassCommand, kEventCommandUpdateStatus }, 547 { kEventClassMouse, kEventMouseUp }, 548 { kEventClassMouse, kEventMouseMoved }, 549 { kEventClassMouse, kEventMouseDragged } }; 550 551#ifdef MAC_PANTHER_SUPPORT 552 pool = [[NSAutoreleasePool alloc] init]; 553#endif 554 eUPP = NewEventHandlerUPP(MainEventHandler); 555 err = InstallApplicationEventHandler(eUPP, GetEventTypeCount(mEvents), mEvents, NULL, &eref); 556 557 Initialize(); 558 559 while (!finished) 560 { 561 if (cartOpen && running) 562 { 563 #ifdef DEBUGGER 564 CPU.Flags |= DEBUG_MODE_FLAG; 565 S9xDoDebug(); 566 #endif 567 568 eventQueued = false; 569 570 Microseconds((UnsignedWide *) &lastFrame); 571 frameCount = 0; 572 if (macFrameSkip < 0) 573 skipFrames = 3; 574 else 575 skipFrames = macFrameSkip; 576 577 err = RemoveEventHandler(eref); 578 DisposeEventHandlerUPP(eUPP); 579 #ifdef MAC_PANTHER_SUPPORT 580 [pool release]; 581 582 pool = [[NSAutoreleasePool alloc] init]; 583 #endif 584 eUPP = NewEventHandlerUPP(SubEventHandler); 585 err = InstallApplicationEventHandler(eUPP, GetEventTypeCount(sEvents), sEvents, NULL, &eref); 586 587 S9xInitDisplay(NULL, NULL); 588 ClearGFXScreen(); 589 590 if (!fullscreen) 591 ForceChangingKeyScript(); 592 593 pthread_create(&s9xthread, NULL, MacSnes9xThread, NULL); 594 595 CFRunLoopTimerRef cftimer = NULL; 596 CFRunLoopTimerContext cftimerctx = { 0, NULL, NULL, NULL, NULL }; 597 598 if (!fullscreen) 599 { 600 cftimer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent(), 30, 0, 0, CFTimerCallback, &cftimerctx); 601 if (cftimer) 602 CFRunLoopAddTimer(CFRunLoopGetCurrent(), cftimer, kCFRunLoopCommonModes); 603 } 604 605 AdjustMenus(); 606 607 RunApplicationEventLoop(); 608 609 if (!fullscreen) 610 { 611 if (cftimer) 612 { 613 CFRunLoopTimerInvalidate(cftimer); 614 CFRelease(cftimer); 615 cftimer = NULL; 616 } 617 } 618 619 pthread_join(s9xthread, NULL); 620 621 if (!Settings.NetPlay || Settings.NetPlayServer) 622 { 623 SNES9X_SaveSRAM(); 624 S9xResetSaveTimer(false); 625 S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR)); 626 } 627 628 S9xDeinitDisplay(); 629 630 if (Settings.NetPlay) 631 { 632 if (!Settings.NetPlayServer) 633 { 634 DeinitGameWindow(); 635 cartOpen = false; 636 } 637 638 Settings.NetPlay = false; 639 Settings.NetPlayServer = false; 640 } 641 642 err = RemoveEventHandler(eref); 643 DisposeEventHandlerUPP(eUPP); 644 #ifdef MAC_PANTHER_SUPPORT 645 [pool release]; 646 647 pool = [[NSAutoreleasePool alloc] init]; 648 #endif 649 eUPP = NewEventHandlerUPP(MainEventHandler); 650 err = InstallApplicationEventHandler(eUPP, GetEventTypeCount(mEvents), mEvents, NULL, &eref); 651 } 652 653 if (!finished) 654 { 655 AdjustMenus(); 656 RunApplicationEventLoop(); 657 } 658 } 659 660 Deinitialize(); 661 662 err = RemoveEventHandler(eref); 663 DisposeEventHandlerUPP(eUPP); 664#ifdef MAC_PANTHER_SUPPORT 665 [pool release]; 666#endif 667 668 return (0); 669} 670 671static void CFTimerCallback (CFRunLoopTimerRef timer, void *info) 672{ 673 OSStatus err; 674 675 err = UpdateSystemActivity(OverallAct); 676} 677 678static void * MacSnes9xThread (void *) 679{ 680 Settings.StopEmulation = false; 681 s9xthreadrunning = true; 682 683 EmulationLoop(); 684 685 s9xthreadrunning = false; 686 Settings.StopEmulation = true; 687 688 return (NULL); 689} 690 691static inline void EmulationLoop (void) 692{ 693 bool8 olddisplayframerate = false; 694 int storedMacFrameSkip = macFrameSkip; 695 696 pauseEmulation = false; 697 frameAdvance = false; 698 699 if (macQTRecord) 700 { 701 olddisplayframerate = Settings.DisplayFrameRate; 702 Settings.DisplayFrameRate = false; 703 } 704 705 MacStartSound(); 706 707 if (Settings.NetPlay) 708 { 709 if (Settings.NetPlayServer) 710 { 711 NPServerDetachNetPlayThread(); 712 NPServerStartClients(); 713 714 while (running) 715 { 716 NPServerProcessInput(); 717 S9xMainLoop(); 718 } 719 720 NPServerStopNetPlayThread(); 721 NPServerStopServer(); 722 } 723 else 724 { 725 NPClientDetachNetPlayThread(); 726 NPClientNetPlayWaitStart(); 727 728 while (running) 729 { 730 NPClientProcessInput(); 731 S9xMainLoop(); 732 } 733 734 NPClientStopNetPlayThread(); 735 NPClientDisconnect(); 736 737 NPClientRestoreConfig(); 738 } 739 } 740 else 741 { 742 while (running) 743 { 744 ProcessInput(); 745 746 if (!pauseEmulation) 747 S9xMainLoop(); 748 else 749 { 750 if (frameAdvance) 751 { 752 macFrameSkip = 1; 753 skipFrames = 1; 754 frameAdvance = false; 755 S9xMainLoop(); 756 macFrameSkip = storedMacFrameSkip; 757 } 758 759 usleep(Settings.FrameTime); 760 } 761 } 762 } 763 764 MacStopSound(); 765 766 if (macQTRecord) 767 { 768 MacQTStopRecording(); 769 macQTRecord = false; 770 771 Settings.DisplayFrameRate = olddisplayframerate; 772 } 773 774 S9xMovieShutdown(); 775} 776 777static pascal OSStatus MainEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData) 778{ 779 OSStatus err, result = eventNotHandledErr; 780 Boolean done = false; 781 782 if (frzselecting) 783 return (result); 784 785 switch (GetEventClass(inEvent)) 786 { 787 case kEventClassCommand: 788 switch (GetEventKind(inEvent)) 789 { 790 HICommand cmd; 791 792 case kEventCommandUpdateStatus: 793 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &cmd); 794 if (err == noErr && cmd.commandID == 'clos') 795 { 796 UpdateMenuCommandStatus(false); 797 result = noErr; 798 } 799 800 break; 801 802 case kEventCommandProcess: 803 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &cmd); 804 if (err == noErr) 805 { 806 UInt32 modifierkey; 807 808 err = GetEventParameter(inEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifierkey); 809 if (err == noErr) 810 { 811 if ((cmd.commandID == 'pref') && (modifierkey & optionKey)) 812 cmd.commandID = 'EXTR'; 813 814 result = HandleMenuChoice(cmd.commandID, &done); 815 816 if (done) 817 QuitApplicationEventLoop(); 818 } 819 } 820 821 break; 822 } 823 824 break; 825 } 826 827 return (result); 828} 829 830static pascal OSStatus SubEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData) 831{ 832 OSStatus err, result = eventNotHandledErr; 833 834 if (frzselecting) 835 return (result); 836 837 switch (GetEventClass(inEvent)) 838 { 839 case kEventClassCommand: 840 switch (GetEventKind(inEvent)) 841 { 842 HICommand cmd; 843 844 case kEventCommandUpdateStatus: 845 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &cmd); 846 if (err == noErr && cmd.commandID == 'clos') 847 { 848 UpdateMenuCommandStatus(false); 849 result = noErr; 850 } 851 852 break; 853 854 case kEventCommandProcess: 855 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &cmd); 856 if (err == noErr) 857 { 858 switch (cmd.commandID) 859 { 860 case 'Erun': // Pause 861 case 'SubQ': // Queue from emulation thread 862 running = false; 863 while (s9xthreadrunning) 864 sleep(0); 865 QuitApplicationEventLoop(); 866 result = noErr; 867 break; 868 869 case 'Ocif': // Core Image Filter 870 HiliteMenu(0); 871 ConfigureCoreImageFilter(); 872 result = noErr; 873 break; 874 } 875 } 876 877 break; 878 } 879 880 break; 881 882 case kEventClassMouse: 883 if (fullscreen) 884 { 885 if ((macControllerOption == SNES_JOYPAD) || (macControllerOption == SNES_MULTIPLAYER5) || (macControllerOption == SNES_MULTIPLAYER5_2)) 886 { 887 if (!(Settings.NetPlay && !Settings.NetPlayServer)) 888 { 889 switch (GetEventKind(inEvent)) 890 { 891 case kEventMouseUp: 892 HIPoint hipt; 893 894 err = GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(HIPoint), NULL, &hipt); 895 if (err == noErr) 896 { 897 if (CGRectContainsPoint(glScreenBounds, hipt)) 898 { 899 running = false; 900 while (s9xthreadrunning) 901 sleep(0); 902 QuitApplicationEventLoop(); 903 result = noErr; 904 } 905 } 906 907 break; 908 } 909 } 910 } 911 else 912 if ((macControllerOption == SNES_MOUSE) || (macControllerOption == SNES_MOUSE_SWAPPED)) 913 { 914 switch (GetEventKind(inEvent)) 915 { 916 case kEventMouseMoved: 917 case kEventMouseDragged: 918 HIPoint hipt; 919 920 err = GetEventParameter(inEvent, kEventParamMouseDelta, typeHIPoint, NULL, sizeof(HIPoint), NULL, &hipt); 921 if (err == noErr) 922 { 923 unlimitedCursor.x += hipt.x; 924 unlimitedCursor.y += hipt.y; 925 } 926 927 break; 928 } 929 } 930 } 931 932 break; 933 } 934 935 return (result); 936} 937 938void PostQueueToSubEventLoop (void) 939{ 940 OSStatus err; 941 EventRef event; 942 943 err = CreateEvent(kCFAllocatorDefault, kEventClassCommand, kEventCommandProcess, 0, kEventAttributeUserEvent, &event); 944 if (err == noErr) 945 { 946 HICommand cmd; 947 948 cmd.commandID = 'SubQ'; 949 cmd.attributes = kEventAttributeUserEvent; 950 cmd.menu.menuRef = NULL; 951 cmd.menu.menuItemIndex = 0; 952 953 err = SetEventParameter(event, kEventParamDirectObject, typeHICommand, sizeof(HICommand), &cmd); 954 if (err == noErr) 955 err = PostEventToQueue(GetMainEventQueue(), event, kEventPriorityStandard); 956 957 ReleaseEvent(event); 958 } 959} 960 961void InitGameWindow (void) 962{ 963 OSStatus err; 964 IBNibRef nibRef; 965 WindowAttributes attr; 966 CFStringRef ref; 967 HIViewRef ctl; 968 HIViewID cid = { 'Pict', 0 }; 969 Rect rct; 970 char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], fname[_MAX_FNAME + 1], ext[_MAX_EXT + 1]; 971 EventTypeSpec wupaneEvents[] = { { kEventClassControl, kEventControlClick }, 972 { kEventClassControl, kEventControlDraw } }, 973 windowEvents[] = { { kEventClassWindow, kEventWindowDeactivated }, 974 { kEventClassWindow, kEventWindowActivated }, 975 { kEventClassWindow, kEventWindowBoundsChanging }, 976 { kEventClassWindow, kEventWindowBoundsChanged }, 977 { kEventClassWindow, kEventWindowZoom }, 978 { kEventClassWindow, kEventWindowToolbarSwitchMode } }; 979 980 if (gWindow) 981 return; 982 983 err = CreateNibReference(kMacS9XCFString, &nibRef); 984 if (err) 985 QuitWithFatalError(err, "os 02"); 986 987 err = CreateWindowFromNib(nibRef, CFSTR("GameWindow"), &gWindow); 988 if (err) 989 QuitWithFatalError(err, "os 03"); 990 991 DisposeNibReference(nibRef); 992 993 HIViewFindByID(HIViewGetRoot(gWindow), cid, &ctl); 994 995 gameWindowUPP = NewEventHandlerUPP(GameWindowEventHandler); 996 err = InstallWindowEventHandler(gWindow, gameWindowUPP, GetEventTypeCount(windowEvents), windowEvents, (void *) gWindow, &gameWindowEventRef); 997 998 gameWUPaneUPP = NewEventHandlerUPP(GameWindowUserPaneEventHandler); 999 err = InstallControlEventHandler(ctl, gameWUPaneUPP, GetEventTypeCount(wupaneEvents), wupaneEvents, (void *) gWindow, &gameWUPaneEventRef); 1000 1001 _splitpath(Memory.ROMFilename, drive, dir, fname, ext); 1002 ref = CFStringCreateWithCString(kCFAllocatorDefault, fname, kCFStringEncodingUTF8); 1003 if (ref) 1004 { 1005 SetWindowTitleWithCFString(gWindow, ref); 1006 CFRelease(ref); 1007 } 1008 1009 attr = kWindowFullZoomAttribute | kWindowResizableAttribute | kWindowLiveResizeAttribute; 1010 err = ChangeWindowAttributes(gWindow, attr, kWindowNoAttributes); 1011 1012 attr = kWindowToolbarButtonAttribute; 1013 if (!drawoverscan) 1014 err = ChangeWindowAttributes(gWindow, attr, kWindowNoAttributes); 1015 else 1016 err = ChangeWindowAttributes(gWindow, kWindowNoAttributes, attr); 1017 1018 if (savewindowpos) 1019 { 1020 MoveWindow(gWindow, windowPos[kWindowScreen].h, windowPos[kWindowScreen].v, false); 1021 1022 if ((windowSize[kWindowScreen].width <= 0) || (windowSize[kWindowScreen].height <= 0)) 1023 { 1024 windowExtend = true; 1025 windowSize[kWindowScreen].width = 512; 1026 windowSize[kWindowScreen].height = kMacWindowHeight; 1027 } 1028 1029 if (!lastoverscan && !windowExtend && drawoverscan) 1030 { 1031 windowExtend = true; 1032 windowSize[kWindowScreen].height = (int) ((float) (windowSize[kWindowScreen].height + 0.5) * SNES_HEIGHT_EXTENDED / SNES_HEIGHT); 1033 } 1034 1035 SizeWindow(gWindow, (short) windowSize[kWindowScreen].width, (short) windowSize[kWindowScreen].height, false); 1036 } 1037 else 1038 { 1039 if (drawoverscan) 1040 windowExtend = true; 1041 1042 SizeWindow(gWindow, 512, (windowExtend ? kMacWindowHeight : (SNES_HEIGHT << 1)), false); 1043 RepositionWindow(gWindow, NULL, kWindowCenterOnMainScreen); 1044 } 1045 1046 windowZoomCount = 0; 1047 1048 GetWindowBounds(gWindow, kWindowContentRgn, &rct); 1049 gWindowRect = CGRectMake((float) rct.left, (float) rct.top, (float) (rct.right - rct.left), (float) (rct.bottom - rct.top)); 1050 1051 ActivateWindow(gWindow, true); 1052} 1053 1054void UpdateGameWindow (void) 1055{ 1056 OSStatus err; 1057 HIViewRef ctl; 1058 HIViewID cid = { 'Pict', 0 }; 1059 1060 if (!gWindow) 1061 return; 1062 1063 HIViewFindByID(HIViewGetRoot(gWindow), cid, &ctl); 1064 err = HIViewSetNeedsDisplay(ctl, true); 1065} 1066 1067static void ResizeGameWindow (void) 1068{ 1069 Rect rct; 1070 int ww, wh; 1071 1072 if (!gWindow) 1073 return; 1074 1075 GetWindowBounds(gWindow, kWindowContentRgn, &rct); 1076 1077 wh = (windowExtend ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT) * ((windowZoomCount >> 1) + 1); 1078 1079 if (windowZoomCount % 2) 1080 ww = SNES_NTSC_OUT_WIDTH(SNES_WIDTH) * ((windowZoomCount >> 1) + 1) / 2; 1081 else 1082 ww = SNES_WIDTH * ((windowZoomCount >> 1) + 1); 1083 1084 rct.right = rct.left + ww; 1085 rct.bottom = rct.top + wh; 1086 1087 SetWindowBounds(gWindow, kWindowContentRgn, &rct); 1088 1089 printf("Window Size: %d, %d\n", ww, wh); 1090 1091 windowZoomCount++; 1092 if (windowZoomCount == 8) 1093 windowZoomCount = 0; 1094} 1095 1096void DeinitGameWindow (void) 1097{ 1098 OSStatus err; 1099 1100 if (!gWindow) 1101 return; 1102 1103 SaveWindowPosition(gWindow, kWindowScreen); 1104 lastoverscan = drawoverscan; 1105 1106 err = RemoveEventHandler(gameWUPaneEventRef); 1107 DisposeEventHandlerUPP(gameWUPaneUPP); 1108 1109 err = RemoveEventHandler(gameWindowEventRef); 1110 DisposeEventHandlerUPP(gameWindowUPP); 1111 1112 CFRelease(gWindow); 1113 gWindow = NULL; 1114} 1115 1116static pascal OSStatus GameWindowEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData) 1117{ 1118 OSStatus err, result = eventNotHandledErr; 1119 HIRect rct; 1120 Rect r; 1121 UInt32 attr; 1122 1123 switch (GetEventClass(inEvent)) 1124 { 1125 case kEventClassWindow: 1126 switch (GetEventKind(inEvent)) 1127 { 1128 case kEventWindowDeactivated: 1129 if (running) 1130 { 1131 if (!(Settings.NetPlay && !Settings.NetPlayServer)) 1132 { 1133 if (inactiveMode == 3) 1134 { 1135 running = false; 1136 while (s9xthreadrunning) 1137 sleep(0); 1138 QuitApplicationEventLoop(); 1139 result = noErr; 1140 } 1141 else 1142 if (inactiveMode == 2) 1143 { 1144 rejectinput = true; 1145 result = noErr; 1146 } 1147 } 1148 } 1149 1150 break; 1151 1152 case kEventWindowActivated: 1153 if (running) 1154 { 1155 if (!(Settings.NetPlay && !Settings.NetPlayServer)) 1156 { 1157 ForceChangingKeyScript(); 1158 1159 if (inactiveMode == 2) 1160 { 1161 rejectinput = false; 1162 result = noErr; 1163 } 1164 } 1165 } 1166 1167 break; 1168 1169 case kEventWindowBoundsChanging: 1170 windowResizeCount = 0x7FFFFFFF; 1171 1172 err = GetEventParameter(inEvent, kEventParamAttributes, typeUInt32, NULL, sizeof(UInt32), NULL, &attr); 1173 if ((err == noErr) && (attr & kWindowBoundsChangeSizeChanged)) 1174 { 1175 err = GetEventParameter(inEvent, kEventParamCurrentBounds, typeHIRect, NULL, sizeof(HIRect), NULL, &rct); 1176 if (err == noErr) 1177 { 1178 if (GetCurrentEventKeyModifiers() & shiftKey) 1179 { 1180 HIRect origRct; 1181 1182 err = GetEventParameter(inEvent, kEventParamOriginalBounds, typeHIRect, NULL, sizeof(HIRect), NULL, &origRct); 1183 if (err == noErr) 1184 { 1185 rct.size.width = (float) (int) (origRct.size.width * rct.size.height / origRct.size.height); 1186 err = SetEventParameter(inEvent, kEventParamCurrentBounds, typeHIRect, sizeof(HIRect), &rct); 1187 } 1188 } 1189 1190 gWindowRect = rct; 1191 } 1192 } 1193 1194 result = noErr; 1195 break; 1196 1197 case kEventWindowBoundsChanged: 1198 windowResizeCount = 3; 1199 result = noErr; 1200 break; 1201 1202 case kEventWindowZoom: 1203 ResizeGameWindow(); 1204 result = noErr; 1205 break; 1206 1207 case kEventWindowToolbarSwitchMode: 1208 windowExtend = !windowExtend; 1209 1210 GetWindowBounds(gWindow, kWindowContentRgn, &r); 1211 1212 if (windowExtend) 1213 r.bottom = r.top + (int) (((float) (r.bottom - r.top) + 0.5) * SNES_HEIGHT_EXTENDED / SNES_HEIGHT); 1214 else 1215 r.bottom = r.top + (int) (((float) (r.bottom - r.top) + 0.5) * SNES_HEIGHT / SNES_HEIGHT_EXTENDED); 1216 1217 SetWindowBounds(gWindow, kWindowContentRgn, &r); 1218 1219 result = noErr; 1220 break; 1221 } 1222 1223 break; 1224 } 1225 1226 return (result); 1227} 1228 1229static pascal OSStatus GameWindowUserPaneEventHandler (EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData) 1230{ 1231 OSStatus err, result = eventNotHandledErr; 1232 1233 switch (GetEventClass(inEvent)) 1234 { 1235 case kEventClassControl: 1236 switch (GetEventKind(inEvent)) 1237 { 1238 case kEventControlClick: 1239 if (running) 1240 { 1241 if ((macControllerOption == SNES_JOYPAD) || (macControllerOption == SNES_MULTIPLAYER5) || (macControllerOption == SNES_MULTIPLAYER5_2)) 1242 { 1243 if (!(Settings.NetPlay && !Settings.NetPlayServer)) 1244 { 1245 if (!frzselecting) 1246 { 1247 running = false; 1248 while (s9xthreadrunning) 1249 sleep(0); 1250 QuitApplicationEventLoop(); 1251 result = noErr; 1252 } 1253 } 1254 } 1255 } 1256 else 1257 { 1258 UInt32 count; 1259 1260 err = GetEventParameter(inEvent, kEventParamClickCount, typeUInt32, NULL, sizeof(UInt32), NULL, &count); 1261 if ((err == noErr) && (count == 2)) 1262 { 1263 SNES9X_Go(); 1264 QuitApplicationEventLoop(); 1265 result = noErr; 1266 } 1267 } 1268 1269 break; 1270 1271 case kEventControlDraw: 1272 CGContextRef ctx; 1273 HIViewRef view; 1274 HIRect bounds; 1275 1276 err = GetEventParameter(inEvent, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &view); 1277 if (err == noErr) 1278 { 1279 err = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(CGContextRef), NULL, &ctx); 1280 if (err == noErr) 1281 { 1282 if (!running) 1283 { 1284 HIViewGetBounds(view, &bounds); 1285 CGContextTranslateCTM(ctx, 0, bounds.size.height); 1286 CGContextScaleCTM(ctx, 1.0f, -1.0f); 1287 DrawPauseScreen(ctx, bounds); 1288 } 1289 } 1290 } 1291 1292 result = noErr; 1293 break; 1294 } 1295 1296 break; 1297 } 1298 1299 return (result); 1300} 1301 1302static void InitRecentItems (void) 1303{ 1304 CFStringRef keyRef, pathRef; 1305 int count; 1306 char key[32]; 1307 1308 count = 0; 1309 1310 for (int i = 0; i <= kRecentMenu_MAX; i++) 1311 recentItem[i] = NULL; 1312 1313 for (int i = 0; i < kRecentMenu_MAX; i++) 1314 { 1315 sprintf(key, "RecentItem_%02d", i); 1316 keyRef = CFStringCreateWithCString(kCFAllocatorDefault, key, CFStringGetSystemEncoding()); 1317 if (keyRef) 1318 { 1319 pathRef = (CFStringRef) CFPreferencesCopyAppValue(keyRef, kCFPreferencesCurrentApplication); 1320 if (pathRef) 1321 { 1322 recentItem[count] = pathRef; 1323 count++; 1324 } 1325 1326 CFRelease(keyRef); 1327 } 1328 } 1329} 1330 1331static void DeinitRecentItems (void) 1332{ 1333 CFStringRef keyRef; 1334 char key[32]; 1335 1336 for (int i = 0; i < kRecentMenu_MAX; i++) 1337 { 1338 sprintf(key, "RecentItem_%02d", i); 1339 keyRef = CFStringCreateWithCString(kCFAllocatorDefault, key, CFStringGetSystemEncoding()); 1340 if (keyRef) 1341 { 1342 if (recentItem[i]) 1343 { 1344 CFPreferencesSetAppValue(keyRef, recentItem[i], kCFPreferencesCurrentApplication); 1345 CFRelease(recentItem[i]); 1346 recentItem[i] = NULL; 1347 } 1348 else 1349 CFPreferencesSetAppValue(keyRef, NULL, kCFPreferencesCurrentApplication); 1350 1351 CFRelease(keyRef); 1352 } 1353 } 1354 1355 CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication); 1356} 1357 1358static void ClearRecentItems (void) 1359{ 1360 for (int i = 0; i < kRecentMenu_MAX; i++) 1361 { 1362 if (recentItem[i]) 1363 { 1364 CFRelease(recentItem[i]); 1365 recentItem[i] = NULL; 1366 } 1367 } 1368} 1369 1370void AddRecentItem (FSRef *ref) 1371{ 1372 OSStatus err; 1373 char path[PATH_MAX + 1]; 1374 1375 err = FSRefMakePath(ref, (unsigned char *) path, PATH_MAX); 1376 if (err == noErr) 1377 { 1378 CFStringRef pathRef; 1379 1380 pathRef = CFStringCreateWithCString(kCFAllocatorDefault, path, kCFStringEncodingUTF8); 1381 if (pathRef) 1382 { 1383 int i, j; 1384 1385 for (i = 0; i < kRecentMenu_MAX; i++) 1386 if (recentItem[i] && (CFStringCompare(pathRef, recentItem[i], 0) == 0)) 1387 break; 1388 1389 if (i == kRecentMenu_MAX) 1390 { 1391 for (j = kRecentMenu_MAX - 1; j >= 0; j--) 1392 recentItem[j + 1] = recentItem[j]; 1393 1394 if (recentItem[kRecentMenu_MAX]) 1395 { 1396 CFRelease(recentItem[kRecentMenu_MAX]); 1397 recentItem[kRecentMenu_MAX] = NULL; 1398 } 1399 1400 recentItem[0] = pathRef; 1401 } 1402 else 1403 { 1404 CFRelease(pathRef); 1405 1406 if (i > 0) 1407 { 1408 CFStringRef temp; 1409 1410 temp = recentItem[i]; 1411 1412 for (j = i - 1; j >= 0; j--) 1413 recentItem[j + 1] = recentItem[j]; 1414 1415 recentItem[0] = temp; 1416 } 1417 } 1418 } 1419 } 1420} 1421 1422static void InitRecentMenu (void) 1423{ 1424 OSStatus err; 1425 1426 err = CreateNewMenu(mRecentItem, 0, &recentMenu); 1427 err = SetMenuItemHierarchicalMenu(GetMenuRef(mFile), iOpenRecent, recentMenu); 1428} 1429 1430static void DeinitRecentMenu (void) 1431{ 1432 CFRelease(recentMenu); 1433} 1434 1435void BuildRecentMenu (void) 1436{ 1437 OSStatus err; 1438 CFStringRef str; 1439 1440 err = DeleteMenuItems(recentMenu, 1, CountMenuItems(recentMenu)); 1441 1442 for (int i = 0; i < kRecentMenu_MAX; i++) 1443 { 1444 if (!recentItem[i]) 1445 break; 1446 1447 Boolean r; 1448 char path[PATH_MAX + 1]; 1449 1450 r = CFStringGetCString(recentItem[i], path, PATH_MAX, kCFStringEncodingUTF8); 1451 if (r) 1452 { 1453 CFStringRef nameRef; 1454 char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], fname[_MAX_FNAME + 1], ext[_MAX_EXT + 1]; 1455 1456 _splitpath(path, drive, dir, fname, ext); 1457 snprintf(path, PATH_MAX + 1, "%s%s", fname, ext); 1458 nameRef = CFStringCreateWithCString(kCFAllocatorDefault, path, kCFStringEncodingUTF8); 1459 if (nameRef) 1460 { 1461 err = AppendMenuItemTextWithCFString(recentMenu, nameRef, 0, 'FRe0' + i, NULL); 1462 CFRelease(nameRef); 1463 } 1464 } 1465 } 1466 1467 err = AppendMenuItemTextWithCFString(recentMenu, NULL, kMenuItemAttrSeparator, 'FR__', NULL); 1468 1469 str = CFCopyLocalizedString(CFSTR("ClearMenu"), "ClearMenu"); 1470 if (str) 1471 { 1472 err = AppendMenuItemTextWithCFString(recentMenu, str, 0, 'FRcr', NULL); 1473 CFRelease(str); 1474 } 1475} 1476 1477void AdjustMenus (void) 1478{ 1479 OSStatus err; 1480 MenuRef menu; 1481 CFStringRef str; 1482 1483 if (running) 1484 { 1485 menu = GetMenuRef(mApple); 1486 DisableMenuItem(menu, iAbout); 1487 DisableMenuCommand(NULL, kHICommandPreferences); 1488 DisableMenuCommand(NULL, kHICommandQuit); 1489 1490 menu = GetMenuRef(mFile); 1491 DisableMenuItem(menu, iOpen); 1492 DisableMenuItem(menu, iOpenMulti); 1493 DisableMenuItem(menu, iOpenRecent); 1494 DisableMenuItem(menu, iRomInfo); 1495 1496 menu = GetMenuRef(mControl); 1497 DisableMenuItem(menu, iKeyboardLayout); 1498 DisableMenuItem(menu, iISpLayout); 1499 DisableMenuItem(menu, iAutoFire); 1500 DisableMenuItem(menu, iISpPreset); 1501 1502 menu = GetMenuRef(mEmulation); 1503 str = CFCopyLocalizedString(CFSTR("PauseMenu"), "pause"); 1504 err = SetMenuItemTextWithCFString(menu, iResume, str); 1505 CFRelease(str); 1506 DisableMenuItem(menu, iSoftReset); 1507 DisableMenuItem(menu, iReset); 1508 DisableMenuItem(menu, iDevice); 1509 1510 if (Settings.NetPlay) 1511 { 1512 if (Settings.NetPlayServer) 1513 EnableMenuItem(menu, iResume); 1514 else 1515 DisableMenuItem(menu, iResume); 1516 } 1517 else 1518 EnableMenuItem(menu, iResume); 1519 1520 menu = GetMenuRef(mCheat); 1521 DisableMenuItem(menu, iApplyCheats); 1522 DisableMenuItem(menu, iGameGenie); 1523 DisableMenuItem(menu, iCheatFinder); 1524 1525 menu = GetMenuRef(mOption); 1526 DisableMenuItem(menu, iFreeze); 1527 DisableMenuItem(menu, iDefrost); 1528 DisableMenuItem(menu, iFreezeTo); 1529 DisableMenuItem(menu, iDefrostFrom); 1530 DisableMenuItem(menu, iRecordMovie); 1531 DisableMenuItem(menu, iPlayMovie); 1532 DisableMenuItem(menu, iQTMovie); 1533 DisableMenuItem(menu, iSaveSPC); 1534 DisableMenuItem(menu, iSaveSRAM); 1535 DisableMenuItem(menu, iMusicBox); 1536 if (ciFilterEnable) 1537 EnableMenuItem(menu, iCIFilter); 1538 else 1539 DisableMenuItem(menu, iCIFilter); 1540 1541 menu = GetMenuRef(mNetplay); 1542 DisableMenuItem(menu, iServer); 1543 DisableMenuItem(menu, iClient); 1544 } 1545 else 1546 { 1547 menu = GetMenuRef(mApple); 1548 EnableMenuItem(menu, iAbout); 1549 EnableMenuCommand(NULL, kHICommandPreferences); 1550 EnableMenuCommand(NULL, kHICommandQuit); 1551 1552 menu = GetMenuRef(mFile); 1553 EnableMenuItem(menu, iOpen); 1554 EnableMenuItem(menu, iOpenMulti); 1555 EnableMenuItem(menu, iOpenRecent); 1556 if (cartOpen) 1557 EnableMenuItem(menu, iRomInfo); 1558 else 1559 DisableMenuItem(menu, iRomInfo); 1560 1561 menu = GetMenuRef(mControl); 1562 EnableMenuItem(menu, iKeyboardLayout); 1563 EnableMenuItem(menu, iAutoFire); 1564 if (hidExist) 1565 { 1566 EnableMenuItem(menu, iISpLayout); 1567 EnableMenuItem(menu, iISpPreset); 1568 } 1569 else 1570 { 1571 DisableMenuItem(menu, iISpLayout); 1572 DisableMenuItem(menu, iISpPreset); 1573 } 1574 1575 menu = GetMenuRef(mEmulation); 1576 str = CFCopyLocalizedString(CFSTR("RunMenu"), "run"); 1577 err = SetMenuItemTextWithCFString(menu, iResume, str); 1578 CFRelease(str); 1579 EnableMenuItem(menu, iDevice); 1580 if (cartOpen) 1581 { 1582 EnableMenuItem(menu, iResume); 1583 EnableMenuItem(menu, iSoftReset); 1584 EnableMenuItem(menu, iReset); 1585 } 1586 else 1587 { 1588 DisableMenuItem(menu, iResume); 1589 DisableMenuItem(menu, iSoftReset); 1590 DisableMenuItem(menu, iReset); 1591 } 1592 1593 menu = GetMenuRef(mCheat); 1594 if (cartOpen) 1595 { 1596 EnableMenuItem(menu, iApplyCheats); 1597 EnableMenuItem(menu, iGameGenie); 1598 EnableMenuItem(menu, iCheatFinder); 1599 } 1600 else 1601 { 1602 DisableMenuItem(menu, iApplyCheats); 1603 DisableMenuItem(menu, iGameGenie); 1604 DisableMenuItem(menu, iCheatFinder); 1605 } 1606 1607 menu = GetMenuRef(mOption); 1608 DisableMenuItem(menu, iCIFilter); 1609 if (cartOpen) 1610 { 1611 EnableMenuItem(menu, iFreeze); 1612 EnableMenuItem(menu, iDefrost); 1613 EnableMenuItem(menu, iFreezeTo); 1614 EnableMenuItem(menu, iDefrostFrom); 1615 EnableMenuItem(menu, iRecordMovie); 1616 EnableMenuItem(menu, iPlayMovie); 1617 EnableMenuItem(menu, iQTMovie); 1618 EnableMenuItem(menu, iSaveSPC); 1619 EnableMenuItem(menu, iSaveSRAM); 1620 EnableMenuItem(menu, iMusicBox); 1621 } 1622 else 1623 { 1624 DisableMenuItem(menu, iFreeze); 1625 DisableMenuItem(menu, iDefrost); 1626 DisableMenuItem(menu, iFreezeTo); 1627 DisableMenuItem(menu, iDefrostFrom); 1628 DisableMenuItem(menu, iRecordMovie); 1629 DisableMenuItem(menu, iPlayMovie); 1630 DisableMenuItem(menu, iQTMovie); 1631 DisableMenuItem(menu, iSaveSPC); 1632 DisableMenuItem(menu, iSaveSRAM); 1633 DisableMenuItem(menu, iMusicBox); 1634 } 1635 1636 menu = GetMenuRef(mNetplay); 1637 EnableMenuItem(menu, iClient); 1638 if (cartOpen) 1639 EnableMenuItem(menu, iServer); 1640 else 1641 DisableMenuItem(menu, iServer); 1642 } 1643 1644 DrawMenuBar(); 1645} 1646 1647void UpdateMenuCommandStatus (Boolean closeMenu) 1648{ 1649 if (closeMenu) 1650 EnableMenuItem(GetMenuRef(mFile), iClose); 1651 else 1652 DisableMenuItem(GetMenuRef(mFile), iClose); 1653} 1654 1655static OSStatus HandleMenuChoice (UInt32 command, Boolean *done) 1656{ 1657 OSStatus err, result = noErr; 1658 MenuRef mh; 1659 int item; 1660 bool8 isok = true; 1661 1662 if ((command & 0xFFFFFF00) == 'FRe\0') 1663 { 1664 Boolean r; 1665 int index; 1666 char path[PATH_MAX + 1]; 1667 1668 index = (int) (command & 0x000000FF) - (int) '0'; 1669 r = CFStringGetCString(recentItem[index], path, PATH_MAX, kCFStringEncodingUTF8); 1670 if (r) 1671 { 1672 FSRef ref; 1673 1674 err = FSPathMakeRef((unsigned char *) path, &ref, NULL); 1675 if (err == noErr) 1676 { 1677 if (SNES9X_OpenCart(&ref)) 1678 { 1679 SNES9X_Go(); 1680 *done = true; 1681 } 1682 else 1683 AdjustMenus(); 1684 } 1685 } 1686 } 1687 else 1688 { 1689 switch (command) 1690 { 1691 case 'abou': // About SNES9X 1692 StartCarbonModalDialog(); 1693 AboutDialog(); 1694 FinishCarbonModalDialog(); 1695 1696 break; 1697 1698 case 'pref': // Preferences... 1699 StartCarbonModalDialog(); 1700 ConfigurePreferences(); 1701 FinishCarbonModalDialog(); 1702 1703 break; 1704 1705 case 'EXTR': // Extra Options... 1706 StartCarbonModalDialog(); 1707 ConfigureExtraOptions(); 1708 FinishCarbonModalDialog(); 1709 1710 break; 1711 1712 case 'quit': // Quit SNES9X 1713 SNES9X_Quit(); 1714 *done = true; 1715 1716 break; 1717 1718 case 'open': // Open ROM Image... 1719 if (SNES9X_OpenCart(NULL)) 1720 { 1721 SNES9X_Go(); 1722 *done = true; 1723 } 1724 else 1725 AdjustMenus(); 1726 1727 break; 1728 1729 case 'Mult': // Open Multiple ROM Images... 1730 if (SNES9X_OpenMultiCart()) 1731 { 1732 SNES9X_Go(); 1733 *done = true; 1734 } 1735 else 1736 AdjustMenus(); 1737 1738 break; 1739 1740 case 'FRcr': // Clear Menu 1741 ClearRecentItems(); 1742 BuildRecentMenu(); 1743 1744 break; 1745 1746 case 'Finf': // ROM Information 1747 StartCarbonModalDialog(); 1748 RomInfoDialog(); 1749 FinishCarbonModalDialog(); 1750 1751 break; 1752 1753 case 'Ckey': // Configure Keyboard... 1754 StartCarbonModalDialog(); 1755 ConfigureKeyboard(); 1756 FinishCarbonModalDialog(); 1757 1758 break; 1759 1760 case 'Cpad': // Configure Controllers... 1761 StartCarbonModalDialog(); 1762 ConfigureHID(); 1763 FinishCarbonModalDialog(); 1764 1765 break; 1766 1767 case 'Caut': // Automatic Fire... 1768 StartCarbonModalDialog(); 1769 ConfigureAutofire(); 1770 FinishCarbonModalDialog(); 1771 1772 break; 1773 1774 case 'Hapl': // Apply Cheat Entries 1775 mh = GetMenuRef(mCheat); 1776 applycheat = !applycheat; 1777 CheckMenuItem(mh, iApplyCheats, applycheat); 1778 Settings.ApplyCheats = applycheat; 1779 1780 if (!Settings.ApplyCheats) 1781 S9xRemoveCheats(); 1782 else 1783 S9xApplyCheats(); 1784 1785 break; 1786 1787 case 'Hent': // Cheat Entry... 1788 StartCarbonModalDialog(); 1789 ConfigureCheat(); 1790 FinishCarbonModalDialog(); 1791 1792 break; 1793 1794 case 'Hfnd': // Cheat Finder... 1795 StartCarbonModalDialog(); 1796 CheatFinder(); 1797 FinishCarbonModalDialog(); 1798 1799 break; 1800 1801 case 'Erun': // Run 1802 SNES9X_Go(); 1803 *done = true; 1804 1805 break; 1806 1807 case 'Esrs': // Software Reset 1808 SNES9X_SoftReset(); 1809 SNES9X_Go(); 1810 *done = true; 1811 1812 break; 1813 1814 case 'Erst': // Hardware Reset 1815 SNES9X_Reset(); 1816 SNES9X_Go(); 1817 *done = true; 1818 1819 break; 1820 1821 case 'Ofrz': // Freeze State 1822 isok = SNES9X_Freeze(); 1823 *done = true; 1824 1825 break; 1826 1827 case 'Odfr': // Defrost state 1828 isok = SNES9X_Defrost(); 1829 *done = true; 1830 1831 break; 1832 1833 case 'Ofrd': // Freeze State to... 1834 StartCarbonModalDialog(); 1835 isok = SNES9X_FreezeTo(); 1836 FinishCarbonModalDialog(); 1837 1838 break; 1839 1840 case 'Odfd': // Defrost State From... 1841 StartCarbonModalDialog(); 1842 isok = SNES9X_DefrostFrom(); 1843 if (gWindow) 1844 ActivateWindow(gWindow, true); 1845 FinishCarbonModalDialog(); 1846 *done = true; 1847 1848 break; 1849 1850 case 'MVrc': // Record Movie... 1851 StartCarbonModalDialog(); 1852 isok = SNES9X_RecordMovie(); 1853 if (gWindow) 1854 ActivateWindow(gWindow, true); 1855 FinishCarbonModalDialog(); 1856 *done = true; 1857 1858 break; 1859 1860 case 'MVpl': // Play Movie... 1861 StartCarbonModalDialog(); 1862 isok = SNES9X_PlayMovie(); 1863 if (isok && (macPlayFlag & 0x2)) 1864 { 1865 running = false; 1866 isok = SNES9X_QTMovieRecord(); 1867 running = true; 1868 } 1869 1870 if (gWindow) 1871 ActivateWindow(gWindow, true); 1872 FinishCarbonModalDialog(); 1873 *done = true; 1874 1875 break; 1876 1877 case 'QTmv': // Record QuickTime Movie... 1878 StartCarbonModalDialog(); 1879 isok = SNES9X_QTMovieRecord(); 1880 if (gWindow) 1881 ActivateWindow(gWindow, true); 1882 FinishCarbonModalDialog(); 1883 *done = true; 1884 1885 break; 1886 1887 case 'Ospc': // Save SPC File at Next Note-on 1888 S9xDumpSPCSnapshot(); 1889 1890 break; 1891 1892 case 'Osrm': // Save SRAM Now 1893 SNES9X_SaveSRAM(); 1894 1895 break; 1896 1897 case 'Ombx': // Music Box 1898 StartCarbonModalDialog(); 1899 MusicBoxDialog(); 1900 FinishCarbonModalDialog(); 1901 1902 break; 1903 1904 case 'Nser': // Server... 1905 bool8 sr; 1906 1907 Settings.NetPlay = false; 1908 Settings.NetPlayServer = false; 1909 1910 NPServerInit(); 1911 1912 if (!NPServerStartServer(NP_PORT)) 1913 { 1914 NPServerStopServer(); 1915 break; 1916 } 1917 1918 StartCarbonModalDialog(); 1919 sr = NPServerDialog(); 1920 FinishCarbonModalDialog(); 1921 1922 if (sr) 1923 { 1924 SNES9X_Reset(); 1925 SNES9X_Go(); 1926 Settings.NetPlay = true; 1927 Settings.NetPlayServer = true; 1928 1929 *done = true; 1930 } 1931 else 1932 NPServerStopServer(); 1933 1934 break; 1935 1936 case 'Ncli': // Client... 1937 bool8 cr; 1938 1939 Settings.NetPlay = false; 1940 Settings.NetPlayServer = false; 1941 1942 NPClientInit(); 1943 1944 StartCarbonModalDialog(); 1945 cr = NPClientDialog(); 1946 FinishCarbonModalDialog(); 1947 1948 if (cr) 1949 { 1950 SNES9X_Go(); 1951 Settings.NetPlay = true; 1952 Settings.NetPlayServer = false; 1953 1954 *done = true; 1955 } 1956 else 1957 AdjustMenus(); 1958 1959 break; 1960 1961 case 'CPr1': // Controller Preset 1962 case 'CPr2': 1963 case 'CPr3': 1964 case 'CPr4': 1965 case 'CPr5': 1966 item = (int) (command & 0x000000FF) - (int) '0'; 1967 err = GetMenuItemHierarchicalMenu(GetMenuRef(mControl), iISpPreset, &mh); 1968 CheckMenuItem(mh, padSetting, false); 1969 padSetting = item; 1970 CheckMenuItem(mh, padSetting, true); 1971 ClearPadSetting(); 1972 LoadControllerSettings(); 1973 1974 break; 1975 1976 case 'EIp1': // Input Device 1977 case 'EIp2': 1978 case 'EIp3': 1979 case 'EIp4': 1980 case 'EIp5': 1981 case 'EIp6': 1982 case 'EIp7': 1983 case 'EIp8': 1984 item = (int) (command & 0x000000FF) - (int) '0'; 1985 err = GetMenuItemHierarchicalMenu(GetMenuRef(mEmulation), iDevice, &mh); 1986 CheckMenuItem(mh, deviceSetting, false); 1987 deviceSetting = item; 1988 deviceSettingMaster = deviceSetting; 1989 CheckMenuItem(mh, deviceSetting, true); 1990 ChangeInputDevice(); 1991 1992 break; 1993 1994 default: 1995 result = eventNotHandledErr; 1996 break; 1997 } 1998 } 1999 2000 return (result); 2001} 2002 2003void ChangeInputDevice (void) 2004{ 2005 switch (deviceSetting) 2006 { 2007 case iPad: 2008 S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0); 2009 S9xSetController(1, CTL_JOYPAD, 1, 0, 0, 0); 2010 macControllerOption = SNES_JOYPAD; 2011 break; 2012 2013 case iMouse: 2014 S9xSetController(0, CTL_MOUSE, 0, 0, 0, 0); 2015 S9xSetController(1, CTL_JOYPAD, 1, 0, 0, 0); 2016 macControllerOption = SNES_MOUSE; 2017 break; 2018 2019 case iMouse2: 2020 S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0); 2021 S9xSetController(1, CTL_MOUSE, 1, 0, 0, 0); 2022 macControllerOption = SNES_MOUSE_SWAPPED; 2023 break; 2024 2025 case iSuperScope: 2026 S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0); 2027 S9xSetController(1, CTL_SUPERSCOPE, 0, 0, 0, 0); 2028 macControllerOption = SNES_SUPERSCOPE; 2029 break; 2030 2031 case iMultiPlayer5: 2032 S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0); 2033 S9xSetController(1, CTL_MP5, 1, 2, 3, 4); 2034 macControllerOption = SNES_MULTIPLAYER5; 2035 break; 2036 2037 case iMultiPlayer5_2: 2038 S9xSetController(0, CTL_MP5, 0, 1, 2, 3); 2039 S9xSetController(1, CTL_MP5, 4, 5, 6, 7); 2040 macControllerOption = SNES_MULTIPLAYER5_2; 2041 break; 2042 2043 case iJustifier1: 2044 S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0); 2045 S9xSetController(1, CTL_JUSTIFIER, 0, 0, 0, 0); 2046 macControllerOption = SNES_JUSTIFIER; 2047 break; 2048 2049 case iJustifier2: 2050 S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0); 2051 S9xSetController(1, CTL_JUSTIFIER, 1, 0, 0, 0); 2052 macControllerOption = SNES_JUSTIFIER_2; 2053 break; 2054 } 2055} 2056 2057void ApplyNSRTHeaderControllers (void) 2058{ 2059 OSStatus err; 2060 MenuRef menu; 2061 2062 err = GetMenuItemHierarchicalMenu(GetMenuRef(mEmulation), iDevice, &menu); 2063 if (err) 2064 return; 2065 2066 for (int i = 1; i <= CountMenuItems(menu); i++) 2067 { 2068 CheckMenuItem(menu, i, false); 2069 SetItemStyle(menu, i, normal); 2070 } 2071 2072 deviceSetting = deviceSettingMaster; 2073 2074 uint32 valid = 0; 2075 2076 if (!strncmp((const char *) Memory.NSRTHeader + 24, "NSRT", 4)) 2077 { 2078 switch (Memory.NSRTHeader[29]) 2079 { 2080 case 0x00: // Everything goes 2081 deviceSetting = iPad; 2082 valid = (1 << iPad); 2083 break; 2084 2085 case 0x10: // Mouse in Port 0 2086 deviceSetting = iMouse; 2087 valid = (1 << iMouse); 2088 break; 2089 2090 case 0x01: // Mouse in Port 1 2091 deviceSetting = iMouse2; 2092 valid = (1 << iMouse2); 2093 break; 2094 2095 case 0x03: // Super Scope in Port 1 2096 deviceSetting = iSuperScope; 2097 valid = (1 << iSuperScope); 2098 break; 2099 2100 case 0x06: // Multitap in Port 1 2101 deviceSetting = iMultiPlayer5; 2102 valid = (1 << iPad) | (1 << iMultiPlayer5); 2103 break; 2104 2105 case 0x66: // Multitap in Ports 0 and 1 2106 deviceSetting = iMultiPlayer5_2; 2107 valid = (1 << iPad) | (1 << iMultiPlayer5) | (1 << iMultiPlayer5_2); 2108 break; 2109 2110 case 0x08: // Multitap in Port 1, Mouse in new Port 1 2111 deviceSetting = iMouse2; 2112 valid = (1 << iPad) | (1 << iMouse2) | (1 << iMultiPlayer5); 2113 break; 2114 2115 case 0x04: // Pad or Super Scope in Port 1 2116 deviceSetting = iSuperScope; 2117 valid = (1 << iPad) | (1 << iSuperScope); 2118 break; 2119 2120 case 0x05: // Justifier - Must ask user... 2121 deviceSetting = iJustifier1; 2122 valid = (1 << iJustifier1) | (1 << iJustifier2); 2123 break; 2124 2125 case 0x20: // Pad or Mouse in Port 0 2126 deviceSetting = iMouse; 2127 valid = (1 << iPad) | (1 << iMouse); 2128 break; 2129 2130 case 0x22: // Pad or Mouse in Port 0 & 1 2131 deviceSetting = iMouse; 2132 valid = (1 << iPad) | (1 << iMouse) | (1 << iMouse2); 2133 break; 2134 2135 case 0x24: // Pad or Mouse in Port 0, Pad or Super Scope in Port 1 2136 deviceSetting = iSuperScope; 2137 valid = (1 << iPad) | (1 << iMouse) | (1 << iSuperScope); 2138 break; 2139 2140 case 0x27: // Pad or Mouse in Port 0, Pad or Mouse or Super Scope in Port 1 2141 deviceSetting = iSuperScope; 2142 valid = (1 << iPad) | (1 << iMouse) | (1 << iMouse2) | (1 << iSuperScope); 2143 break; 2144 2145 case 0x99: // Lasabirdie 2146 break; 2147 2148 case 0x0A: // Barcode Battler 2149 break; 2150 2151 default: 2152 break; 2153 } 2154 } 2155 2156 CheckMenuItem(menu, deviceSetting, true); 2157 2158 for (int i = 1; i <= CountMenuItems(menu); i++) 2159 { 2160 if (valid & (1 << i)) 2161 SetItemStyle(menu, i, underline); 2162 } 2163 2164 ChangeInputDevice(); 2165} 2166 2167int PromptFreezeDefrost (Boolean freezing) 2168{ 2169 OSStatus err; 2170 CGContextRef ctx; 2171 CGColorSpaceRef color; 2172 CGDataProviderRef prov; 2173 CGImageRef image; 2174 CGRect rct; 2175 CGPoint pt; 2176 CFURLRef url; 2177 FSCatalogInfo info; 2178 FSRef ref; 2179 KeyMap keys; 2180 UInt64 newestDate, currentDate; 2181 UInt32 startTime; 2182 float x, y, textw; 2183 int result, newestIndex, current_selection, oldInactiveMode; 2184 char dateC[256]; 2185 uint8 *back, *draw; 2186 2187 const UInt32 repeatDelay = 10; 2188 const int w = SNES_WIDTH << 1, h = kMacWindowHeight; 2189 const char letters[] = "123456789ABC", *filename; 2190 const uint8 keyCheck[] = { kmEscKey, km1Key, km2Key, km3Key, km4Key, km5Key, km6Key, km7Key, km8Key, km9Key, kmAKey, kmBKey, kmCKey }; 2191 2192 if (!directDisplay) 2193 { 2194 S9xInitDisplay(NULL, NULL); 2195 SNES9X_Go(); 2196 } 2197 2198 frzselecting = true; 2199 oldInactiveMode = inactiveMode; 2200 if (inactiveMode == 3) 2201 inactiveMode = 2; 2202 2203 S9xSetSoundMute(true); 2204 2205 back = (uint8 *) malloc(w * h * 2); 2206 draw = (uint8 *) malloc(w * h * 2); 2207 if (!back || !draw) 2208 QuitWithFatalError(0, "os 04"); 2209 2210 color = CGColorSpaceCreateDeviceRGB(); 2211 if (!color) 2212 QuitWithFatalError(0, "os 05"); 2213 2214 ctx = CGBitmapContextCreate(back, w, h, 5, w * 2, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrder16Host : 0)); 2215 if (!ctx) 2216 QuitWithFatalError(0, "os 06"); 2217 2218 rct = CGRectMake(0.0f, 0.0f, (float) w, (float) h); 2219 CGContextClearRect(ctx, rct); 2220 2221 image = NULL; 2222 2223 if (freezing) 2224 url = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("logo_freeze"), CFSTR("png"), NULL); 2225 else 2226 url = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("logo_defrost"), CFSTR("png"), NULL); 2227 if (url) 2228 { 2229 prov = CGDataProviderCreateWithURL(url); 2230 if (prov) 2231 { 2232 image = CGImageCreateWithPNGDataProvider(prov, NULL, true, kCGRenderingIntentDefault); 2233 CGDataProviderRelease(prov); 2234 } 2235 2236 CFRelease(url); 2237 } 2238 2239 if (image) 2240 { 2241 rct = CGRectMake(0.0f, (float) h - 118.0f, 512.0f, 118.0f); 2242 CGContextDrawImage(ctx, rct, image); 2243 CGImageRelease(image); 2244 } 2245 2246 newestDate = 0; 2247 newestIndex = -1; 2248 2249 CGContextSetLineJoin(ctx, kCGLineJoinRound); 2250 2251 rct = CGRectMake(0.0f, (float) h - 238.0f, 128.0f, 120.0f); 2252 2253 for (int count = 0; count < 12; count++) 2254 { 2255 filename = S9xGetFreezeFilename(count); 2256 err = FSPathMakeRef((unsigned char *) filename, &ref, NULL); 2257 if (err == noErr) 2258 { 2259 err = FSGetCatalogInfo(&ref, kFSCatInfoContentMod, &info, NULL, NULL, NULL); 2260 currentDate = (((UInt64) info.contentModDate.highSeconds << 48) | ((UInt64) info.contentModDate.lowSeconds << 16) | (UInt64) info.contentModDate.fraction); 2261 2262 if (currentDate > newestDate) 2263 { 2264 newestIndex = count; 2265 newestDate = currentDate; 2266 } 2267 2268 DrawThumbnailResource(&ref, ctx, rct); 2269 2270 CGContextSetShouldAntialias(ctx, false); 2271 CGContextSetLineWidth(ctx, 1.0f); 2272 2273 CGContextSetRGBStrokeColor(ctx, 0.0f, 0.0f, 0.0f, 1.0f); 2274 x = rct.origin.x + 127.0f; 2275 y = rct.origin.y + 119.0f; 2276 CGContextBeginPath(ctx); 2277 CGContextMoveToPoint(ctx, x, y); 2278 CGContextAddLineToPoint(ctx, x, y - 119.0f); 2279 CGContextAddLineToPoint(ctx, x - 127.0f, y - 119.0f); 2280 CGContextStrokePath(ctx); 2281 2282 CGContextSetShouldAntialias(ctx, true); 2283 CGContextSetLineWidth(ctx, 3.0f); 2284 2285 CGContextSelectFont(ctx, "Helvetica", 12.0f, kCGEncodingMacRoman); 2286 x = rct.origin.x + 5.0f; 2287 y = rct.origin.y + 107.0f; 2288 CGContextSetTextDrawingMode(ctx, kCGTextStroke); 2289 CGContextSetRGBStrokeColor(ctx, 0.0f, 0.0f, 0.0f, 0.8f); 2290 CGContextShowTextAtPoint(ctx, x, y, &letters[count], 1); 2291 CGContextSetTextDrawingMode(ctx, kCGTextFill); 2292 CGContextSetRGBFillColor(ctx, 1.0f, 0.7f, 0.7f, 1.0f); 2293 CGContextShowTextAtPoint(ctx, x, y, &letters[count], 1); 2294 2295 if (showtimeinfrz) 2296 { 2297 CFAbsoluteTime at; 2298 CFDateFormatterRef format; 2299 CFLocaleRef locale; 2300 CFStringRef datstr; 2301 Boolean r; 2302 2303 err = UCConvertUTCDateTimeToCFAbsoluteTime(&(info.contentModDate), &at); 2304 locale = CFLocaleCopyCurrent(); 2305 format = CFDateFormatterCreate(kCFAllocatorDefault, locale, kCFDateFormatterShortStyle, kCFDateFormatterMediumStyle); 2306 datstr = CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault, format, at); 2307 r = CFStringGetCString(datstr, dateC, sizeof(dateC), CFStringGetSystemEncoding()); 2308 CFRelease(datstr); 2309 CFRelease(format); 2310 CFRelease(locale); 2311 2312 CGContextSelectFont(ctx, "Helvetica", 10.0f, kCGEncodingMacRoman); 2313 x = rct.origin.x + 20.0f; 2314 y = rct.origin.y + 107.0f; 2315 CGContextSetTextDrawingMode(ctx, kCGTextInvisible); 2316 CGContextShowTextAtPoint(ctx, x, y, dateC, strlen(dateC)); 2317 pt = CGContextGetTextPosition(ctx); 2318 textw = pt.x - x; 2319 x = rct.origin.x + 122.0f - textw; 2320 CGContextSetTextDrawingMode(ctx, kCGTextStroke); 2321 CGContextSetRGBStrokeColor(ctx, 0.0f, 0.0f, 0.0f, 0.8f); 2322 CGContextShowTextAtPoint(ctx, x, y, dateC, strlen(dateC)); 2323 CGContextSetTextDrawingMode(ctx, kCGTextFill); 2324 CGContextSetRGBFillColor(ctx, 1.0f, 1.0f, 1.0f, 1.0f); 2325 CGContextShowTextAtPoint(ctx, x, y, dateC, strlen(dateC)); 2326 } 2327 } 2328 else 2329 { 2330 CGContextSelectFont(ctx, "Helvetica", 12.0f, kCGEncodingMacRoman); 2331 x = rct.origin.x + 5.0f; 2332 y = rct.origin.y + 107.0f; 2333 CGContextSetTextDrawingMode(ctx, kCGTextFill); 2334 CGContextSetRGBFillColor(ctx, 0.7f, 0.7f, 0.7f, 1.0f); 2335 CGContextShowTextAtPoint(ctx, x, y, &letters[count], 1); 2336 } 2337 2338 if ((count % 4) == 3) 2339 rct = CGRectOffset(rct, -128.0f * 3.0f, -120.0f); 2340 else 2341 rct = CGRectOffset(rct, 128.0f, 0.0f); 2342 } 2343 2344 if (newestIndex < 0) 2345 newestIndex = 0; 2346 2347 CGContextRelease(ctx); 2348 2349 image = NULL; 2350 2351 prov = CGDataProviderCreateWithData(NULL, back, w * h * 2, NULL); 2352 if (prov) 2353 { 2354 image = CGImageCreate(w, h, 5, 16, w * 2, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrder16Host : 0), prov, NULL, 0, kCGRenderingIntentDefault); 2355 CGDataProviderRelease(prov); 2356 } 2357 2358 if (!image) 2359 QuitWithFatalError(0, "os 07"); 2360 2361 ctx = CGBitmapContextCreate(draw, w, h, 5, w * 2, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrder16Host : 0)); 2362 if (!ctx) 2363 QuitWithFatalError(0, "os 08"); 2364 2365 CGContextSetShouldAntialias(ctx, false); 2366 2367 UpdateFreezeDefrostScreen(newestIndex, image, draw, ctx); 2368 2369 CocoaPlayFreezeDefrostSound(); 2370 2371 result = -2; 2372 current_selection = newestIndex; 2373 2374 do 2375 { 2376 if (!rejectinput) 2377 { 2378 GetKeys(keys); 2379 2380 for (int count = 0; count <= 12; count++) 2381 { 2382 while (KeyIsPressed(keys, keyCheck[count])) 2383 { 2384 result = count - 1; 2385 GetKeys(keys); 2386 } 2387 } 2388 2389 while (KeyIsPressed(keys, keyCode[k1PRight])) 2390 { 2391 startTime = TickCount(); 2392 current_selection += 1; 2393 if (current_selection > 11) 2394 current_selection -= 12; 2395 UpdateFreezeDefrostScreen(current_selection, image, draw, ctx); 2396 while (KeyIsPressed(keys, keyCode[k1PRight]) && (TickCount() < (startTime + repeatDelay))) 2397 GetKeys(keys); 2398 } 2399 2400 while (KeyIsPressed(keys, keyCode[k1PLeft])) 2401 { 2402 startTime = TickCount(); 2403 current_selection -= 1; 2404 if (current_selection < 0) 2405 current_selection += 12; 2406 UpdateFreezeDefrostScreen(current_selection, image, draw, ctx); 2407 while (KeyIsPressed(keys, keyCode[k1PLeft]) && (TickCount() < (startTime + repeatDelay))) 2408 GetKeys(keys); 2409 } 2410 2411 while (KeyIsPressed(keys, keyCode[k1PDown])) 2412 { 2413 startTime = TickCount(); 2414 current_selection += 4; 2415 if (current_selection > 11) 2416 current_selection -= 12; 2417 UpdateFreezeDefrostScreen(current_selection, image, draw, ctx); 2418 while (KeyIsPressed(keys, keyCode[k1PDown]) && (TickCount() < (startTime + repeatDelay))) 2419 GetKeys(keys); 2420 } 2421 2422 while (KeyIsPressed(keys, keyCode[k1PUp])) 2423 { 2424 startTime = TickCount(); 2425 current_selection -= 4; 2426 if (current_selection < 0) 2427 current_selection += 12; 2428 UpdateFreezeDefrostScreen(current_selection, image, draw, ctx); 2429 while (KeyIsPressed(keys, keyCode[k1PUp]) && (TickCount() < (startTime + repeatDelay))) 2430 GetKeys(keys); 2431 } 2432 2433 while (KeyIsPressed(keys, keyCode[k1PA] ) || 2434 KeyIsPressed(keys, keyCode[k2PA] ) || 2435 KeyIsPressed(keys, keyCode[k1PB] ) || 2436 KeyIsPressed(keys, keyCode[k2PB] ) || 2437 KeyIsPressed(keys, keyCode[k1PX] ) || 2438 KeyIsPressed(keys, keyCode[k2PX] ) || 2439 KeyIsPressed(keys, keyCode[k1PY] ) || 2440 KeyIsPressed(keys, keyCode[k2PY] ) || 2441 KeyIsPressed(keys, keyCode[k1PStart] ) || 2442 KeyIsPressed(keys, keyCode[k2PStart] ) || 2443 KeyIsPressed(keys, keyCode[k1PSelect]) || 2444 KeyIsPressed(keys, keyCode[k2PSelect])) 2445 { 2446 GetKeys(keys); 2447 result = current_selection; 2448 } 2449 2450 uint32 pad1, pad2; 2451 2452 while (ISpKeyIsPressed(kISpEsc ) || 2453 ISpKeyIsPressed(kISp1PStart) || 2454 ISpKeyIsPressed(kISp2PStart)) 2455 result = -1; 2456 2457 pad1 = pad2 = 0; 2458 JoypadScanDirection(0, &pad1); 2459 JoypadScanDirection(1, &pad2); 2460 while ((pad1 & 0x0100) || (pad2 & 0x0100)) // Rt 2461 { 2462 startTime = TickCount(); 2463 current_selection += 1; 2464 if (current_selection > 11) 2465 current_selection -= 12; 2466 UpdateFreezeDefrostScreen(current_selection, image, draw, ctx); 2467 do 2468 { 2469 pad1 = pad2 = 0; 2470 JoypadScanDirection(0, &pad1); 2471 JoypadScanDirection(1, &pad2); 2472 } while (((pad1 & 0x0100) || (pad2 & 0x0100)) && (TickCount() < (startTime + repeatDelay))); 2473 } 2474 2475 pad1 = pad2 = 0; 2476 JoypadScanDirection(0, &pad1); 2477 JoypadScanDirection(1, &pad2); 2478 while ((pad1 & 0x0200) || (pad2 & 0x0200)) // Lf 2479 { 2480 startTime = TickCount(); 2481 current_selection -= 1; 2482 if (current_selection < 0) 2483 current_selection += 12; 2484 UpdateFreezeDefrostScreen(current_selection, image, draw, ctx); 2485 do 2486 { 2487 pad1 = pad2 = 0; 2488 JoypadScanDirection(0, &pad1); 2489 JoypadScanDirection(1, &pad2); 2490 } while (((pad1 & 0x0200) || (pad2 & 0x0200)) && (TickCount() < (startTime + repeatDelay))); 2491 } 2492 2493 pad1 = pad2 = 0; 2494 JoypadScanDirection(0, &pad1); 2495 JoypadScanDirection(1, &pad2); 2496 while ((pad1 & 0x0800) || (pad2 & 0x0800)) // Up 2497 { 2498 startTime = TickCount(); 2499 current_selection -= 4; 2500 if (current_selection < 0) 2501 current_selection += 12; 2502 UpdateFreezeDefrostScreen(current_selection, image, draw, ctx); 2503 do 2504 { 2505 pad1 = pad2 = 0; 2506 JoypadScanDirection(0, &pad1); 2507 JoypadScanDirection(1, &pad2); 2508 } while (((pad1 & 0x0800) || (pad2 & 0x0800)) && (TickCount() < (startTime + repeatDelay))); 2509 } 2510 2511 pad1 = pad2 = 0; 2512 JoypadScanDirection(0, &pad1); 2513 JoypadScanDirection(1, &pad2); 2514 while ((pad1 & 0x0400) || (pad2 & 0x0400)) // Dn 2515 { 2516 startTime = TickCount(); 2517 current_selection += 4; 2518 if (current_selection > 11) 2519 current_selection -= 12; 2520 UpdateFreezeDefrostScreen(current_selection, image, draw, ctx); 2521 do 2522 { 2523 pad1 = pad2 = 0; 2524 JoypadScanDirection(0, &pad1); 2525 JoypadScanDirection(1, &pad2); 2526 } while (((pad1 & 0x0400) || (pad2 & 0x0400)) && (TickCount() < (startTime + repeatDelay))); 2527 } 2528 2529 while (ISpKeyIsPressed(kISp1PA) || 2530 ISpKeyIsPressed(kISp2PA) || 2531 ISpKeyIsPressed(kISp1PB) || 2532 ISpKeyIsPressed(kISp2PB) || 2533 ISpKeyIsPressed(kISp1PX) || 2534 ISpKeyIsPressed(kISp2PX) || 2535 ISpKeyIsPressed(kISp1PY) || 2536 ISpKeyIsPressed(kISp2PY)) 2537 result = current_selection; 2538 } 2539 2540 usleep(30000); 2541 2542 windowResizeCount = 2; 2543 UpdateFreezeDefrostScreen(current_selection, image, draw, ctx); 2544 } while (result == -2); 2545 2546 CocoaPlayFreezeDefrostSound(); 2547 2548 CGContextRelease(ctx); 2549 CGImageRelease(image); 2550 CGColorSpaceRelease(color); 2551 free(draw); 2552 free(back); 2553 2554 S9xSetSoundMute(false); 2555 2556 inactiveMode = oldInactiveMode; 2557 frzselecting = false; 2558 2559 windowResizeCount = 2; 2560 2561 return (result); 2562} 2563 2564static void UpdateFreezeDefrostScreen (int newIndex, CGImageRef image, uint8 *draw, CGContextRef ctx) 2565{ 2566 if (newIndex >= 0 && newIndex < 12) 2567 { 2568 CGRect rct; 2569 const int w = SNES_WIDTH << 1, h = kMacWindowHeight; 2570 2571 CGContextSetLineWidth(ctx, 1.0f); 2572 2573 rct = CGRectMake(0.0f, 0.0f, (float) w, (float) h); 2574 CGContextDrawImage(ctx, rct, image); 2575 2576 rct = CGRectMake(0.0f, (float) h - 238.0f, 128.0f, 120.0f); 2577 rct = CGRectOffset(rct, (float) (128 * (newIndex % 4)), (float) (-120 * (newIndex / 4))); 2578 rct.size.width -= 1.0f; 2579 rct.size.height -= 1.0f; 2580 2581 CGContextSetRGBStrokeColor(ctx, 1.0f, 1.0f, 0.0f, 1.0f); 2582 CGContextStrokeRect(ctx, rct); 2583 rct = CGRectInset(rct, 1.0f, 1.0f); 2584 CGContextSetRGBStrokeColor(ctx, 0.0f, 0.0f, 0.0f, 1.0f); 2585 CGContextStrokeRect(ctx, rct); 2586 } 2587 2588 DrawFreezeDefrostScreen(draw); 2589} 2590 2591static void ProcessInput (void) 2592{ 2593 KeyMap myKeys; 2594 bool8 isok, fnbtn, altbtn, tcbtn; 2595 static bool8 toggleff = false, lastTimeTT = false, lastTimeFn = false, ffUp = false, ffDown = false, ffUpSp = false, ffDownSp = false; 2596 2597 if (rejectinput) 2598 return; 2599 2600 if (ISpKeyIsPressed(kISpEsc)) 2601 { 2602 if (s9xthreadrunning) 2603 { 2604 if (!eventQueued) 2605 { 2606 PostQueueToSubEventLoop(); 2607 eventQueued = true; 2608 } 2609 } 2610 else 2611 running = false; 2612 2613 return; 2614 } 2615 2616 if (ISpKeyIsPressed(kISpFreeze)) 2617 { 2618 MacStopSound(); 2619 while (ISpKeyIsPressed(kISpFreeze)); 2620 2621 isok = SNES9X_Freeze(); 2622 ClearGFXScreen(); 2623 return; 2624 } 2625 2626 if (ISpKeyIsPressed(kISpDefrost)) 2627 { 2628 MacStopSound(); 2629 while (ISpKeyIsPressed(kISpDefrost)); 2630 2631 isok = SNES9X_Defrost(); 2632 ClearGFXScreen(); 2633 return; 2634 } 2635 2636 if (ISpKeyIsPressed(kISpScreenshot)) 2637 { 2638 Settings.TakeScreenshot = true; 2639 while (ISpKeyIsPressed(kISpScreenshot)); 2640 } 2641 2642 if (ISpKeyIsPressed(kISpSPC)) 2643 { 2644 S9xDumpSPCSnapshot(); 2645 while (ISpKeyIsPressed(kISpSPC)); 2646 } 2647 2648 if (ISpKeyIsPressed(kISpFFUp)) 2649 { 2650 if (!ffUpSp) 2651 { 2652 ChangeTurboRate(+1); 2653 ffUpSp = true; 2654 } 2655 } 2656 else 2657 ffUpSp = false; 2658 2659 if (ISpKeyIsPressed(kISpFFDown)) 2660 { 2661 if (!ffDownSp) 2662 { 2663 ChangeTurboRate(-1); 2664 ffDownSp = true; 2665 } 2666 } 2667 else 2668 ffDownSp = false; 2669 2670 controlPad[0] = controlPad[1] = 0; 2671 2672 JoypadScanDirection(0, &(controlPad[0])); 2673 if (ISpKeyIsPressed(kISp1PR )) controlPad[0] |= 0x0010; 2674 if (ISpKeyIsPressed(kISp1PL )) controlPad[0] |= 0x0020; 2675 if (ISpKeyIsPressed(kISp1PX )) controlPad[0] |= 0x0040; 2676 if (ISpKeyIsPressed(kISp1PA )) controlPad[0] |= 0x0080; 2677 if (ISpKeyIsPressed(kISp1PStart )) controlPad[0] |= 0x1000; 2678 if (ISpKeyIsPressed(kISp1PSelect)) controlPad[0] |= 0x2000; 2679 if (ISpKeyIsPressed(kISp1PY )) controlPad[0] |= 0x4000; 2680 if (ISpKeyIsPressed(kISp1PB )) controlPad[0] |= 0x8000; 2681 2682 JoypadScanDirection(1, &(controlPad[1])); 2683 if (ISpKeyIsPressed(kISp2PR )) controlPad[1] |= 0x0010; 2684 if (ISpKeyIsPressed(kISp2PL )) controlPad[1] |= 0x0020; 2685 if (ISpKeyIsPressed(kISp2PX )) controlPad[1] |= 0x0040; 2686 if (ISpKeyIsPressed(kISp2PA )) controlPad[1] |= 0x0080; 2687 if (ISpKeyIsPressed(kISp2PStart )) controlPad[1] |= 0x1000; 2688 if (ISpKeyIsPressed(kISp2PSelect)) controlPad[1] |= 0x2000; 2689 if (ISpKeyIsPressed(kISp2PY )) controlPad[1] |= 0x4000; 2690 if (ISpKeyIsPressed(kISp2PB )) controlPad[1] |= 0x8000; 2691 2692 if (((macControllerOption == SNES_MULTIPLAYER5) || (macControllerOption == SNES_MULTIPLAYER5_2)) && Settings.MultiPlayer5Master) 2693 { 2694 controlPad[2] = controlPad[3] = controlPad[4] = 0; 2695 2696 JoypadScanDirection(2, &(controlPad[2])); 2697 if (ISpKeyIsPressed(kISp3PR )) controlPad[2] |= 0x0010; 2698 if (ISpKeyIsPressed(kISp3PL )) controlPad[2] |= 0x0020; 2699 if (ISpKeyIsPressed(kISp3PX )) controlPad[2] |= 0x0040; 2700 if (ISpKeyIsPressed(kISp3PA )) controlPad[2] |= 0x0080; 2701 if (ISpKeyIsPressed(kISp3PStart )) controlPad[2] |= 0x1000; 2702 if (ISpKeyIsPressed(kISp3PSelect)) controlPad[2] |= 0x2000; 2703 if (ISpKeyIsPressed(kISp3PY )) controlPad[2] |= 0x4000; 2704 if (ISpKeyIsPressed(kISp3PB )) controlPad[2] |= 0x8000; 2705 2706 JoypadScanDirection(3, &(controlPad[3])); 2707 if (ISpKeyIsPressed(kISp4PR )) controlPad[3] |= 0x0010; 2708 if (ISpKeyIsPressed(kISp4PL )) controlPad[3] |= 0x0020; 2709 if (ISpKeyIsPressed(kISp4PX )) controlPad[3] |= 0x0040; 2710 if (ISpKeyIsPressed(kISp4PA )) controlPad[3] |= 0x0080; 2711 if (ISpKeyIsPressed(kISp4PStart )) controlPad[3] |= 0x1000; 2712 if (ISpKeyIsPressed(kISp4PSelect)) controlPad[3] |= 0x2000; 2713 if (ISpKeyIsPressed(kISp4PY )) controlPad[3] |= 0x4000; 2714 if (ISpKeyIsPressed(kISp4PB )) controlPad[3] |= 0x8000; 2715 2716 JoypadScanDirection(4, &(controlPad[4])); 2717 if (ISpKeyIsPressed(kISp5PR )) controlPad[4] |= 0x0010; 2718 if (ISpKeyIsPressed(kISp5PL )) controlPad[4] |= 0x0020; 2719 if (ISpKeyIsPressed(kISp5PX )) controlPad[4] |= 0x0040; 2720 if (ISpKeyIsPressed(kISp5PA )) controlPad[4] |= 0x0080; 2721 if (ISpKeyIsPressed(kISp5PStart )) controlPad[4] |= 0x1000; 2722 if (ISpKeyIsPressed(kISp5PSelect)) controlPad[4] |= 0x2000; 2723 if (ISpKeyIsPressed(kISp5PY )) controlPad[4] |= 0x4000; 2724 if (ISpKeyIsPressed(kISp5PB )) controlPad[4] |= 0x8000; 2725 2726 ControlPadFlagsToS9xReportButtons(2, controlPad[2]); 2727 ControlPadFlagsToS9xReportButtons(3, controlPad[3]); 2728 ControlPadFlagsToS9xReportButtons(4, controlPad[4]); 2729 2730 if (macControllerOption == SNES_MULTIPLAYER5_2) 2731 { 2732 controlPad[5] = controlPad[6] = controlPad[7] = 0; 2733 2734 JoypadScanDirection(5, &(controlPad[5])); 2735 if (ISpKeyIsPressed(kISp6PR )) controlPad[5] |= 0x0010; 2736 if (ISpKeyIsPressed(kISp6PL )) controlPad[5] |= 0x0020; 2737 if (ISpKeyIsPressed(kISp6PX )) controlPad[5] |= 0x0040; 2738 if (ISpKeyIsPressed(kISp6PA )) controlPad[5] |= 0x0080; 2739 if (ISpKeyIsPressed(kISp6PStart )) controlPad[5] |= 0x1000; 2740 if (ISpKeyIsPressed(kISp6PSelect)) controlPad[5] |= 0x2000; 2741 if (ISpKeyIsPressed(kISp6PY )) controlPad[5] |= 0x4000; 2742 if (ISpKeyIsPressed(kISp6PB )) controlPad[5] |= 0x8000; 2743 2744 JoypadScanDirection(6, &(controlPad[6])); 2745 if (ISpKeyIsPressed(kISp7PR )) controlPad[6] |= 0x0010; 2746 if (ISpKeyIsPressed(kISp7PL )) controlPad[6] |= 0x0020; 2747 if (ISpKeyIsPressed(kISp7PX )) controlPad[6] |= 0x0040; 2748 if (ISpKeyIsPressed(kISp7PA )) controlPad[6] |= 0x0080; 2749 if (ISpKeyIsPressed(kISp7PStart )) controlPad[6] |= 0x1000; 2750 if (ISpKeyIsPressed(kISp7PSelect)) controlPad[6] |= 0x2000; 2751 if (ISpKeyIsPressed(kISp7PY )) controlPad[6] |= 0x4000; 2752 if (ISpKeyIsPressed(kISp7PB )) controlPad[6] |= 0x8000; 2753 2754 JoypadScanDirection(7, &(controlPad[7])); 2755 if (ISpKeyIsPressed(kISp8PR )) controlPad[7] |= 0x0010; 2756 if (ISpKeyIsPressed(kISp8PL )) controlPad[7] |= 0x0020; 2757 if (ISpKeyIsPressed(kISp8PX )) controlPad[7] |= 0x0040; 2758 if (ISpKeyIsPressed(kISp8PA )) controlPad[7] |= 0x0080; 2759 if (ISpKeyIsPressed(kISp8PStart )) controlPad[7] |= 0x1000; 2760 if (ISpKeyIsPressed(kISp8PSelect)) controlPad[7] |= 0x2000; 2761 if (ISpKeyIsPressed(kISp8PY )) controlPad[7] |= 0x4000; 2762 if (ISpKeyIsPressed(kISp8PB )) controlPad[7] |= 0x8000; 2763 2764 ControlPadFlagsToS9xReportButtons(5, controlPad[5]); 2765 ControlPadFlagsToS9xReportButtons(6, controlPad[6]); 2766 ControlPadFlagsToS9xReportButtons(7, controlPad[7]); 2767 } 2768 } 2769 2770 GetKeys(myKeys); 2771 2772 fnbtn = (KeyIsPressed(myKeys, keyCode[kKeyFunction]) || ISpKeyIsPressed(kISpFunction)); 2773 altbtn = (KeyIsPressed(myKeys, keyCode[kKeyAlt] ) || ISpKeyIsPressed(kISpAlt) ); 2774 2775 if (fnbtn) 2776 { 2777 if (!lastTimeFn) 2778 { 2779 for (unsigned int i = 0; i < kCommandListSize; i++) 2780 btncmd[i].held = false; 2781 } 2782 2783 lastTimeFn = true; 2784 lastTimeTT = false; 2785 ffUp = ffDown = false; 2786 2787 for (unsigned int i = 0; i < kCommandListSize; i++) 2788 { 2789 if (KeyIsPressed(myKeys, btncmd[i].keycode)) 2790 { 2791 if (!(btncmd[i].held)) 2792 { 2793 btncmd[i].held = true; 2794 2795 if (strncmp(btncmd[i].command, "_mac", 4) == 0) 2796 { 2797 static char msg[64]; 2798 2799 switch (btncmd[i].command[4] - '0') 2800 { 2801 case 1: 2802 Settings.DisplayPressedKeys = !Settings.DisplayPressedKeys; 2803 break; 2804 2805 case 2: 2806 if (S9xMovieActive()) 2807 Settings.DisplayMovieFrame = !Settings.DisplayMovieFrame; 2808 break; 2809 2810 case 3: 2811 if (macFrameAdvanceRate < 5000000) 2812 macFrameAdvanceRate += 100000; 2813 sprintf(msg, "Emulation Speed: 100/%d", macFrameAdvanceRate / 10000); 2814 S9xSetInfoString(msg); 2815 break; 2816 2817 case 4: 2818 if (macFrameAdvanceRate > 500000) 2819 macFrameAdvanceRate -= 100000; 2820 sprintf(msg, "Emulation Speed: 100/%d", macFrameAdvanceRate / 10000); 2821 S9xSetInfoString(msg); 2822 break; 2823 2824 case 5: 2825 pauseEmulation = !pauseEmulation; 2826 break; 2827 2828 case 6: 2829 frameAdvance = true; 2830 break; 2831 } 2832 } 2833 else 2834 { 2835 s9xcommand_t s9xcmd; 2836 2837 s9xcmd = S9xGetCommandT(btncmd[i].command); 2838 S9xApplyCommand(s9xcmd, 1, 0); 2839 } 2840 } 2841 } 2842 else 2843 btncmd[i].held = false; 2844 } 2845 } 2846 else 2847 { 2848 lastTimeFn = false; 2849 2850 if (KeyIsPressed(myKeys, keyCode[kKeyEsc])) 2851 { 2852 if (s9xthreadrunning) 2853 { 2854 if (!eventQueued) 2855 { 2856 PostQueueToSubEventLoop(); 2857 eventQueued = true; 2858 } 2859 } 2860 else 2861 running = false; 2862 2863 return; 2864 } 2865 2866 if (KeyIsPressed(myKeys, keyCode[kKeyFreeze])) 2867 { 2868 MacStopSound(); 2869 while (KeyIsPressed(myKeys, keyCode[kKeyFreeze])) 2870 GetKeys(myKeys); 2871 2872 isok = SNES9X_Freeze(); 2873 ClearGFXScreen(); 2874 return; 2875 } 2876 2877 if (KeyIsPressed(myKeys, keyCode[kKeyDefrost])) 2878 { 2879 MacStopSound(); 2880 while (KeyIsPressed(myKeys, keyCode[kKeyDefrost])) 2881 GetKeys(myKeys); 2882 2883 isok = SNES9X_Defrost(); 2884 ClearGFXScreen(); 2885 return; 2886 } 2887 2888 if (KeyIsPressed(myKeys, keyCode[kKeyScreenshot])) 2889 { 2890 Settings.TakeScreenshot = true; 2891 while (KeyIsPressed(myKeys, keyCode[kKeyScreenshot])) 2892 GetKeys(myKeys); 2893 } 2894 2895 if (KeyIsPressed(myKeys, keyCode[kKeySPC])) 2896 { 2897 S9xDumpSPCSnapshot(); 2898 while (KeyIsPressed(myKeys, keyCode[kKeySPC])) 2899 GetKeys(myKeys); 2900 } 2901 2902 if (KeyIsPressed(myKeys, keyCode[kKeyFFUp])) 2903 { 2904 if (!ffUp) 2905 { 2906 ChangeTurboRate(+1); 2907 ffUp = true; 2908 } 2909 } 2910 else 2911 ffUp = false; 2912 2913 if (KeyIsPressed(myKeys, keyCode[kKeyFFDown])) 2914 { 2915 if (!ffDown) 2916 { 2917 ChangeTurboRate(-1); 2918 ffDown = true; 2919 } 2920 } 2921 else 2922 ffDown = false; 2923 2924 if (KeyIsPressed(myKeys, keyCode[k1PR] )) controlPad[0] |= 0x0010; 2925 if (KeyIsPressed(myKeys, keyCode[k1PL] )) controlPad[0] |= 0x0020; 2926 if (KeyIsPressed(myKeys, keyCode[k1PX] )) controlPad[0] |= 0x0040; 2927 if (KeyIsPressed(myKeys, keyCode[k1PA] )) controlPad[0] |= 0x0080; 2928 if (KeyIsPressed(myKeys, keyCode[k1PRight] )) controlPad[0] |= 0x0100; 2929 if (KeyIsPressed(myKeys, keyCode[k1PLeft] )) controlPad[0] |= 0x0200; 2930 if (KeyIsPressed(myKeys, keyCode[k1PDown] )) controlPad[0] |= 0x0400; 2931 if (KeyIsPressed(myKeys, keyCode[k1PUp] )) controlPad[0] |= 0x0800; 2932 if (KeyIsPressed(myKeys, keyCode[k1PStart] )) controlPad[0] |= 0x1000; 2933 if (KeyIsPressed(myKeys, keyCode[k1PSelect])) controlPad[0] |= 0x2000; 2934 if (KeyIsPressed(myKeys, keyCode[k1PY] )) controlPad[0] |= 0x4000; 2935 if (KeyIsPressed(myKeys, keyCode[k1PB] )) controlPad[0] |= 0x8000; 2936 2937 if (KeyIsPressed(myKeys, keyCode[k2PR] )) controlPad[1] |= 0x0010; 2938 if (KeyIsPressed(myKeys, keyCode[k2PL] )) controlPad[1] |= 0x0020; 2939 if (KeyIsPressed(myKeys, keyCode[k2PX] )) controlPad[1] |= 0x0040; 2940 if (KeyIsPressed(myKeys, keyCode[k2PA] )) controlPad[1] |= 0x0080; 2941 if (KeyIsPressed(myKeys, keyCode[k2PRight] )) controlPad[1] |= 0x0100; 2942 if (KeyIsPressed(myKeys, keyCode[k2PLeft] )) controlPad[1] |= 0x0200; 2943 if (KeyIsPressed(myKeys, keyCode[k2PDown] )) controlPad[1] |= 0x0400; 2944 if (KeyIsPressed(myKeys, keyCode[k2PUp] )) controlPad[1] |= 0x0800; 2945 if (KeyIsPressed(myKeys, keyCode[k2PStart] )) controlPad[1] |= 0x1000; 2946 if (KeyIsPressed(myKeys, keyCode[k2PSelect])) controlPad[1] |= 0x2000; 2947 if (KeyIsPressed(myKeys, keyCode[k2PY] )) controlPad[1] |= 0x4000; 2948 if (KeyIsPressed(myKeys, keyCode[k2PB] )) controlPad[1] |= 0x8000; 2949 2950 if (altbtn) 2951 { 2952 if (!lastTimeTT) 2953 changeAuto[0] = changeAuto[1] = 0; 2954 2955 for (int i = 0; i < 2; i++) 2956 { 2957 for (int j = 0; j < 12; j++) 2958 { 2959 uint16 mask = 0x0010 << j; 2960 2961 if (controlPad[i] & mask & autofireRec[i].toggleMask) 2962 { 2963 controlPad[i] &= ~mask; 2964 2965 if (!(changeAuto[i] & mask)) 2966 { 2967 changeAuto[i] |= mask; 2968 ChangeAutofireSettings(i, j); 2969 } 2970 } 2971 else 2972 changeAuto[i] &= ~mask; 2973 } 2974 } 2975 2976 lastTimeTT = true; 2977 } 2978 else 2979 lastTimeTT = false; 2980 } 2981 2982 if (enabletoggle) 2983 { 2984 if ((ISpKeyIsPressed(kISpFastForward) || KeyIsPressed(myKeys, keyCode[kKeyFastForward])) && !fnbtn) 2985 { 2986 if (!toggleff) 2987 { 2988 toggleff = true; 2989 Settings.TurboMode = !Settings.TurboMode; 2990 S9xSetInfoString(Settings.TurboMode ? "Turbo mode on" : "Turbo mode off"); 2991 if (!Settings.TurboMode) 2992 S9xClearSamples(); 2993 } 2994 } 2995 else 2996 toggleff = false; 2997 } 2998 else 2999 { 3000 bool8 old = Settings.TurboMode; 3001 Settings.TurboMode = ((ISpKeyIsPressed(kISpFastForward) || KeyIsPressed(myKeys, keyCode[kKeyFastForward])) && !fnbtn) ? true : false; 3002 if (!Settings.TurboMode && old) 3003 S9xClearSamples(); 3004 } 3005 3006 for (int i = 0; i < 2; i++) 3007 controlPad[i] ^= autofireRec[i].invertMask; 3008 3009 if (autofire) 3010 { 3011 long long currentTime; 3012 uint16 changeMask; 3013 3014 Microseconds((UnsignedWide *) ¤tTime); 3015 tcbtn = (KeyIsPressed(myKeys, keyCode[kKeyTC]) || ISpKeyIsPressed(kISpTC)); 3016 3017 for (int i = 0; i < 2; i++) 3018 { 3019 changeMask = (lastTimeTT ? (~changeAuto[i]) : 0xFFFF); 3020 3021 for (int j = 0; j < 12; j++) 3022 { 3023 uint16 mask = (0x0010 << j) & changeMask; 3024 3025 if (autofireRec[i].tcMask & mask) 3026 { 3027 if (!tcbtn) 3028 continue; 3029 } 3030 3031 if (autofireRec[i].buttonMask & mask) 3032 { 3033 if (controlPad[i] & mask) 3034 { 3035 if (currentTime > autofireRec[i].nextTime[j]) 3036 { 3037 if (Settings.TurboMode) 3038 autofireRec[i].nextTime[j] = currentTime + (long long) ((1.0 / (float) autofireRec[i].frequency) * 1000000.0 / macFastForwardRate); 3039 else 3040 autofireRec[i].nextTime[j] = currentTime + (long long) ((1.0 / (float) autofireRec[i].frequency) * 1000000.0); 3041 } 3042 else 3043 controlPad[i] &= ~mask; 3044 } 3045 } 3046 } 3047 } 3048 } 3049 3050 ControlPadFlagsToS9xReportButtons(0, controlPad[0]); 3051 ControlPadFlagsToS9xReportButtons(1, controlPad[1]); 3052 3053 if (macControllerOption == SNES_JUSTIFIER_2) 3054 ControlPadFlagsToS9xPseudoPointer(controlPad[1]); 3055} 3056 3057static void ChangeAutofireSettings (int player, int btn) 3058{ 3059 static char msg[64]; 3060 uint16 mask, m; 3061 3062 mask = 0x0010 << btn; 3063 autofireRec[player].buttonMask ^= mask; 3064 autofire = (autofireRec[0].buttonMask || autofireRec[1].buttonMask); 3065 3066 m = autofireRec[player].buttonMask; 3067 if (m) 3068 snprintf(msg, sizeof(msg), "Autofire %d:%s%s%s%s%s%s%s%s%s%s%s%s%s", player + 1, 3069 (m & 0xC0F0 ? " " : ""), 3070 (m & 0x0080 ? "A" : ""), 3071 (m & 0x8000 ? "B" : ""), 3072 (m & 0x0040 ? "X" : ""), 3073 (m & 0x4000 ? "Y" : ""), 3074 (m & 0x0020 ? "L" : ""), 3075 (m & 0x0010 ? "R" : ""), 3076 (m & 0x0800 ? " Up" : ""), 3077 (m & 0x0400 ? " Dn" : ""), 3078 (m & 0x0200 ? " Lf" : ""), 3079 (m & 0x0100 ? " Rt" : ""), 3080 (m & 0x1000 ? " St" : ""), 3081 (m & 0x2000 ? " Se" : "")); 3082 else 3083 snprintf(msg, sizeof(msg), "Autofire %d: Off", player + 1); 3084 3085 S9xSetInfoString(msg); 3086} 3087 3088static void ChangeTurboRate (int d) 3089{ 3090 static char msg[64]; 3091 3092 macFastForwardRate += d; 3093 if (macFastForwardRate < 1) 3094 macFastForwardRate = 1; 3095 else 3096 if (macFastForwardRate > 15) 3097 macFastForwardRate = 15; 3098 3099 snprintf(msg, sizeof(msg), "Turbo Rate: %d", macFastForwardRate); 3100 S9xSetInfoString(msg); 3101} 3102 3103void GetGameScreenPointer (int16 *x, int16 *y, bool fullmouse) 3104{ 3105 int ph; 3106 3107 ph = !drawoverscan ? ((IPPU.RenderedScreenHeight > 256) ? IPPU.RenderedScreenHeight : (IPPU.RenderedScreenHeight << 1)) : (SNES_HEIGHT_EXTENDED << 1); 3108 3109 if (fullscreen) 3110 { 3111 if (glstretch) 3112 { 3113 float fpw = (float) glScreenH / (float) ph * 512.0f; 3114 3115 scopeViewInfo.width = (int) (fpw + ((float) glScreenW - fpw) * (float) macAspectRatio / 10000.0); 3116 scopeViewInfo.height = glScreenH; 3117 scopeViewInfo.globalLeft = (int) glScreenBounds.origin.x + ((glScreenW - scopeViewInfo.width) >> 1); 3118 scopeViewInfo.globalTop = (int) glScreenBounds.origin.y; 3119 } 3120 else 3121 { 3122 scopeViewInfo.width = 512; 3123 scopeViewInfo.height = ph; 3124 scopeViewInfo.globalLeft = (int) glScreenBounds.origin.x + ((glScreenW - 512) >> 1); 3125 scopeViewInfo.globalTop = (int) glScreenBounds.origin.y + ((glScreenH - ph ) >> 1); 3126 } 3127 } 3128 else 3129 { 3130 Rect rct; 3131 3132 GetWindowBounds(gWindow, kWindowContentRgn, &rct); 3133 3134 int ww = rct.right - rct.left, 3135 wh = rct.bottom - rct.top; 3136 3137 scopeViewInfo.width = ww; 3138 scopeViewInfo.globalLeft = rct.left; 3139 3140 if (windowExtend) 3141 { 3142 scopeViewInfo.height = ph * wh / kMacWindowHeight; 3143 scopeViewInfo.globalTop = rct.top + ((kMacWindowHeight - ph) >> 1) * wh / kMacWindowHeight; 3144 } 3145 else 3146 { 3147 scopeViewInfo.height = wh; 3148 scopeViewInfo.globalTop = rct.top; 3149 } 3150 } 3151 3152 if (!fullmouse) 3153 { 3154 Point pos; 3155 3156 GetGlobalMouse(&pos); 3157 3158 *x = (int16) (((float) (pos.h - scopeViewInfo.globalLeft)) / ((float) scopeViewInfo.width ) * (float) IPPU.RenderedScreenWidth); 3159 *y = (int16) (((float) (pos.v - scopeViewInfo.globalTop )) / ((float) scopeViewInfo.height) * (float) (!drawoverscan ? IPPU.RenderedScreenHeight : SNES_HEIGHT_EXTENDED)); 3160 } 3161 else 3162 { 3163 *x = (int16) (unlimitedCursor.x / (float) scopeViewInfo.width * (float) IPPU.RenderedScreenWidth); 3164 *y = (int16) (unlimitedCursor.y / (float) scopeViewInfo.height * (float) (!drawoverscan ? IPPU.RenderedScreenHeight : SNES_HEIGHT_EXTENDED)); 3165 } 3166} 3167 3168static void Initialize (void) 3169{ 3170 OSStatus err; 3171 IBNibRef menuNibRef; 3172 MenuRef menu; 3173 SInt32 qtVersion; 3174 3175 printf("\nSnes9x for Mac OS X %s (%s), ", VERSION, MAC_VERSION); 3176#ifdef __BIG_ENDIAN__ 3177 printf("PowerPC\n\n"); 3178#else 3179 printf("Intel\n\n"); 3180#endif 3181 3182 err = Gestalt(gestaltSystemVersion, &systemVersion); 3183 err = Gestalt(gestaltQuickTimeVersion, &qtVersion); 3184 3185 if ((systemVersion < 0x1039) || (qtVersion < 0x07008000)) 3186 { 3187 AppearanceAlert(kAlertStopAlert, kS9xMacAlertRequiredSystem, kS9xMacAlertRequiredSystemHint); 3188 QuitWithFatalError(0, "os 09"); 3189 } 3190 3191 printf("OS: %x QuickTime: %x\n\n", (unsigned) systemVersion, (unsigned) qtVersion); 3192 3193#ifdef ZLIB 3194 printf("zlib header version: %s\n\n", ZLIB_VERSION); 3195#endif 3196 3197 NSApplicationLoad(); 3198 3199 ZeroMemory(&Settings, sizeof(Settings)); 3200 Settings.MouseMaster = true; 3201 Settings.SuperScopeMaster = true; 3202 Settings.JustifierMaster = true; 3203 Settings.MultiPlayer5Master = true; 3204 Settings.FrameTimePAL = 20000; 3205 Settings.FrameTimeNTSC = 16667; 3206 Settings.SixteenBitSound = true; 3207 Settings.Stereo = true; 3208 Settings.SoundPlaybackRate = 32000; 3209 Settings.SoundInputRate = 32000; 3210 Settings.SupportHiRes = true; 3211 Settings.Transparency = true; 3212 Settings.AutoDisplayMessages = true; 3213 Settings.InitialInfoStringTimeout = 120; 3214 Settings.HDMATimingHack = 100; 3215 Settings.BlockInvalidVRAMAccessMaster = true; 3216 Settings.StopEmulation = true; 3217 Settings.WrongMovieStateProtection = true; 3218 Settings.DumpStreamsMaxFrames = -1; 3219 Settings.StretchScreenshots = 1; 3220 Settings.SnapshotScreenshots = true; 3221 Settings.OpenGLEnable = true; 3222 3223 for (int a = 0; a < kWindowCount; a++) 3224 { 3225 windowPos[a].h = 40; 3226 windowPos[a].v = 80; 3227 windowSize[a].width = -1.0f; 3228 windowSize[a].height = -1.0f; 3229 } 3230 3231 extraOptions.benchmark = false; 3232 extraOptions.glForceNoTextureRectangle = false; 3233 extraOptions.glUseClientStrageApple = true; 3234 extraOptions.glUseTexturePriority = false; 3235 extraOptions.glStorageHint = 2; 3236 3237 npServerIP[0] = 0; 3238 npName[0] = 0; 3239 3240 saveFolderPath = NULL; 3241 3242 CreateIconImages(); 3243 3244 InitAppleEvents(); 3245 InitKeyboard(); 3246 InitAutofire(); 3247 InitCheatFinder(); 3248 3249 LoadPrefs(); 3250 3251 InitGraphics(); 3252 InitMacSound(); 3253 SetUpHID(); 3254 3255 RegisterHelpBook(); 3256 3257 if (systemVersion < 0x1040) 3258 ciFilterEnable = false; 3259 3260 err = CreateNibReference(kMacS9XCFString, &menuNibRef); 3261 err = SetMenuBarFromNib(menuNibRef, CFSTR("MenuBar")); 3262 DisposeNibReference(menuNibRef); 3263 3264 EnableMenuCommand(NULL, kHICommandPreferences); 3265 3266 DisableMenuItem(GetMenuRef(mEdit), 0); 3267 3268 CheckMenuItem(GetMenuRef(mCheat), iApplyCheats, applycheat); 3269 Settings.ApplyCheats = applycheat; 3270 3271 err = GetMenuItemHierarchicalMenu(GetMenuRef(mControl), iISpPreset, &menu); 3272 CheckMenuItem(menu, padSetting, true); 3273 3274 err = GetMenuItemHierarchicalMenu(GetMenuRef(mEmulation), iDevice, &menu); 3275 CheckMenuItem(menu, deviceSetting, true); 3276 deviceSettingMaster = deviceSetting; 3277 3278 DisableMenuItem(GetMenuRef(mOption), iCIFilter); 3279 3280 InitRecentItems(); 3281 InitRecentMenu(); 3282 BuildRecentMenu(); 3283 3284 InitMultiCart(); 3285 3286 DrawMenuBar(); 3287 3288 autofire = (autofireRec[0].buttonMask || autofireRec[1].buttonMask) ? true : false; 3289 for (int a = 0; a < MAC_MAX_PLAYERS; a++) 3290 for (int b = 0; b < 12; b++) 3291 autofireRec[a].nextTime[b] = 0; 3292 3293 S9xMovieInit(); 3294 3295 S9xUnmapAllControls(); 3296 S9xSetupDefaultKeymap(); 3297 ChangeInputDevice(); 3298 3299 err = EnterMovies(); 3300 3301 if (!Memory.Init() || !S9xInitAPU() || !S9xGraphicsInit()) 3302 QuitWithFatalError(err, "os 01"); 3303 3304 frzselecting = false; 3305 3306 S9xSetControllerCrosshair(X_MOUSE1, 0, NULL, NULL); 3307 S9xSetControllerCrosshair(X_MOUSE2, 0, NULL, NULL); 3308 3309 if (systemVersion >= 0x1040) 3310 { 3311 InitCoreImage(); 3312 InitCoreImageFilter(); 3313 } 3314} 3315 3316static void Deinitialize (void) 3317{ 3318 if (systemVersion >= 0x1040) 3319 { 3320 DeinitCoreImageFilter(); 3321 DeinitCoreImage(); 3322 } 3323 3324 deviceSetting = deviceSettingMaster; 3325 3326 ExitMovies(); 3327 3328 DeinitMultiCart(); 3329 DeinitRecentMenu(); 3330 DeinitRecentItems(); 3331 SavePrefs(); 3332 ReleaseHID(); 3333 DeinitCheatFinder(); 3334 DeinitGraphics(); 3335 DeinitKeyboard(); 3336 DeinitMacSound(); 3337 DeinitAppleEvents(); 3338 ReleaseIconImages(); 3339 3340 S9xGraphicsDeinit(); 3341 S9xDeinitAPU(); 3342 Memory.Deinit(); 3343} 3344 3345static void InitAutofire (void) 3346{ 3347 autofire = false; 3348 3349 for (int i = 0; i < 2; i++) 3350 { 3351 for (int j = 0; j < 12; j++) 3352 autofireRec[i].nextTime[j] = 0; 3353 3354 autofireRec[i].buttonMask = 0x0000; 3355 autofireRec[i].toggleMask = 0xFFF0; 3356 autofireRec[i].tcMask = 0x0000; 3357 autofireRec[i].invertMask = 0x0000; 3358 autofireRec[i].frequency = 10; 3359 } 3360} 3361 3362static void ForceChangingKeyScript (void) 3363{ 3364 if (systemVersion >= 0x1050) 3365 { 3366 OSStatus err; 3367 TISInputSourceRef tis; 3368 3369 tis = TISCopyCurrentASCIICapableKeyboardInputSource(); 3370 err = TISSelectInputSource(tis); 3371 CFRelease(tis); 3372 } 3373#ifdef MAC_TIGER_PANTHER_SUPPORT 3374 else 3375 { 3376 long script; 3377 3378 script = GetScriptManagerVariable(smKeyScript); 3379 if (script == smJapanese) 3380 KeyScript(smRoman | smKeyForceKeyScriptMask); 3381 } 3382#endif 3383} 3384 3385void S9xSyncSpeed (void) 3386{ 3387 long long currentFrame, adjustment; 3388 3389 if (directDisplay) 3390 { 3391 if (extraOptions.benchmark) 3392 IPPU.RenderThisFrame = true; 3393 else 3394 { 3395 if (Settings.SoundSync) 3396 { 3397 while (!S9xSyncSound()) 3398 usleep(0); 3399 } 3400 3401 if (!macQTRecord) 3402 { 3403 if (macFrameSkip < 0) // auto skip 3404 { 3405 skipFrames--; 3406 3407 if (skipFrames <= 0) 3408 { 3409 adjustment = (Settings.TurboMode ? (macFrameAdvanceRate / macFastForwardRate) : macFrameAdvanceRate) / Memory.ROMFramesPerSecond; 3410 Microseconds((UnsignedWide *) ¤tFrame); 3411 3412 skipFrames = (int32) ((currentFrame - lastFrame) / adjustment); 3413 lastFrame += frameCount * adjustment; 3414 3415 if (skipFrames < 1) 3416 skipFrames = 1; 3417 else 3418 if (skipFrames > 7) 3419 { 3420 skipFrames = 7; 3421 Microseconds((UnsignedWide *) &lastFrame); 3422 } 3423 3424 frameCount = skipFrames; 3425 3426 if (lastFrame > currentFrame) 3427 usleep((useconds_t) (lastFrame - currentFrame)); 3428 3429 IPPU.RenderThisFrame = true; 3430 } 3431 else 3432 IPPU.RenderThisFrame = false; 3433 } 3434 else // constant 3435 { 3436 skipFrames--; 3437 3438 if (skipFrames <= 0) 3439 { 3440 adjustment = macFrameAdvanceRate * macFrameSkip / Memory.ROMFramesPerSecond; 3441 Microseconds((UnsignedWide *) ¤tFrame); 3442 3443 if (currentFrame - lastFrame < adjustment) 3444 { 3445 usleep((useconds_t) (adjustment + lastFrame - currentFrame)); 3446 Microseconds((UnsignedWide *) ¤tFrame); 3447 } 3448 3449 lastFrame = currentFrame; 3450 skipFrames = macFrameSkip; 3451 if (Settings.TurboMode) 3452 skipFrames *= macFastForwardRate; 3453 3454 IPPU.RenderThisFrame = true; 3455 } 3456 else 3457 IPPU.RenderThisFrame = false; 3458 } 3459 } 3460 else 3461 { 3462 MacQTRecordFrame(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight); 3463 3464 adjustment = macFrameAdvanceRate / Memory.ROMFramesPerSecond; 3465 Microseconds((UnsignedWide *) ¤tFrame); 3466 3467 if (currentFrame - lastFrame < adjustment) 3468 usleep((useconds_t) (adjustment + lastFrame - currentFrame)); 3469 3470 lastFrame = currentFrame; 3471 3472 IPPU.RenderThisFrame = true; 3473 } 3474 } 3475 } 3476 else 3477 IPPU.RenderThisFrame = false; 3478} 3479 3480void S9xAutoSaveSRAM (void) 3481{ 3482 SNES9X_SaveSRAM(); 3483} 3484 3485void S9xMessage (int type, int number, const char *message) 3486{ 3487 static char mes[256]; 3488 3489 if (!onscreeninfo) 3490 { 3491 printf("%s\n", message); 3492 3493 if ((type == S9X_INFO) && (number == S9X_ROM_INFO)) 3494 if (strstr(message, "checksum ok") == NULL) 3495 AppearanceAlert(kAlertCautionAlert, kS9xMacAlertkBadRom, kS9xMacAlertkBadRomHint); 3496 } 3497 else 3498 { 3499 strncpy(mes, message, 255); 3500 S9xSetInfoString(mes); 3501 } 3502} 3503 3504const char * S9xStringInput (const char *s) 3505{ 3506 return (NULL); 3507} 3508 3509void S9xToggleSoundChannel (int c) 3510{ 3511 static int channel_enable = 255; 3512 3513 if (c == 8) 3514 channel_enable = 255; 3515 else 3516 channel_enable ^= 1 << c; 3517 3518 S9xSetSoundControl(channel_enable); 3519} 3520 3521void S9xExit (void) 3522{ 3523 PlayAlertSound(); 3524 3525 running = false; 3526 cartOpen = false; 3527 3528 QuitApplicationEventLoop(); 3529} 3530 3531void QuitWithFatalError (OSStatus err, const char *msg) 3532{ 3533 printf("Quit. %s err: %ld\n", msg, err); 3534 ExitToShell(); 3535} 3536