diff --git a/macosx/.DS_Store b/macosx/.DS_Store
new file mode 100644
index 00000000..a8ddca29
Binary files /dev/null and b/macosx/.DS_Store differ
diff --git a/macosx/.gitignore b/macosx/.gitignore
new file mode 100644
index 00000000..4e6f89d5
--- /dev/null
+++ b/macosx/.gitignore
@@ -0,0 +1,3 @@
+Build
+.DS_Store
+xcuserdata
diff --git a/macosx/English.lproj/Snes9x Help/pgs/14.html b/macosx/English.lproj/Snes9x Help/pgs/14.html
deleted file mode 100644
index a1c3d064..00000000
--- a/macosx/English.lproj/Snes9x Help/pgs/14.html
+++ /dev/null
@@ -1,118 +0,0 @@
-
-
-
-
-
-
-
- References
-
-
- References
- Preferences Dialog
- Graphics Tab
-
- Full Screen Mode
- Toggles full screen/windowed mode. Press esc key to hide full screen window and pause the game.
- Switch Monitor Resolution
- Toggles between scaling full screen graphics to the current screen resolution or changing the screen resolution to fit Snes9x's needs.
- Show Frame Rate
- Toggles display of the frame rate on/off.
- Transparency Effects
- Toggles transparency effects on/off. Transparency effect is used in almost all games so this option is just for hack.
- Video Mode
- Choose the image scaling filter which is applied to the raw SNES image.
- Multitask
- When this option is on, the rendering process is separated from the emulation thread (except blocky and smooth modes).
- Keep Overscanned Height
- Keeps the screen height always 239/478, for some games that change screen height frequently.
- Sync to Vertical Blank
- Synchronizes the render timing to the monitor's vertical refresh rate.
- Stretch Image in Full Screen Mode
- Stretches the image to fill the screen in full screen mode.
- Aspect Ratio
- The aspect ratio of above option: the left is proportional and the right is full width of the monitor.
- Use Core Image
- Applies additional Core Image effect after the image filter is applied.
- Filter...
- Choose the Core Image filter.
- Use 32 Bit Color
- Uses 16,777,216 colors.
- Use Screen Curvature
- Adds a warp effect like a CRT-based television.
- Warp
- The degree of curvature.
-
- Sound Tab
-
- Synchronize
- Tries and ensures all available samples are buffered so there are no overruns.
- 16 Bit Playback
- Enables 16-bit playback instead of 8-bit.
- Stereo
- Enables stereo sound instead of mono.
- Reverse Stereo
- Swaps the left and right stereo channels.
- Effect...
- Opens 'Sound Effect' dialog.
- Playback Rate
- The real SNES is 32040 Hz. Any values other than 32040 Hz will cause resampling.
- Output Interval
- Make sure this value is smaller than the mix buffer length.
- Mix Buffer Length
- Too short length will cause crackling noise.
- Allow Lag
- Safer from crackling noise, but time-lag becomes more noticeable.
- Volume
- Volume of the whole Snes9x sounds.
- Input Rate
- Adjusts the sound rate through resampling. For every Input Rate samples generated by the SNES, Playback Rate samples will be produced.
-
- File Tab
-
- Save Data in
- Choose the folder where Snes9x will look for files.
- Auto Save SRAM
- Updates SRAM file when SRAM contents are modified. This may cause frequent disk access.
-
- Accuracy Tab
-
- HDMA Timing Hack
- Changes HDMA timing and will 'fix' some games' glitches, but breaks many other games. The default value is 100.
- Skip CPU Emulation Until the Next Event Comes
- Skips internal CPU emulation for speed-ups until the next event comes.
- Allow Invalid VRAM Access
- Allows to write to VRAM outside blank periods.
- Apply Specific Game Hacks
- Applies special hacks for games that can't be emulated correctly.
- Frame Skip
- Adjust this value if your Mac is slow.
- Speed in Turbo Mode
- The speed when turbo mode is on. Modify in-game with Fn+T, Fn+Y.
-
- Others Tab
-
- Toggle Turbo Button
- Sets 'Turbo' button as a toggle switch.
- Show Onscreen Information
- Shows messages from Snes9x on the game screen. When off, messages are put in the standard console.
- Open Choose ROM Image Dialog at Startup
- Choose whether open dialog should be shown when Snes9x is launched.
- Show Dates and Times in Freeze State Selection Screen
- Shows time stamps on thumbnails in freeze/defrost screen.
- Save Window Size and Position
- Saves the sizes and positions of the game window and dialogs so they come back to the same place.
- Use IPS / UPS Patch
- When this option is on, Snes9x automatically loads the .ips or .ups file and patch the ROM image.
- Boot Up BS Games from BS-X
- When this option is on, BS-X ROM is loaded first, then you launch BS games from the menu in BS-X.
- When in Background
- Choose the behavior of Snes9x when it is in back of other applications.
- Music Box
- Choose the behavior of Music Box: 'Sound Emulation Only' to only emulate the music system, and 'Whole Emulation' to also emulate the CPU. Music that depends on the CPU running will not sound right without 'Whole Emulation.'
-
-
-
-
diff --git a/macosx/English.lproj/musicbox.xib b/macosx/English.lproj/musicbox.xib
deleted file mode 100644
index f955ffcb..00000000
--- a/macosx/English.lproj/musicbox.xib
+++ /dev/null
@@ -1,2171 +0,0 @@
-
-
-
- 1040
- 10J869
- 851
- 1038.35
- 461.00
-
- com.apple.InterfaceBuilder.CocoaPlugin
- 851
-
-
- YES
-
-
- YES
- com.apple.InterfaceBuilder.CocoaPlugin
-
-
- YES
-
- YES
-
-
- YES
-
-
-
- YES
-
- MusicBoxController
-
-
- FirstResponder
-
-
- NSApplication
-
-
- 7
- 2
- {{100, 100}, {352, 242}}
- 1685586944
- Music Box
- NSWindow
-
- {352, 242}
- {352, 61}
-
-
- 256
-
- YES
-
-
- 268
-
- YES
-
- YES
- Apple PDF pasteboard type
- Apple PICT pasteboard type
- Apple PNG pasteboard type
- NSFilenamesPboardType
- NeXT Encapsulated PostScript v1.2 pasteboard type
- NeXT TIFF v4.0 pasteboard type
-
-
- {{30, 37}, {262, 142}}
-
-
- YES
-
- 130560
- 33554432
-
- NSImage
- musicbox_indicator
-
- 0
- 2
- 0
- NO
-
- YES
-
-
-
- 268
- {{302, 158}, {30, 22}}
-
-
- YES
-
- 67239424
- 134217728
-
-
- LucidaGrande
- 13
- 1044
-
-
- 918831359
- 34
-
- NSImage
- musicbox_pause
-
-
-
- 400
- 75
-
-
-
-
- 268
- {{302, 134}, {30, 22}}
-
-
- YES
-
- 67239424
- 134217728
-
-
-
- -2033958657
- 34
-
- NSImage
- musicbox_rewind
-
-
-
- 400
- 75
-
-
-
-
- 268
- {{302, 110}, {30, 22}}
-
-
- YES
-
- 67239424
- 134217728
-
-
-
- -2033958657
- 34
-
- NSImage
- musicbox_effect
-
-
-
- 400
- 75
-
-
-
-
- 268
- {{36, 43}, {250, 130}}
-
-
- MusicBoxIndicatorView
-
-
-
- 268
- {{41, 19}, {12, 14}}
-
-
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{111, 19}, {12, 14}}
-
-
- 5
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{55, 19}, {12, 14}}
-
-
- 1
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{69, 19}, {12, 14}}
-
-
- 2
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{83, 19}, {12, 14}}
-
-
- 3
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{97, 19}, {12, 14}}
-
-
- 4
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{139, 19}, {12, 14}}
-
-
- 7
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{125, 19}, {12, 14}}
-
-
- 6
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{171, 19}, {12, 14}}
-
-
- 8
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{241, 19}, {12, 14}}
-
-
- 13
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{185, 19}, {12, 14}}
-
-
- 9
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{199, 19}, {12, 14}}
-
-
- 10
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{213, 19}, {12, 14}}
-
-
- 11
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{227, 19}, {12, 14}}
-
-
- 12
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{269, 19}, {12, 14}}
-
-
- 15
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{255, 19}, {12, 14}}
-
-
- 14
- YES
-
- 67239424
- 134217728
-
-
-
- 918831359
- 34
-
-
- 400
- 75
-
-
-
-
- 268
- {{307, 198}, {29, 26}}
-
-
- YES
-
- -2080244224
- 134217728
-
-
-
- 918831359
- 38
-
-
- 400
- 75
-
-
-
-
- 268
-
- YES
-
- YES
- Apple PDF pasteboard type
- Apple PICT pasteboard type
- Apple PNG pasteboard type
- NSFilenamesPboardType
- NeXT Encapsulated PostScript v1.2 pasteboard type
- NeXT TIFF v4.0 pasteboard type
-
-
- {{153, 18}, {16, 16}}
-
-
- YES
-
- 130560
- 33554432
-
- NSImage
- musicbox_ledoff
-
- 0
- 0
- 0
- NO
-
- YES
-
-
-
- 268
- {{17, 203}, {58, 17}}
-
-
- YES
-
- 67239488
- 272635904
- Playing :
-
-
- YES
- 1
-
- 6
- System
- controlColor
-
- 3
- MC42NjY2NjY2ODY1AA
-
-
-
- 6
- System
- controlTextColor
-
- 3
- MAA
-
-
-
-
-
-
- 268
- {{77, 203}, {218, 17}}
-
-
- YES
-
- 67239488
- 272635904
- Game Title
-
-
- YES
- 1
-
-
-
-
-
- {352, 242}
-
-
-
- {{0, 0}, {1440, 878}}
- {352, 83}
- {352, 264}
-
-
-
-
-
- YES
-
-
- disclosure
-
-
-
- 93
-
-
-
- rewind
-
-
-
- 95
-
-
-
- gametitle
-
-
-
- 113
-
-
-
- indicator
-
-
-
- 114
-
-
-
- led
-
-
-
- 115
-
-
-
- window
-
-
-
- 116
-
-
-
- handlePauseButton:
-
-
-
- 123
-
-
-
- handleRewindButton:
-
-
-
- 124
-
-
-
- handleEffectButton:
-
-
-
- 125
-
-
-
- handleDisclosureButton:
-
-
-
- 126
-
-
-
- handleChannelButton:
-
-
-
- 127
-
-
-
- handleChannelButton:
-
-
-
- 129
-
-
-
- handleChannelButton:
-
-
-
- 130
-
-
-
- handleChannelButton:
-
-
-
- 131
-
-
-
- handleChannelButton:
-
-
-
- 132
-
-
-
- handleChannelButton:
-
-
-
- 133
-
-
-
- handleChannelButton:
-
-
-
- 134
-
-
-
- handleChannelButton:
-
-
-
- 135
-
-
-
- handleChannelButton:
-
-
-
- 136
-
-
-
- handleChannelButton:
-
-
-
- 137
-
-
-
- handleChannelButton:
-
-
-
- 138
-
-
-
- handleChannelButton:
-
-
-
- 139
-
-
-
- handleChannelButton:
-
-
-
- 140
-
-
-
- handleChannelButton:
-
-
-
- 141
-
-
-
- handleChannelButton:
-
-
-
- 142
-
-
-
- handleChannelButton:
-
-
-
- 143
-
-
-
- delegate
-
-
-
- 146
-
-
-
-
- YES
-
- 0
-
-
-
-
-
- -2
-
-
- File's Owner
-
-
- -1
-
-
- First Responder
-
-
- -3
-
-
- Application
-
-
- 2
-
-
- YES
-
-
-
-
-
- 3
-
-
- YES
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
- YES
-
-
-
-
- 14
-
-
- YES
-
-
-
-
-
- 15
-
-
-
-
- 26
-
-
- YES
-
-
-
-
-
- 27
-
-
-
-
- 28
-
-
- YES
-
-
-
-
-
- 29
-
-
-
-
- 30
-
-
- YES
-
-
-
-
-
- 31
-
-
-
-
- 32
-
-
- YES
-
-
-
-
-
- 33
-
-
-
-
- 34
-
-
- YES
-
-
-
-
-
- 35
-
-
-
-
- 36
-
-
- YES
-
-
-
-
-
- 37
-
-
-
-
- 38
-
-
- YES
-
-
-
-
-
- 39
-
-
-
-
- 40
-
-
- YES
-
-
-
-
-
- 41
-
-
- YES
-
-
-
-
-
- 42
-
-
- YES
-
-
-
-
-
- 43
-
-
- YES
-
-
-
-
-
- 44
-
-
- YES
-
-
-
-
-
- 45
-
-
- YES
-
-
-
-
-
- 46
-
-
- YES
-
-
-
-
-
- 47
-
-
- YES
-
-
-
-
-
- 48
-
-
-
-
- 49
-
-
-
-
- 50
-
-
-
-
- 51
-
-
-
-
- 52
-
-
-
-
- 53
-
-
-
-
- 54
-
-
-
-
- 55
-
-
-
-
- 62
-
-
- YES
-
-
-
-
-
- 63
-
-
-
-
- 64
-
-
- YES
-
-
-
-
-
- 65
-
-
-
-
- 66
-
-
- YES
-
-
-
-
-
- 67
-
-
-
-
- 68
-
-
- YES
-
-
-
-
-
- 69
-
-
-
-
- 70
-
-
- YES
-
-
-
-
-
- 71
-
-
-
-
- 72
-
-
- YES
-
-
-
-
-
- 73
-
-
-
-
- 6
-
-
- YES
-
-
-
-
-
- 7
-
-
-
-
- 120
-
-
- YES
-
-
-
-
-
- 121
-
-
-
-
-
-
- YES
-
- YES
- -1.IBPluginDependency
- -2.IBPluginDependency
- -3.IBPluginDependency
- 1.IBEditorWindowLastContentRect
- 1.IBPluginDependency
- 1.IBViewBoundsToFrameTransform
- 1.WindowOrigin
- 1.editorWindowContentRectSynchronizationRect
- 120.IBPluginDependency
- 120.IBViewBoundsToFrameTransform
- 120.IBViewIntegration.shadowColor
- 121.IBPluginDependency
- 14.IBPluginDependency
- 14.IBViewBoundsToFrameTransform
- 15.IBPluginDependency
- 2.IBEditorWindowLastContentRect
- 2.IBPluginDependency
- 2.IBWindowTemplateEditedContentRect
- 2.NSWindowTemplate.visibleAtLaunch
- 2.windowTemplate.hasMaxSize
- 2.windowTemplate.hasMinSize
- 2.windowTemplate.maxSize
- 2.windowTemplate.minSize
- 26.IBPluginDependency
- 26.IBViewBoundsToFrameTransform
- 27.IBPluginDependency
- 28.IBPluginDependency
- 28.IBViewBoundsToFrameTransform
- 29.IBPluginDependency
- 3.IBPluginDependency
- 30.IBPluginDependency
- 30.IBViewBoundsToFrameTransform
- 31.IBPluginDependency
- 32.IBPluginDependency
- 32.IBViewBoundsToFrameTransform
- 33.IBPluginDependency
- 34.IBPluginDependency
- 34.IBViewBoundsToFrameTransform
- 35.IBPluginDependency
- 36.IBPluginDependency
- 36.IBViewBoundsToFrameTransform
- 37.IBPluginDependency
- 38.IBPluginDependency
- 38.IBViewBoundsToFrameTransform
- 39.IBPluginDependency
- 40.IBPluginDependency
- 40.IBViewBoundsToFrameTransform
- 41.IBPluginDependency
- 41.IBViewBoundsToFrameTransform
- 42.IBPluginDependency
- 42.IBViewBoundsToFrameTransform
- 43.IBPluginDependency
- 43.IBViewBoundsToFrameTransform
- 44.IBPluginDependency
- 44.IBViewBoundsToFrameTransform
- 45.IBPluginDependency
- 45.IBViewBoundsToFrameTransform
- 46.IBPluginDependency
- 46.IBViewBoundsToFrameTransform
- 47.IBPluginDependency
- 47.IBViewBoundsToFrameTransform
- 48.IBPluginDependency
- 49.IBPluginDependency
- 50.IBPluginDependency
- 51.IBPluginDependency
- 52.IBPluginDependency
- 53.IBPluginDependency
- 54.IBPluginDependency
- 55.IBPluginDependency
- 6.IBPluginDependency
- 6.IBViewBoundsToFrameTransform
- 62.IBPluginDependency
- 62.IBViewBoundsToFrameTransform
- 63.IBPluginDependency
- 64.IBPluginDependency
- 64.IBViewBoundsToFrameTransform
- 65.IBPluginDependency
- 66.IBPluginDependency
- 66.IBViewBoundsToFrameTransform
- 67.IBPluginDependency
- 68.IBPluginDependency
- 68.IBViewBoundsToFrameTransform
- 69.IBPluginDependency
- 7.IBPluginDependency
- 70.IBPluginDependency
- 70.IBViewBoundsToFrameTransform
- 71.IBPluginDependency
- 72.IBPluginDependency
- 72.IBViewBoundsToFrameTransform
- 73.IBPluginDependency
-
-
- YES
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- {{0, 573}, {480, 272}}
- com.apple.InterfaceBuilder.CocoaPlugin
-
- AUIQAABCMAAAA
-
- {628, 654}
- {{357, 416}, {480, 272}}
- com.apple.InterfaceBuilder.CocoaPlugin
-
- AUOaAAAAAAAAA
-
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABCCAAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
- {{8, 606}, {352, 242}}
- com.apple.InterfaceBuilder.CocoaPlugin
- {{8, 606}, {352, 242}}
-
-
-
- {352, 242}
- {352, 61}
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABC0AAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABCQAAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABCeAAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABCmAAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABCtAAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABDBAAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABC7AAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABDJQAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABDawAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABDMwAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABDQQAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABDTwAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABDXQAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABDg4AAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABDeQAAwbgAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABDlwAAwy0AAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABDlwAAw1QAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- AUMZAABBkAAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABBiAAAw1oAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABDlwAAwx4AAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABDlwAAwwAAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- P4AAAL+AAABCmgAAw1oAAA
-
- com.apple.InterfaceBuilder.CocoaPlugin
-
-
-
- YES
-
-
- YES
-
-
-
-
- YES
-
-
- YES
-
-
-
- 150
-
-
-
- YES
-
- MusicBoxController
- NSObject
-
- YES
-
- YES
- handleChannelButton:
- handleDisclosureButton:
- handleEffectButton:
- handlePauseButton:
- handleRewindButton:
-
-
- YES
- id
- id
- id
- id
- id
-
-
-
- YES
-
- YES
- handleChannelButton:
- handleDisclosureButton:
- handleEffectButton:
- handlePauseButton:
- handleRewindButton:
-
-
- YES
-
- handleChannelButton:
- id
-
-
- handleDisclosureButton:
- id
-
-
- handleEffectButton:
- id
-
-
- handlePauseButton:
- id
-
-
- handleRewindButton:
- id
-
-
-
-
- YES
-
- YES
- disclosure
- gametitle
- indicator
- led
- rewind
- window
-
-
- YES
- id
- id
- id
- id
- id
- id
-
-
-
- YES
-
- YES
- disclosure
- gametitle
- indicator
- led
- rewind
- window
-
-
- YES
-
- disclosure
- id
-
-
- gametitle
- id
-
-
- indicator
- id
-
-
- led
- id
-
-
- rewind
- id
-
-
- window
- id
-
-
-
-
- IBProjectSource
- mac-musicbox.h
-
-
-
- MusicBoxController
- NSObject
-
- IBUserSource
-
-
-
-
- MusicBoxIndicatorView
- NSView
-
-
-
-
- YES
-
- NSActionCell
- NSCell
-
- IBFrameworkSource
- AppKit.framework/Headers/NSActionCell.h
-
-
-
- NSApplication
- NSResponder
-
- IBFrameworkSource
- AppKit.framework/Headers/NSApplication.h
-
-
-
- NSApplication
-
- IBFrameworkSource
- AppKit.framework/Headers/NSApplicationScripting.h
-
-
-
- NSApplication
-
- IBFrameworkSource
- AppKit.framework/Headers/NSColorPanel.h
-
-
-
- NSApplication
-
- IBFrameworkSource
- AppKit.framework/Headers/NSHelpManager.h
-
-
-
- NSApplication
-
- IBFrameworkSource
- AppKit.framework/Headers/NSPageLayout.h
-
-
-
- NSApplication
-
- IBFrameworkSource
- AppKit.framework/Headers/NSUserInterfaceItemSearching.h
-
-
-
- NSButton
- NSControl
-
- IBFrameworkSource
- AppKit.framework/Headers/NSButton.h
-
-
-
- NSButtonCell
- NSActionCell
-
- IBFrameworkSource
- AppKit.framework/Headers/NSButtonCell.h
-
-
-
- NSCell
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSCell.h
-
-
-
- NSControl
- NSView
-
- IBFrameworkSource
- AppKit.framework/Headers/NSControl.h
-
-
-
- NSFormatter
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSFormatter.h
-
-
-
- NSImageCell
- NSCell
-
- IBFrameworkSource
- AppKit.framework/Headers/NSImageCell.h
-
-
-
- NSImageView
- NSControl
-
- IBFrameworkSource
- AppKit.framework/Headers/NSImageView.h
-
-
-
- NSMenu
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSMenu.h
-
-
-
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSAccessibility.h
-
-
-
- NSObject
-
-
-
- NSObject
-
-
-
- NSObject
-
-
-
- NSObject
-
-
-
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSDictionaryController.h
-
-
-
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSDragging.h
-
-
-
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSFontManager.h
-
-
-
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSFontPanel.h
-
-
-
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSKeyValueBinding.h
-
-
-
- NSObject
-
-
-
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSNibLoading.h
-
-
-
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSOutlineView.h
-
-
-
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSPasteboard.h
-
-
-
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSSavePanel.h
-
-
-
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSTableView.h
-
-
-
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSToolbarItem.h
-
-
-
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSView.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSArchiver.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSClassDescription.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSError.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSFileManager.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSKeyValueCoding.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSKeyValueObserving.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSKeyedArchiver.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSObject.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSObjectScripting.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSPortCoder.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSRunLoop.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSScriptClassDescription.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSScriptKeyValueCoding.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSScriptObjectSpecifiers.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSScriptWhoseTests.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSThread.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSURL.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSURLConnection.h
-
-
-
- NSObject
-
- IBFrameworkSource
- Foundation.framework/Headers/NSURLDownload.h
-
-
-
- NSObject
-
- IBFrameworkSource
- QuartzCore.framework/Headers/CAAnimation.h
-
-
-
- NSObject
-
- IBFrameworkSource
- QuartzCore.framework/Headers/CALayer.h
-
-
-
- NSObject
-
- IBFrameworkSource
- QuartzCore.framework/Headers/CIImageProvider.h
-
-
-
- NSResponder
-
- IBFrameworkSource
- AppKit.framework/Headers/NSInterfaceStyle.h
-
-
-
- NSResponder
- NSObject
-
- IBFrameworkSource
- AppKit.framework/Headers/NSResponder.h
-
-
-
- NSTextField
- NSControl
-
- IBFrameworkSource
- AppKit.framework/Headers/NSTextField.h
-
-
-
- NSTextFieldCell
- NSActionCell
-
- IBFrameworkSource
- AppKit.framework/Headers/NSTextFieldCell.h
-
-
-
- NSView
-
- IBFrameworkSource
- AppKit.framework/Headers/NSClipView.h
-
-
-
- NSView
-
- IBFrameworkSource
- AppKit.framework/Headers/NSMenuItem.h
-
-
-
- NSView
-
- IBFrameworkSource
- AppKit.framework/Headers/NSRulerView.h
-
-
-
- NSView
- NSResponder
-
-
-
- NSWindow
-
- IBFrameworkSource
- AppKit.framework/Headers/NSDrawer.h
-
-
-
- NSWindow
- NSResponder
-
- IBFrameworkSource
- AppKit.framework/Headers/NSWindow.h
-
-
-
- NSWindow
-
- IBFrameworkSource
- AppKit.framework/Headers/NSWindowScripting.h
-
-
-
-
- 0
- IBCocoaFramework
-
- com.apple.InterfaceBuilder.CocoaPlugin.macosx
-
-
-
- com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3
-
-
- YES
- ../cocoatest.xcodeproj
- 3
-
- YES
-
- YES
- musicbox_effect
- musicbox_indicator
- musicbox_ledoff
- musicbox_pause
- musicbox_rewind
-
-
- YES
- {16, 16}
- {262, 142}
- {16, 16}
- {16, 16}
- {16, 16}
-
-
-
-
diff --git a/macosx/HID_Utilities_External.h b/macosx/HID_Utilities_External.h
index d890bfcc..fe4b0f03 100644
--- a/macosx/HID_Utilities_External.h
+++ b/macosx/HID_Utilities_External.h
@@ -51,7 +51,7 @@
/*****************************************************/
#if !TARGET_RT_MAC_CFM
#include
-#endif TARGET_RT_MAC_CFM
+#endif // TARGET_RT_MAC_CFM
//#include
#if 0 // NOTE: These are now in
@@ -109,7 +109,7 @@ typedef enum IOHIDReportType {
// Notes: This is a MachO function pointer. If you're using CFM you have to call MachOFunctionPointerForCFMFunctionPointer.
typedef void( *IOHIDCallbackFunction ) ( void* target, unsigned long result, void* refcon, void* sender );
typedef void* IOHIDEventStruct;
-#endif TARGET_RT_MAC_CFM
+#endif // TARGET_RT_MAC_CFM
// Device and Element Interfaces
diff --git a/macosx/Info.plist b/macosx/Info.plist
index 966f925a..5c345422 100644
--- a/macosx/Info.plist
+++ b/macosx/Info.plist
@@ -160,7 +160,7 @@
CFBundleExecutable
- Snes9x
+ Snes9x (i386)
CFBundleGetInfoString
Snes9x 1.60, Copyright 1996-2019 Snes9x developers.
CFBundleHelpBookFolder
@@ -170,7 +170,7 @@
CFBundleIconFile
APPL.icns
CFBundleIdentifier
- com.snes9x.macos.snes9x
+ $(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
diff --git a/macosx/Info_i386.plist b/macosx/Info_i386.plist
deleted file mode 100644
index 2229ece9..00000000
--- a/macosx/Info_i386.plist
+++ /dev/null
@@ -1,189 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- English
- CFBundleDocumentTypes
-
-
- CFBundleTypeExtensions
-
- jma
-
- CFBundleTypeName
- JMA archive
- CFBundleTypeOSTypes
-
- JMAf
-
- CFBundleTypeRole
- Viewer
- LSTypeIsPackage
-
-
-
- CFBundleTypeExtensions
-
- sfc
- smc
- swc
- fig
- gd3
-
- CFBundleTypeIconFile
- CART.icns
- CFBundleTypeName
- Snes9x ROM Image
- CFBundleTypeOSTypes
-
- CART
-
- CFBundleTypeRole
- Viewer
- LSTypeIsPackage
-
-
-
- CFBundleTypeExtensions
-
- srm
-
- CFBundleTypeIconFile
- SRAM.icns
- CFBundleTypeName
- Snes9x SRAM Data
- CFBundleTypeOSTypes
-
- SRAM
-
- CFBundleTypeRole
- None
- LSTypeIsPackage
-
-
-
- CFBundleTypeExtensions
-
- frz
-
- CFBundleTypeIconFile
- SAVE.icns
- CFBundleTypeName
- Snes9x Freeze Data
- CFBundleTypeOSTypes
-
- SAVE
-
- CFBundleTypeRole
- None
- LSTypeIsPackage
-
-
-
- CFBundleTypeExtensions
-
- smv
-
- CFBundleTypeName
- Snes9x Movie Data
- CFBundleTypeOSTypes
-
- SMOV
-
- CFBundleTypeRole
- None
- LSTypeIsPackage
-
-
-
- CFBundleTypeExtensions
-
- spc
-
- CFBundleTypeName
- Snes9x SPC Data
- CFBundleTypeOSTypes
-
- SSPC
-
- CFBundleTypeRole
- None
- LSTypeIsPackage
-
-
-
- CFBundleTypeExtensions
-
- cht
-
- CFBundleTypeName
- Snes9x Cheat Data
- CFBundleTypeOSTypes
-
- SCHT
-
- CFBundleTypeRole
- None
- LSTypeIsPackage
-
-
-
- CFBundleTypeExtensions
-
- rtc
-
- CFBundleTypeName
- Snes9x RTC Data
- CFBundleTypeOSTypes
-
- SRTC
-
- CFBundleTypeRole
- None
- LSTypeIsPackage
-
-
-
- CFBundleTypeExtensions
-
- *
-
- CFBundleTypeOSTypes
-
- ****
-
- CFBundleTypeRole
- None
- LSTypeIsPackage
-
-
-
- CFBundleExecutable
- Snes9x (i386)
- CFBundleGetInfoString
- Snes9x 1.60, Copyright 1996-2019 Snes9x developers.
- CFBundleHelpBookFolder
- Snes9x Help
- CFBundleHelpBookName
- Snes9x Help
- CFBundleIconFile
- APPL.icns
- CFBundleIdentifier
- com.snes9x.macos.snes9x
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- Snes9x
- CFBundlePackageType
- APPL
- CFBundleShortVersionString
- 1.60
- CFBundleSignature
- ~9X~
- CFBundleVersion
- 1.60
- CSResourcesFileMapped
-
-
-
diff --git a/macosx/ReClassicfication/EndianStuff.h b/macosx/ReClassicfication/EndianStuff.h
new file mode 100755
index 00000000..1e6d3d4d
--- /dev/null
+++ b/macosx/ReClassicfication/EndianStuff.h
@@ -0,0 +1,28 @@
+/*
+ * EndianStuff.h
+ * stackimport
+ *
+ * Created by Mr. Z. on 10/06/06.
+ * Copyright 2006 Mr Z. All rights reserved.
+ *
+ */
+
+#pragma once
+
+#include
+
+
+#if RECLASSIFICATION_BUILD_BIG_ENDIAN
+#define BIG_ENDIAN_16(value) (value)
+#define BIG_ENDIAN_32(value) (value)
+#else
+#define BIG_ENDIAN_16(value) \
+ (((((uint16_t)(value))<<8) & 0xFF00) | \
+ ((((uint16_t)(value))>>8) & 0x00FF))
+
+#define BIG_ENDIAN_32(value) \
+ (((((uint32_t)(value))<<24) & 0xFF000000) | \
+ ((((uint32_t)(value))<< 8) & 0x00FF0000) | \
+ ((((uint32_t)(value))>> 8) & 0x0000FF00) | \
+ ((((uint32_t)(value))>>24) & 0x000000FF))
+#endif
diff --git a/macosx/ReClassicfication/FakeHandles.c b/macosx/ReClassicfication/FakeHandles.c
new file mode 100755
index 00000000..e2315cc4
--- /dev/null
+++ b/macosx/ReClassicfication/FakeHandles.c
@@ -0,0 +1,269 @@
+/* ===========================================================================
+
+ PROJECT: FakeHandles
+
+ FILE: FakeHandles.c
+
+ PURPOSE: Simulate Handles on machines which only have ANSI-C to easily
+ port some of the more simple Macintosh code fragments to other
+ platforms.
+
+ (C) Copyright 1998 by Uli Kusterer, all rights reserved.
+
+ ======================================================================== */
+
+#pragma mark [Headers]
+
+
+// -----------------------------------------------------------------------------
+// Headers:
+// -----------------------------------------------------------------------------
+
+#include "FakeHandles.h"
+
+
+// -----------------------------------------------------------------------------
+// Globals:
+// -----------------------------------------------------------------------------
+
+/* The last entry in the master pointer array is mis-used to hold a pointer
+ to another master pointer array. Thus, we have a linked list of master
+ pointer arrays in RAM, and we don't run out of master pointers as easily. */
+MasterPointer gMasterPointers[MASTERPOINTER_CHUNK_SIZE];
+long gFakeHandleError = noErr;
+
+
+/* -----------------------------------------------------------------------------
+ FakeInitHandles:
+ Call this to initialize the fake memory Manager at the start of your
+ program. Only call this once or you'll lose all your Handles and will have
+ stale memory lying around. Pass the global gMasterPointers in
+ masterPtrArray.
+
+ REVISIONS:
+ 98-08-30 UK Created.
+ ----------------------------------------------------------------------------- */
+
+void FakeInitHandles( MasterPointer* masterPtrArray )
+{
+ long x;
+
+ for( x = 0; x < MASTERPOINTER_CHUNK_SIZE; x++ )
+ {
+ masterPtrArray[x].actualPointer = NULL;
+ masterPtrArray[x].used = false;
+ masterPtrArray[x].memoryFlags = 0;
+ masterPtrArray[x].size = 0;
+ }
+
+ gFakeHandleError = noErr;
+}
+
+
+/* -----------------------------------------------------------------------------
+ FakeMoreMasters:
+ Call this if you need more master pointers Called internally by
+ FakeNewHandle() when it runs out of master pointers.
+
+ REVISIONS:
+ 98-08-30 UK Created.
+ ----------------------------------------------------------------------------- */
+
+void FakeMoreMasters()
+{
+ long x;
+ MasterPointer* vMPtrBlock;
+ MasterPointer* vCurrBlock;
+
+ // Make a new master pointer block:
+ vMPtrBlock = malloc( MASTERPOINTER_CHUNK_SIZE *sizeof(MasterPointer) );
+ if( vMPtrBlock == NULL )
+ {
+ gFakeHandleError = memFulErr;
+ return;
+ }
+
+ // Clear it:
+ for( x = 0; x < MASTERPOINTER_CHUNK_SIZE; x++ )
+ {
+ vMPtrBlock[x].actualPointer = NULL;
+ vMPtrBlock[x].used = false;
+ vMPtrBlock[x].memoryFlags = 0;
+ vMPtrBlock[x].size = 0;
+ }
+
+ // Find last master pointer in last master pointer block:
+ vCurrBlock = gMasterPointers;
+ while( vCurrBlock[MASTERPOINTER_CHUNK_SIZE -1].used == true )
+ vCurrBlock = (MasterPointer*) vCurrBlock[MASTERPOINTER_CHUNK_SIZE-1].actualPointer;
+
+ // Make this last master pointer point to our new block:
+ vCurrBlock[MASTERPOINTER_CHUNK_SIZE-1].actualPointer = (char*) vMPtrBlock;
+ vCurrBlock[MASTERPOINTER_CHUNK_SIZE-1].used = true;
+ vMPtrBlock[MASTERPOINTER_CHUNK_SIZE-1].size = MASTERPOINTER_CHUNK_SIZE *sizeof(MasterPointer);
+
+ gFakeHandleError = noErr;
+}
+
+
+Handle FakeNewEmptyHandle()
+{
+ Handle theHandle = NULL;
+ long x;
+ MasterPointer* vCurrBlock = gMasterPointers;
+ bool notFound = true;
+
+ gFakeHandleError = noErr;
+
+ while( notFound )
+ {
+ for( x = 0; x < (MASTERPOINTER_CHUNK_SIZE-1); x++ )
+ {
+ if( !(vCurrBlock[x].used) )
+ {
+ vCurrBlock[x].used = true;
+ vCurrBlock[x].memoryFlags = 0;
+ vCurrBlock[x].size = 0;
+
+ theHandle = (Handle) &(vCurrBlock[x]);
+ notFound = false;
+ break;
+ }
+ }
+
+ if( !vCurrBlock[MASTERPOINTER_CHUNK_SIZE-1].used ) // Last is unused? We need a new master pointer block!
+ {
+ FakeMoreMasters();
+ if( !vCurrBlock[MASTERPOINTER_CHUNK_SIZE-1].used ) // No new block added?!
+ notFound = false; // Terminate, it's very likely an error occurred.
+ }
+ vCurrBlock = (MasterPointer*) vCurrBlock[MASTERPOINTER_CHUNK_SIZE-1].actualPointer; // Go next master pointer block.
+ }
+
+ return theHandle;
+}
+
+
+/* -----------------------------------------------------------------------------
+ NewHandle:
+ Create a new Handle. This creates a new entry in the Master Ptr array and
+ allocates memory of the specified size for it. Then it returns a Ptr to
+ this entry.
+
+ Returns NULL if not successful. If MemError() is noErr upon a NULL return
+ value, we are out of master pointers.
+
+ REVISIONS:
+ 2001-02-16 UK Added support for error codes.
+ 1998-08-30 UK Created.
+ ----------------------------------------------------------------------------- */
+
+Handle FakeNewHandle( long theSize )
+{
+ MasterPointer * theHandle = (MasterPointer*) FakeNewEmptyHandle();
+
+ theHandle->actualPointer = malloc( theSize );
+ if( theHandle->actualPointer == NULL )
+ {
+ FakeDisposeHandle( (Handle) theHandle );
+ gFakeHandleError = memFulErr;
+ }
+ else
+ theHandle->size = theSize;
+
+ return (Handle)theHandle;
+}
+
+
+/* -----------------------------------------------------------------------------
+ DisposeHandle:
+ Dispose an existing Handle. Only call this once or you might kill valid
+ memory or worse.
+
+ This frees the memory we use and marks the entry for the specified Handle
+ as unused.
+
+ REVISIONS:
+ 1998-08-30 UK Created.
+ ----------------------------------------------------------------------------- */
+
+void FakeDisposeHandle( Handle theHand )
+{
+ MasterPointer* theEntry = (MasterPointer*) theHand;
+
+ if( theEntry->actualPointer )
+ free( theEntry->actualPointer );
+ theEntry->used = false;
+ theEntry->actualPointer = NULL;
+ theEntry->memoryFlags = 0;
+ theEntry->size = 0;
+}
+
+
+void FakeEmptyHandle( Handle theHand )
+{
+ MasterPointer* theEntry = (MasterPointer*) theHand;
+
+ if( theEntry->actualPointer )
+ free( theEntry->actualPointer );
+ theEntry->actualPointer = NULL;
+}
+
+
+/* -----------------------------------------------------------------------------
+ GetHandleSize:
+ Return the size of an existing Handle. This simply examines the "size"
+ field of the Handle's entry.
+
+ REVISIONS:
+ 1998-08-30 UK Created.
+ ----------------------------------------------------------------------------- */
+
+long FakeGetHandleSize( Handle theHand )
+{
+ MasterPointer* theEntry = (MasterPointer*) theHand;
+
+ gFakeHandleError = noErr;
+
+ return( theEntry->size );
+}
+
+
+/* -----------------------------------------------------------------------------
+ SetHandleSize:
+ Change the size of an existing Handle. This reallocates the Handle (keeping
+ its data) and updates the size field of the Handle's entry accordingly.
+
+ REVISIONS:
+ 1998-08-30 UK Created.
+ ----------------------------------------------------------------------------- */
+
+void FakeSetHandleSize( Handle theHand, long theSize )
+{
+ MasterPointer* theEntry = (MasterPointer*) theHand;
+ char* thePtr;
+
+ thePtr = theEntry->actualPointer;
+ thePtr = realloc( thePtr, theSize );
+
+ if( thePtr )
+ {
+ theEntry->actualPointer = thePtr;
+ theEntry->size = theSize;
+ gFakeHandleError = noErr;
+ }
+ else
+ gFakeHandleError = memFulErr;
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/macosx/ReClassicfication/FakeHandles.h b/macosx/ReClassicfication/FakeHandles.h
new file mode 100755
index 00000000..35c0014f
--- /dev/null
+++ b/macosx/ReClassicfication/FakeHandles.h
@@ -0,0 +1,114 @@
+/* ===========================================================================
+
+ PROJECT: FakeHandles
+
+ FILE: FakeHandles.h
+
+ PURPOSE: Simulate Handles on machines which only have ANSI-C to easily
+ port some of the more simple Macintosh code fragments to other
+ platforms.
+
+ (C) Copyright 1998 by Uli Kusterer, all rights reserved.
+
+ DIRECTIONS:
+ A Handle is a memory block that remembers its size automatically.
+ To the user, a Handle is simply a pointer to a pointer to the actual
+ data. Dereference it twice to get at the actual data. Before you
+ pass a once-dereferenced Handle to any other functions, you need to
+ call HLock() on it to avoid that it moves. Call HUnlock() when you
+ are finished with that.
+ To create a Handle, use NewHandle(). To free a Handle, call
+ DisposeHandle(). To resize use SetHandleSize() (the Handle itself
+ will not change, but the pointer to the actual data may change),
+ GetHandleSize() returns the actual size of the Handle.
+ Before making any of these calls, you *must have* called
+ InitHandles().
+
+ ======================================================================== */
+
+#ifndef FAKEHANDLES_H
+#define FAKEHANDLES_H
+
+#pragma mark [Headers]
+
+
+// -----------------------------------------------------------------------------
+// Headers:
+// -----------------------------------------------------------------------------
+
+#include
+#include
+#include
+
+
+// -----------------------------------------------------------------------------
+// Constants:
+// -----------------------------------------------------------------------------
+
+#ifndef NULL
+ #define NULL 0L
+#endif
+
+#define MASTERPOINTER_CHUNK_SIZE 1024 // Size of blocks of master pointers we allocate in one go.
+
+
+// Error codes MemError() may return after Handle calls:
+enum
+{
+#ifndef __MACTYPES__
+ noErr = 0, // No error, success.
+#endif /* __MACTYPES__ */
+ memFulErr = -108 // Out of memory error.
+};
+
+
+// -----------------------------------------------------------------------------
+// Data Types:
+// -----------------------------------------------------------------------------
+
+// Data types special to Mac:
+
+typedef char** Handle;
+#ifndef __MACTYPES__
+typedef unsigned char Boolean;
+#endif /* __MACTYPES__ */
+
+
+// Private data structure used internally to keep track of Handles:
+typedef struct MasterPointer
+{
+ char* actualPointer; // The actual Pointer we're pointing to.
+ Boolean used; // Is this master Ptr being used?
+ long memoryFlags; // Some flags for this Handle.
+ long size; // The size of this Handle.
+} MasterPointer;
+
+// -----------------------------------------------------------------------------
+// Globals:
+// -----------------------------------------------------------------------------
+
+extern MasterPointer gMasterPointers[MASTERPOINTER_CHUNK_SIZE];
+extern long gFakeHandleError;
+
+
+// -----------------------------------------------------------------------------
+// Prototypes:
+// -----------------------------------------------------------------------------
+
+extern void FakeInitHandles( MasterPointer* masterPtrArray );
+extern Handle FakeNewHandle( long theSize );
+extern void FakeDisposeHandle( Handle theHand );
+extern long FakeGetHandleSize( Handle theHand );
+extern void FakeSetHandleSize( Handle theHand, long theSize );
+extern void FakeMoreMasters( void );
+extern Handle FakeNewEmptyHandle();
+extern void FakeEmptyHandle( Handle theHand );
+
+
+
+
+
+
+
+
+#endif /*FAKEHANDLES_H*/
diff --git a/macosx/ReClassicfication/FakeResources.c b/macosx/ReClassicfication/FakeResources.c
new file mode 100755
index 00000000..1442bba2
--- /dev/null
+++ b/macosx/ReClassicfication/FakeResources.c
@@ -0,0 +1,1115 @@
+//
+// FakeResources.c
+// ReClassicfication
+//
+// Created by Uli Kusterer on 20.02.13.
+// Copyright (c) 2013 Uli Kusterer. All rights reserved.
+//
+
+#include
+#include // for memmove().
+#include
+#include "FakeResources.h"
+#include "EndianStuff.h"
+
+
+// Turn this on if you want to read actual Mac resource forks on a Mac or Darwin
+// but using the ANSI file APIs (uses Apple's "/..namedfork/rsrc" trick).
+#define READ_REAL_RESOURCE_FORKS 1
+
+
+/*
+ resource data offset 4 bytes
+ resource map offset 4 bytes
+ resource data length 4 bytes
+ resource map length 4 bytes
+ Reserved for system use 112 bytes
+ Application data 128 bytes
+ resource data ...
+ resource map ...
+
+
+ Resource data is 4-byte-long-counted, followed by actual data.
+
+
+ Resource map:
+
+ copy of resource header in RAM 16 bytes
+ next resource map in RAM 4 bytes
+ file reference number in RAM 2 bytes
+ Resource file attributes 2 bytes
+ type list offset (resource map-relative) 2 bytes
+ name list offset (resource map-relative) 2 bytes
+*/
+
+struct FakeResourceMap
+{
+ struct FakeResourceMap* nextResourceMap;
+ bool dirty; // per-file tracking of whether FakeUpdateResFile() needs to write
+ FILE* fileDescriptor;
+ int16_t fileRefNum;
+ uint16_t resFileAttributes;
+ uint16_t numTypes;
+ struct FakeTypeListEntry* typeList;
+};
+
+/*
+ Type list:
+
+ number of types (-1) 2 bytes
+ resource type 4 bytes
+ number of resources (-1) 2 bytes
+ offset to reference list (type list relative) 2 bytes
+*/
+
+struct FakeTypeListEntry
+{
+ uint32_t resourceType;
+ uint16_t numberOfResourcesOfType; // -1
+ struct FakeReferenceListEntry* resourceList;
+};
+
+/*
+ Reference list:
+
+ resource ID 2 bytes
+ resource name offset (relative to resource name list) 2 bytes
+ resource attributes 1 byte
+ resource data offset (resource data relative) 3 bytes
+ handle to resource in RAM 4 bytes
+*/
+
+struct FakeReferenceListEntry
+{
+ int16_t resourceID;
+ uint8_t resourceAttributes;
+ Handle resourceHandle;
+ char resourceName[257]; // 257 = 1 Pascal length byte, 255 characters for actual string, 1 byte for C terminator \0.
+};
+
+/*
+ Resource names are stored as byte-counted strings. (I.e. packed P-Strings)
+ Look-up by name is case-insensitive but case-preserving and diacritic-sensitive.
+*/
+
+
+struct FakeResourceMap * gResourceMap = NULL; // Linked list.
+struct FakeResourceMap * gCurrResourceMap = NULL; // Start search of map here.
+int16_t gFileRefNumSeed = 0;
+int16_t gFakeResError = noErr;
+struct FakeTypeCountEntry* gLoadedTypes = NULL;
+int16_t gNumLoadedTypes = 0;
+
+
+struct FakeTypeCountEntry
+{
+ uint32_t type;
+ int16_t retainCount;
+};
+
+
+size_t FakeFWriteUInt32BE( uint32_t inInt, FILE* theFile )
+{
+ inInt = BIG_ENDIAN_32(inInt);
+ return fwrite( &inInt, sizeof(inInt), 1, theFile );
+}
+
+
+size_t FakeFWriteInt16BE( int16_t inInt, FILE* theFile )
+{
+ inInt = BIG_ENDIAN_16(inInt);
+ return fwrite( &inInt, sizeof(inInt), 1, theFile );
+}
+
+
+size_t FakeFWriteUInt16BE( uint16_t inInt, FILE* theFile )
+{
+ inInt = BIG_ENDIAN_16(inInt);
+ return fwrite( &inInt, sizeof(inInt), 1, theFile );
+}
+
+
+void FakeFSeek( FILE* inFile, long inOffset, int inMode )
+{
+ int theResult = fseek( inFile, inOffset, inMode );
+}
+
+
+int16_t FakeResError()
+{
+ return gFakeResError;
+}
+
+
+// To be able to iterate types across files without duplicates, we build a list
+// of all types in open files and keep track of how many files contain each type
+// by "retaining" each type and "releasing" it when a file closes.
+void FakeRetainType( uint32_t resType )
+{
+ if( gLoadedTypes == NULL )
+ {
+ gLoadedTypes = malloc( sizeof(struct FakeTypeCountEntry) );
+ gLoadedTypes[0].type = resType;
+ gLoadedTypes[0].retainCount = 1;
+ }
+
+ for( int x = 0; x < gNumLoadedTypes; x++ )
+ {
+ if( gLoadedTypes[x].type == resType )
+ {
+ gLoadedTypes[x].retainCount++;
+ return;
+ }
+ }
+
+ gNumLoadedTypes++;
+ gLoadedTypes = realloc( gLoadedTypes, gNumLoadedTypes * sizeof(struct FakeTypeCountEntry) );
+ gLoadedTypes[gNumLoadedTypes -1].type = resType;
+ gLoadedTypes[gNumLoadedTypes -1].retainCount = 1;
+}
+
+
+// The converse of FakeRetainType (see for more info):
+void FakeReleaseType( uint32_t resType )
+{
+ for( int x = 0; x < gNumLoadedTypes; x++ )
+ {
+ if( gLoadedTypes[x].type == resType )
+ {
+ gLoadedTypes[x].retainCount--;
+ if( gLoadedTypes[x].retainCount == 0 )
+ {
+ gNumLoadedTypes--;
+ if( gNumLoadedTypes > 0 )
+ gLoadedTypes[x] = gLoadedTypes[gNumLoadedTypes];
+ }
+ break;
+ }
+ }
+}
+
+
+struct FakeResourceMap* FakeFindResourceMap( int16_t inFileRefNum, struct FakeResourceMap*** outPrevMapPtr )
+{
+ struct FakeResourceMap* currMap = gResourceMap;
+ if( outPrevMapPtr )
+ *outPrevMapPtr = &gResourceMap;
+
+ while( currMap != NULL && currMap->fileRefNum != inFileRefNum )
+ {
+ if( outPrevMapPtr )
+ *outPrevMapPtr = &currMap->nextResourceMap;
+ currMap = currMap->nextResourceMap;
+ }
+ return currMap;
+}
+
+
+struct FakeResourceMap* FakeResFileOpen( const char* inPath, const char* inMode )
+{
+ FILE * theFile = fopen( inPath, inMode );
+ if( !theFile )
+ {
+ gFakeResError = fnfErr;
+ return NULL;
+ }
+
+ uint32_t resourceDataOffset = 0;
+ uint32_t resourceMapOffset = 0;
+ uint32_t lengthOfResourceData = 0;
+ uint32_t lengthOfResourceMap = 0;
+
+ struct FakeResourceMap * newMap = calloc( 1, sizeof(struct FakeResourceMap) );
+ newMap->fileDescriptor = theFile;
+ newMap->fileRefNum = gFileRefNumSeed++;
+
+ if( fread( &resourceDataOffset, 1, sizeof(resourceDataOffset), theFile ) != sizeof(resourceDataOffset) )
+ {
+ gFakeResError = eofErr;
+ free( newMap );
+ newMap = NULL;
+ return NULL;
+ }
+ resourceDataOffset = BIG_ENDIAN_32(resourceDataOffset);
+
+ if( fread( &resourceMapOffset, 1, sizeof(resourceMapOffset), theFile ) != sizeof(resourceMapOffset) )
+ {
+ gFakeResError = eofErr;
+ free( newMap );
+ newMap = NULL;
+ return NULL;
+ }
+ resourceMapOffset = BIG_ENDIAN_32(resourceMapOffset);
+
+ if( fread( &lengthOfResourceData, 1, sizeof(lengthOfResourceData), theFile ) != sizeof(lengthOfResourceData) )
+ {
+ gFakeResError = eofErr;
+ free( newMap );
+ newMap = NULL;
+ return NULL;
+ }
+ lengthOfResourceData = BIG_ENDIAN_32(lengthOfResourceData);
+
+ if( fread( &lengthOfResourceMap, 1, sizeof(lengthOfResourceMap), theFile ) != sizeof(lengthOfResourceMap) )
+ {
+ gFakeResError = eofErr;
+ free( newMap );
+ newMap = NULL;
+ return NULL;
+ }
+ lengthOfResourceMap = BIG_ENDIAN_32(lengthOfResourceMap);
+
+ FakeFSeek( theFile, 112, SEEK_CUR ); // Skip system data.
+ FakeFSeek( theFile, 128, SEEK_CUR ); // Skip application data.
+
+ FakeFSeek( theFile, resourceMapOffset, SEEK_SET );
+ FakeFSeek( theFile, 16, SEEK_CUR ); // Skip resource file header copy.
+ FakeFSeek( theFile, 4, SEEK_CUR ); // Skip next resource map placeholder.
+ FakeFSeek( theFile, 2, SEEK_CUR ); // Skip file ref num placeholder.
+ fread( &newMap->resFileAttributes, 1, sizeof(uint16_t), theFile ); // Read file attributes.
+ newMap->resFileAttributes = BIG_ENDIAN_16(newMap->resFileAttributes);
+
+ uint16_t typeListOffset = 0;
+ uint16_t nameListOffset = 0;
+
+ fread( &typeListOffset, 1, sizeof(typeListOffset), theFile );
+ typeListOffset = BIG_ENDIAN_16(typeListOffset);
+ fread( &nameListOffset, 1, sizeof(nameListOffset), theFile );
+ nameListOffset = BIG_ENDIAN_16(nameListOffset);
+
+ long typeListSeekPos = resourceMapOffset +(long)typeListOffset;
+ FakeFSeek( theFile, typeListSeekPos, SEEK_SET );
+
+ uint16_t numTypes = 0;
+ fread( &numTypes, 1, sizeof(numTypes), theFile );
+ numTypes = BIG_ENDIAN_16(numTypes) +1;
+
+ newMap->typeList = calloc( ((int)numTypes), sizeof(struct FakeTypeListEntry) );
+ newMap->numTypes = numTypes;
+ for( int x = 0; x < ((int)numTypes); x++ )
+ {
+ uint32_t currType = 0;
+ fread( &currType, 1, sizeof(uint32_t), theFile ); // Read type code (4CC).
+ char typeStr[5] = {0};
+ memmove( typeStr, &currType, 4 );
+ currType = BIG_ENDIAN_32( currType );
+ newMap->typeList[x].resourceType = currType;
+
+ FakeRetainType( currType );
+
+ uint16_t numResources = 0;
+ fread( &numResources, 1, sizeof(numResources), theFile );
+ numResources = BIG_ENDIAN_16(numResources);
+
+ uint16_t refListOffset = 0;
+ fread( &refListOffset, 1, sizeof(refListOffset), theFile );
+ refListOffset = BIG_ENDIAN_16(refListOffset);
+
+ long oldOffset = ftell(theFile);
+
+ long refListSeekPos = typeListSeekPos +(long)refListOffset;
+ FakeFSeek( theFile, refListSeekPos, SEEK_SET );
+
+ newMap->typeList[x].resourceList = calloc( ((int)numResources) +1, sizeof(struct FakeReferenceListEntry) );
+ newMap->typeList[x].numberOfResourcesOfType = ((int)numResources) +1;
+ for( int y = 0; y < ((int)numResources) +1; y++ )
+ {
+ fread( &newMap->typeList[x].resourceList[y].resourceID, 1, sizeof(uint16_t), theFile );
+ newMap->typeList[x].resourceList[y].resourceID = BIG_ENDIAN_16(newMap->typeList[x].resourceList[y].resourceID);
+
+ uint16_t nameOffset = 0;
+ fread( &nameOffset, 1, sizeof(nameOffset), theFile );
+ nameOffset = BIG_ENDIAN_16(nameOffset);
+
+ unsigned char attributesAndDataOffset[4];
+ uint32_t dataOffset = 0;
+ fread( &attributesAndDataOffset, 1, sizeof(attributesAndDataOffset), theFile );
+ newMap->typeList[x].resourceList[y].resourceAttributes = attributesAndDataOffset[0];
+ memmove( ((char*)&dataOffset) +1, attributesAndDataOffset +1, 3 );
+ dataOffset = BIG_ENDIAN_32(dataOffset);
+ FakeFSeek( theFile, 4, SEEK_CUR ); // Skip resource Handle placeholder.
+
+ long innerOldOffset = ftell(theFile);
+ long dataSeekPos = resourceDataOffset +(long)dataOffset;
+ FakeFSeek( theFile, dataSeekPos, SEEK_SET );
+ uint32_t dataLength = 0;
+ fread( &dataLength, 1, sizeof(dataLength), theFile );
+ dataLength = BIG_ENDIAN_32(dataLength);
+ newMap->typeList[x].resourceList[y].resourceHandle = FakeNewHandle(dataLength);
+ fread( (*newMap->typeList[x].resourceList[y].resourceHandle), 1, dataLength, theFile );
+
+ if( -1 != (long)nameOffset )
+ {
+ long nameSeekPos = resourceMapOffset +(long)nameListOffset +(long)nameOffset;
+ FakeFSeek( theFile, nameSeekPos, SEEK_SET );
+ uint8_t nameLength = 0;
+ fread( &nameLength, 1, sizeof(nameLength), theFile );
+ newMap->typeList[x].resourceList[y].resourceName[0] = nameLength;
+ if( nameLength > 0 )
+ fread( newMap->typeList[x].resourceList[y].resourceName +1, 1, nameLength, theFile );
+ }
+
+ FakeFSeek( theFile, innerOldOffset, SEEK_SET );
+ }
+
+ FakeFSeek( theFile, oldOffset, SEEK_SET );
+ }
+
+ newMap->nextResourceMap = gResourceMap;
+ gResourceMap = newMap;
+ gFakeResError = noErr;
+
+ gCurrResourceMap = gResourceMap;
+
+ return newMap;
+}
+
+
+int16_t FakeOpenResFile( const unsigned char* inPath )
+{
+#if READ_REAL_RESOURCE_FORKS
+ const char* resForkSuffix = "/..namedfork/rsrc";
+#endif // READ_REAL_RESOURCE_FORKS
+ char thePath[256 +17] = {0};
+ memmove(thePath,inPath +1,inPath[0]);
+#if READ_REAL_RESOURCE_FORKS
+ memmove(thePath +inPath[0],resForkSuffix,17);
+#endif // READ_REAL_RESOURCE_FORKS
+ struct FakeResourceMap* theMap = FakeResFileOpen( thePath, "r+" );
+ if( !theMap )
+ theMap = FakeResFileOpen( thePath, "r" );
+ if( theMap )
+ return theMap->fileRefNum;
+ else
+ return gFakeResError;
+}
+
+
+static bool FakeFindResourceHandleInMap( Handle theResource, struct FakeTypeListEntry** outTypeEntry, struct FakeReferenceListEntry** outRefEntry, struct FakeResourceMap* inMap )
+{
+ if( (theResource != NULL) && (inMap != NULL) )
+ {
+ for( int x = 0; x < inMap->numTypes; x++ )
+ {
+ for( int y = 0; y < inMap->typeList[x].numberOfResourcesOfType; y++ )
+ {
+ if( inMap->typeList[x].resourceList[y].resourceHandle == theResource )
+ {
+ if (outTypeEntry)
+ {
+ *outTypeEntry = &inMap->typeList[x];
+ }
+
+ if (outRefEntry)
+ {
+ *outRefEntry = &inMap->typeList[x].resourceList[y];
+ }
+
+ return true;
+ }
+ }
+ }
+ }
+
+ if (outTypeEntry)
+ {
+ *outTypeEntry = NULL;
+ }
+
+ if (outRefEntry)
+ {
+ *outRefEntry = NULL;
+ }
+
+ return false;
+}
+
+
+static bool FakeFindResourceHandle( Handle theResource, struct FakeResourceMap** outMap, struct FakeTypeListEntry** outTypeEntry, struct FakeReferenceListEntry** outRefEntry )
+{
+ struct FakeResourceMap* currMap = gResourceMap;
+ while( currMap != NULL )
+ {
+ if( FakeFindResourceHandleInMap(theResource, outTypeEntry, outRefEntry, currMap) )
+ {
+ if( outMap )
+ {
+ *outMap = currMap;
+ }
+ return true;
+ }
+
+ currMap = currMap->nextResourceMap;
+ }
+
+ if ( outMap )
+ {
+ *outMap = NULL;
+ }
+
+ if (outTypeEntry)
+ {
+ *outTypeEntry = NULL;
+ }
+
+ if (outRefEntry)
+ {
+ *outRefEntry = NULL;
+ }
+
+ return false;
+}
+
+
+static struct FakeTypeListEntry* FakeFindTypeListEntry(struct FakeResourceMap* inMap, uint32_t theType)
+{
+ if( inMap != NULL )
+ {
+ for( int x = 0; x < inMap->numTypes; x++ )
+ {
+ if( inMap->typeList[x].resourceType == theType )
+ {
+ return &inMap->typeList[x];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+int16_t FakeHomeResFile( Handle theResource )
+{
+ struct FakeResourceMap* currMap = NULL;
+
+ if( FakeFindResourceHandle( theResource, &currMap, NULL, NULL) )
+ {
+ gFakeResError = noErr;
+ return currMap->fileRefNum;
+ }
+
+ gFakeResError = resNotFound;
+ return -1;
+}
+
+
+void FakeUpdateResFile( int16_t inFileRefNum )
+{
+ const long kResourceHeaderLength = 16;
+ const long kResourceHeaderMapOffsetPos = 4;
+ const long kResourceHeaderMapLengthPos = 4 + 4 + 4;
+ const long kResourceHeaderReservedLength = 112;
+ const long kResourceHeaderAppReservedLength = 128;
+ const long kReservedHeaderLength = kResourceHeaderReservedLength + kResourceHeaderAppReservedLength;
+ const long kResourceDataSizeLength = 4;
+ const long kResourceMapNextHandleLength = 4;
+ const long kResourceMapFileRefLength = 2;
+ const long kResourceMapTypeListOffsetLength = 2;
+ const long kResourceMapNameListOffsetLength = 2;
+ const long kResourceMapNumTypesLength = 2;
+ const long kResourceRefLength = 2 + 2 + 1 + 3 + 4;
+ const long kResourceTypeLength = 4 + 2 + 2;
+
+ struct FakeResourceMap* currMap = FakeFindResourceMap( inFileRefNum, NULL );
+ long headerLength = kResourceHeaderLength + kReservedHeaderLength;
+ uint32_t resMapOffset = 0;
+ long refListSize = 0;
+
+ if (!currMap->dirty)
+ return;
+
+ // Write header:
+ FakeFSeek( currMap->fileDescriptor, 0, SEEK_SET );
+ uint32_t resDataOffset = (uint32_t)headerLength;
+ FakeFWriteUInt32BE( resDataOffset, currMap->fileDescriptor );
+ FakeFWriteUInt32BE( 0, currMap->fileDescriptor ); // placeholder offset to resource map
+ FakeFWriteUInt32BE( 0, currMap->fileDescriptor ); // placeholder resource data length
+ FakeFWriteUInt32BE( 0, currMap->fileDescriptor ); // placeholder resource map length
+
+ // reserved
+ for( int x = 0; x < (kResourceHeaderReservedLength / sizeof(uint32_t)); x++ )
+ FakeFWriteUInt32BE( 0, currMap->fileDescriptor );
+ for( int x = 0; x < (kResourceHeaderAppReservedLength / sizeof(uint32_t)); x++ )
+ FakeFWriteUInt32BE( 0, currMap->fileDescriptor );
+
+ resMapOffset = (uint32_t)headerLength;
+
+ // Write out data for each resource and calculate space needed:
+ for( int x = 0; x < currMap->numTypes; x++ )
+ {
+ for( int y = 0; y < currMap->typeList[x].numberOfResourcesOfType; y++ )
+ {
+ uint32_t theSize = (uint32_t)FakeGetHandleSize( currMap->typeList[x].resourceList[y].resourceHandle );
+ FakeFWriteUInt32BE( theSize, currMap->fileDescriptor );
+ resMapOffset += sizeof(theSize);
+ fwrite( *currMap->typeList[x].resourceList[y].resourceHandle, 1, theSize, currMap->fileDescriptor );
+ resMapOffset += theSize;
+ }
+
+ refListSize += currMap->typeList[x].numberOfResourcesOfType * kResourceRefLength;
+ }
+
+ // Write out what we know into the header now:
+ FakeFSeek( currMap->fileDescriptor, kResourceHeaderMapOffsetPos, SEEK_SET );
+ FakeFWriteUInt32BE( resMapOffset, currMap->fileDescriptor );
+ uint32_t resDataLength = resMapOffset -(uint32_t)headerLength;
+ FakeFWriteUInt32BE( resDataLength, currMap->fileDescriptor );
+
+ // Start writing resource map after data:
+ uint32_t resMapLength = 0;
+ FakeFSeek( currMap->fileDescriptor, resMapOffset, SEEK_SET );
+
+ // Copy what we know from the resource header
+ FakeFWriteUInt32BE( resDataOffset, currMap->fileDescriptor );
+ FakeFWriteUInt32BE( resMapOffset, currMap->fileDescriptor );
+ FakeFWriteUInt32BE( resDataLength, currMap->fileDescriptor );
+ FakeFWriteUInt32BE( 0, currMap->fileDescriptor ); // Placeholder
+
+ // Fake a next handle
+ FakeFWriteUInt32BE( 0, currMap->fileDescriptor );
+
+ resMapLength += kResourceHeaderLength + kResourceMapNextHandleLength + kResourceMapFileRefLength; // reserved: copy of resource header, next resource handle, file ref
+ FakeFWriteInt16BE( inFileRefNum, currMap->fileDescriptor );
+ FakeFWriteUInt16BE( currMap->resFileAttributes, currMap->fileDescriptor );
+ resMapLength += sizeof(uint16_t);
+
+ uint16_t typeListOffset = ftell(currMap->fileDescriptor)
+ +kResourceMapTypeListOffsetLength +kResourceMapNameListOffsetLength -resMapOffset;
+ FakeFWriteUInt16BE( typeListOffset, currMap->fileDescriptor ); // Res map relative, points to the type count
+ long refListStartPosition = typeListOffset + kResourceMapNumTypesLength + currMap->numTypes * kResourceTypeLength; // Calc where we'll start to put resource lists (right after types).
+
+ uint16_t nameListOffset = refListStartPosition +refListSize; // Calc where we'll start to put name lists (right after resource lists).
+ FakeFWriteUInt16BE( nameListOffset, currMap->fileDescriptor ); // Res map relative.
+
+ // Now write type list and ref lists:
+ uint32_t nameListStartOffset = 0;
+ FakeFWriteUInt16BE( currMap->numTypes -1, currMap->fileDescriptor );
+ uint32_t resDataCurrOffset = 0; // Keep track of where we wrote the associated data for each resource, relative to the start of resource data
+
+ refListStartPosition = kResourceMapNumTypesLength + currMap->numTypes * kResourceTypeLength; // relative to beginning of resource type list
+
+ for( int x = 0; x < currMap->numTypes; x++ )
+ {
+ // Write entry for this type:
+ uint32_t currType = currMap->typeList[x].resourceType;
+ FakeFWriteUInt32BE( currType, currMap->fileDescriptor );
+
+ uint16_t numResources = currMap->typeList[x].numberOfResourcesOfType -1;
+ FakeFWriteUInt16BE( numResources, currMap->fileDescriptor );
+
+ uint16_t refListOffset = refListStartPosition;
+ FakeFWriteUInt16BE( refListOffset, currMap->fileDescriptor );
+
+ // Jump to ref list location and write ref list out:
+ long oldOffsetAfterPrevType = ftell(currMap->fileDescriptor);
+
+ FakeFSeek( currMap->fileDescriptor, resMapOffset + typeListOffset + refListStartPosition, SEEK_SET );
+
+ for( int y = 0; y < currMap->typeList[x].numberOfResourcesOfType; y++ )
+ {
+ FakeFWriteInt16BE( currMap->typeList[x].resourceList[y].resourceID, currMap->fileDescriptor );
+
+ // Write name to name table:
+ if( currMap->typeList[x].resourceList[y].resourceName[0] == 0 )
+ FakeFWriteInt16BE( -1, currMap->fileDescriptor ); // Don't have a name, mark as -1.
+ else
+ {
+ FakeFWriteUInt16BE( nameListStartOffset, currMap->fileDescriptor ); // Associate name in name table with this.
+
+ long oldOffsetAfterNameOffset = ftell( currMap->fileDescriptor );
+ FakeFSeek( currMap->fileDescriptor, resMapOffset +nameListOffset +nameListStartOffset, SEEK_SET );
+ fwrite( currMap->typeList[x].resourceList[y].resourceName, currMap->typeList[x].resourceList[y].resourceName[0] +1, sizeof(uint8_t), currMap->fileDescriptor );
+
+ long currMapLen = (ftell(currMap->fileDescriptor) -resMapOffset);
+ if( currMapLen > resMapLength )
+ resMapLength = (uint32_t)currMapLen;
+
+ FakeFSeek( currMap->fileDescriptor, oldOffsetAfterNameOffset, SEEK_SET );
+ nameListStartOffset += currMap->typeList[x].resourceList[y].resourceName[0] +1; // Make sure we write next name *after* this one.
+ }
+
+ fwrite( &currMap->typeList[x].resourceList[y].resourceAttributes, 1, sizeof(uint8_t), currMap->fileDescriptor );
+ uint32_t resDataCurrOffsetBE = BIG_ENDIAN_32(resDataCurrOffset);
+ fwrite( ((uint8_t*)&resDataCurrOffsetBE) +1, 1, 3, currMap->fileDescriptor );
+ resDataCurrOffset += kResourceDataSizeLength + FakeGetHandleSize(currMap->typeList[x].resourceList[y].resourceHandle);
+ FakeFWriteUInt32BE( 0, currMap->fileDescriptor ); // Handle placeholder.
+
+ long currMapLen = (ftell(currMap->fileDescriptor) -resMapOffset);
+ if( currMapLen > resMapLength )
+ resMapLength = (uint32_t)currMapLen;
+ }
+
+ refListStartPosition += currMap->typeList[x].numberOfResourcesOfType * kResourceRefLength;
+
+ // Jump back to after our type entry so we can write the next one:
+ FakeFSeek( currMap->fileDescriptor, oldOffsetAfterPrevType, SEEK_SET );
+ }
+
+ // Write res map length:
+ FakeFSeek( currMap->fileDescriptor, kResourceHeaderMapLengthPos, SEEK_SET );
+ FakeFWriteUInt32BE( resMapLength, currMap->fileDescriptor );
+ FakeFSeek( currMap->fileDescriptor, resMapOffset + kResourceHeaderMapLengthPos, SEEK_SET );
+ FakeFWriteUInt32BE( resMapLength, currMap->fileDescriptor );
+
+ ftruncate(fileno(currMap->fileDescriptor), resMapOffset + resMapLength);
+
+ currMap->dirty = false;
+}
+
+
+void FakeRedirectResFileToPath( int16_t inFileRefNum, const char* cPath )
+{
+ struct FakeResourceMap** prevMapPtr = NULL;
+ struct FakeResourceMap* currMap = FakeFindResourceMap( inFileRefNum, &prevMapPtr );
+ if( currMap )
+ {
+ fclose( currMap->fileDescriptor );
+ currMap->fileDescriptor = fopen( cPath, "w" );
+ currMap->dirty = true;
+ }
+}
+
+
+void FakeCloseResFile( int16_t inFileRefNum )
+{
+ struct FakeResourceMap** prevMapPtr = NULL;
+ struct FakeResourceMap* currMap = FakeFindResourceMap( inFileRefNum, &prevMapPtr );
+ if( currMap )
+ {
+ FakeUpdateResFile(inFileRefNum);
+
+ *prevMapPtr = currMap->nextResourceMap; // Remove this from the linked list.
+ if( gCurrResourceMap == currMap )
+ gCurrResourceMap = currMap->nextResourceMap;
+
+ for( int x = 0; x < currMap->numTypes; x++ )
+ {
+ FakeReleaseType( currMap->typeList[x].resourceType );
+
+ for( int y = 0; y < currMap->typeList[x].numberOfResourcesOfType; y++ )
+ {
+ FakeDisposeHandle( currMap->typeList[x].resourceList[y].resourceHandle );
+ }
+ free( currMap->typeList[x].resourceList );
+ }
+ free( currMap->typeList );
+
+ fclose( currMap->fileDescriptor );
+ free( currMap );
+ }
+}
+
+
+Handle FakeGet1ResourceFromMap( uint32_t resType, int16_t resID, struct FakeResourceMap* inMap )
+{
+ gFakeResError = noErr;
+
+ if( inMap != NULL )
+ {
+ for( int x = 0; x < inMap->numTypes; x++ )
+ {
+ uint32_t currType = inMap->typeList[x].resourceType;
+ if( currType == resType )
+ {
+ for( int y = 0; y < inMap->typeList[x].numberOfResourcesOfType; y++ )
+ {
+ if( inMap->typeList[x].resourceList[y].resourceID == resID )
+ {
+ return inMap->typeList[x].resourceList[y].resourceHandle;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ gFakeResError = resNotFound;
+
+ return NULL;
+}
+
+
+Handle FakeGet1Resource( uint32_t resType, int16_t resID )
+{
+ return FakeGet1ResourceFromMap( resType, resID, gCurrResourceMap );
+}
+
+
+Handle FakeGetResource( uint32_t resType, int16_t resID )
+{
+ struct FakeResourceMap * currMap = gCurrResourceMap;
+ Handle theRes = NULL;
+
+ while( theRes == NULL && currMap != NULL )
+ {
+ theRes = FakeGet1ResourceFromMap( resType, resID, currMap );
+ if( theRes != NULL )
+ {
+ gFakeResError = noErr;
+ return theRes;
+ }
+
+ currMap = currMap->nextResourceMap;
+ }
+
+ gFakeResError = resNotFound;
+
+ return NULL;
+}
+
+
+int16_t FakeCount1ResourcesInMap( uint32_t resType, struct FakeResourceMap* inMap )
+{
+ gFakeResError = noErr;
+
+ if( inMap != NULL )
+ {
+ for( int x = 0; x < inMap->numTypes; x++ )
+ {
+ uint32_t currType = inMap->typeList[x].resourceType;
+ if( currType == resType )
+ return inMap->typeList[x].numberOfResourcesOfType;
+ }
+ }
+
+ return 0;
+}
+
+
+int16_t FakeCount1TypesInMap( struct FakeResourceMap* inMap )
+{
+ if( inMap == NULL )
+ return 0;
+
+ return inMap->numTypes;
+}
+
+
+int16_t FakeCount1Types()
+{
+ return FakeCount1TypesInMap( gCurrResourceMap );
+}
+
+
+int16_t FakeCount1Resources( uint32_t resType )
+{
+ return FakeCount1ResourcesInMap( resType, gCurrResourceMap );
+}
+
+
+int16_t FakeCountResources( uint32_t resType )
+{
+ int16_t numRes = 0;
+ struct FakeResourceMap* theMap = gCurrResourceMap;
+
+ while( theMap )
+ {
+ numRes += FakeCount1ResourcesInMap( resType, theMap );
+
+ theMap = theMap->nextResourceMap;
+ }
+
+ return numRes;
+}
+
+
+int16_t FakeCountTypes()
+{
+ return gNumLoadedTypes;
+}
+
+
+int16_t FakeCurResFile()
+{
+ struct FakeResourceMap* currMap = gCurrResourceMap;
+
+ if( !currMap )
+ return 0;
+
+ return currMap->fileRefNum;
+}
+
+void FakeUseResFile( int16_t resRefNum )
+{
+ struct FakeResourceMap* currMap = FakeFindResourceMap( resRefNum, NULL );
+ if( !currMap )
+ currMap = gResourceMap;
+
+ gCurrResourceMap = currMap;
+}
+
+
+void FakeGet1IndType( uint32_t * resType, int16_t index )
+{
+ if( resType == NULL )
+ return;
+
+ *resType = 0;
+
+ struct FakeResourceMap* currMap = gCurrResourceMap;
+ if( (index <= 0) || (index > FakeCount1Types()) || !currMap )
+ {
+ gFakeResError = resNotFound;
+ return;
+ }
+
+ *resType = currMap->typeList[index-1].resourceType;
+
+ gFakeResError = noErr;
+}
+
+Handle FakeGet1IndResource( uint32_t resType, int16_t index )
+{
+ struct FakeResourceMap* currMap = gCurrResourceMap;
+
+ if( !currMap || (index <= 0) || (index > FakeCount1Resources(resType)))
+ {
+ gFakeResError = resNotFound;
+ }
+
+ for( int x = 0; x < currMap->numTypes; x++ )
+ {
+ uint32_t currType = currMap->typeList[x].resourceType;
+ if( currType == resType )
+ {
+ gFakeResError = noErr;
+ return currMap->typeList[x].resourceList[index-1].resourceHandle;
+ }
+ }
+
+ gFakeResError = resNotFound;
+
+ return NULL;
+}
+
+void FakeGetResInfo( Handle theResource, int16_t * theID, uint32_t * theType, FakeStr255 * name )
+{
+ struct FakeTypeListEntry* typeEntry = NULL;
+ struct FakeReferenceListEntry* refEntry = NULL;
+
+
+ if( FakeFindResourceHandle(theResource, NULL, &typeEntry, &refEntry) )
+ {
+ gFakeResError = noErr;
+ if( theID )
+ {
+ *theID = refEntry->resourceID;
+ }
+
+ if( theType )
+ {
+ *theType = typeEntry->resourceType;
+ }
+
+ if( name )
+ {
+ memcpy(name, refEntry->resourceName, sizeof(FakeStr255));
+ }
+ return;
+ }
+
+ gFakeResError = resNotFound;
+}
+
+
+void FakeSetResInfo( Handle theResource, int16_t theID, FakeStr255 name )
+{
+ struct FakeReferenceListEntry* refEntry = NULL;
+
+ if( !theResource || !FakeFindResourceHandle( theResource, NULL, NULL, &refEntry) )
+ {
+ gFakeResError = resNotFound;
+ return;
+ }
+
+ if( (refEntry->resourceAttributes & resProtected) != 0 )
+ {
+ gFakeResError = resAttrErr;
+ return;
+ }
+
+ refEntry->resourceID = theID;
+ memcpy(refEntry->resourceName, name, sizeof(FakeStr255));
+
+ gFakeResError = noErr;
+}
+
+
+void FakeAddResource( Handle theData, uint32_t theType, int16_t theID, FakeStr255 name )
+{
+ struct FakeResourceMap* currMap = gCurrResourceMap;
+ struct FakeTypeListEntry* typeEntry = NULL;
+ struct FakeReferenceListEntry* resourceEntry = NULL;
+
+ // AddResource() only ensures that the handle is not a resource, but doesn't check whether the type/ID are already in use
+ if( !theData || FakeFindResourceHandleInMap( theData, &typeEntry, &resourceEntry, currMap ) )
+ {
+ gFakeResError = addResFailed;
+ return;
+ }
+
+ typeEntry = FakeFindTypeListEntry( currMap, theType );
+ if( !typeEntry )
+ {
+ currMap->numTypes++;
+ currMap->typeList = realloc(currMap->typeList, currMap->numTypes * sizeof(struct FakeTypeListEntry));
+
+ typeEntry = currMap->typeList + (currMap->numTypes - 1);
+ typeEntry->resourceType = theType;
+ typeEntry->numberOfResourcesOfType = 0;
+ typeEntry->resourceList = NULL;
+
+ FakeRetainType(theType);
+ }
+
+ typeEntry->numberOfResourcesOfType++;
+
+ if( typeEntry->resourceList )
+ {
+ typeEntry->resourceList = realloc( typeEntry->resourceList, typeEntry->numberOfResourcesOfType * sizeof(struct FakeReferenceListEntry) );
+ }
+ else
+ {
+ typeEntry->resourceList = calloc(typeEntry->numberOfResourcesOfType, sizeof(struct FakeReferenceListEntry));
+ }
+
+ resourceEntry = typeEntry->resourceList + ( typeEntry->numberOfResourcesOfType - 1 );
+ resourceEntry->resourceAttributes = 0;
+ resourceEntry->resourceID = theID;
+ memcpy(resourceEntry->resourceName, name, sizeof(FakeStr255));
+ resourceEntry->resourceHandle = theData;
+
+ currMap->dirty = true;
+
+ gFakeResError = noErr;
+}
+
+void FakeChangedResource( Handle theResource )
+{
+ struct FakeResourceMap* theMap = NULL;
+ struct FakeReferenceListEntry* theEntry = NULL;
+ if( !FakeFindResourceHandle( theResource, &theMap, NULL, &theEntry ) )
+ {
+ gFakeResError = resNotFound;
+ return;
+ }
+
+ if( (theEntry->resourceAttributes & resProtected) == 0 )
+ {
+ theMap->dirty = true;
+ gFakeResError = noErr;
+ }
+ else
+ {
+ gFakeResError = resAttrErr;
+ }
+}
+
+// NOTE: you must call DisposeHandle(theResource) manually to release the memory. Normally,
+// the Resource Manager will dispose the handle on update or file close, but this implementation
+// does not track removed resource handles for later disposal.
+void FakeRemoveResource( Handle theResource )
+{
+ struct FakeResourceMap* currMap = gCurrResourceMap;
+ struct FakeTypeListEntry* typeEntry = NULL;
+ struct FakeReferenceListEntry* resEntry = NULL;
+ if( !currMap || !FakeFindResourceHandleInMap( theResource, &typeEntry, &resEntry, currMap ) || ((resEntry->resourceAttributes & resProtected) != 0) )
+ {
+ gFakeResError = rmvResFailed;
+ return;
+ }
+
+ struct FakeReferenceListEntry* nextResEntry = resEntry + 1;
+ int resourcesListSize = typeEntry->numberOfResourcesOfType * sizeof(struct FakeReferenceListEntry);
+ long nextResEntryOffset = (void*)nextResEntry - (void*)typeEntry->resourceList;
+
+ typeEntry->numberOfResourcesOfType--;
+
+ if( typeEntry->numberOfResourcesOfType > 0 )
+ {
+ memcpy( resEntry, nextResEntry, resourcesListSize - nextResEntryOffset );
+ typeEntry->resourceList = realloc( typeEntry->resourceList, resourcesListSize - sizeof(struct FakeReferenceListEntry) );
+ }
+ else
+ {
+ // got rid of the last resource reference, release the memory
+ free(typeEntry->resourceList);
+ typeEntry->resourceList = NULL;
+
+ // now remove the type entry
+ struct FakeTypeListEntry* nextTypeEntry = typeEntry + 1;
+ int typeListSize = currMap->numTypes * sizeof(struct FakeTypeListEntry);
+ long nextTypeEntryOffset = (void*)nextTypeEntry - (void*)currMap->typeList;
+
+ currMap->numTypes--;
+ FakeReleaseType(typeEntry->resourceType);
+
+ if( currMap->numTypes > 0 )
+ {
+ memcpy( typeEntry, nextTypeEntry, typeListSize - nextTypeEntryOffset );
+ currMap->typeList = realloc( currMap->typeList, typeListSize - sizeof(struct FakeTypeListEntry) );
+ }
+ else
+ {
+ // got rid of the last type entry
+ free(currMap->typeList);
+ currMap->typeList = NULL;
+ }
+ }
+
+
+ currMap->dirty = true;
+ gFakeResError = noErr;
+}
+
+
+// NOTE: effectively a no-op since we don't have a way to write a resource without writing the whole map
+void FakeWriteResource( Handle theResource )
+{
+ struct FakeReferenceListEntry* resEntry = NULL;
+ if( !theResource || !FakeFindResourceHandle( theResource, NULL, NULL, &resEntry ))
+ {
+ gFakeResError = resNotFound;
+ }
+ else
+ {
+ gFakeResError = noErr;
+ }
+}
+
+// NOTE: effectively a no-op since we don't have a way to load an individual resource from disk right now.
+// All resources are already loaded at file open time.
+void FakeLoadResource( Handle theResource )
+{
+ struct FakeReferenceListEntry* resEntry = NULL;
+ if( !theResource || !FakeFindResourceHandle( theResource, NULL, NULL, &resEntry ))
+ {
+ gFakeResError = resNotFound;
+ }
+ else
+ {
+ gFakeResError = noErr;
+ }
+}
+
+// NOTE: effectively a no-op since we don't have a way to reload a released resource from disk right now
+void FakeReleaseResource( Handle theResource )
+{
+ struct FakeReferenceListEntry* resEntry = NULL;
+ if( !theResource || !FakeFindResourceHandle( theResource, NULL, NULL, &resEntry ))
+ {
+ gFakeResError = resNotFound;
+ }
+ else
+ {
+ gFakeResError = noErr;
+ }
+}
+
+
+void FakeSetResLoad(bool load)
+{
+ // NOTE: a no-op since resources are always loaded at file open time
+}
+
+
+
diff --git a/macosx/ReClassicfication/FakeResources.h b/macosx/ReClassicfication/FakeResources.h
new file mode 100755
index 00000000..0792d503
--- /dev/null
+++ b/macosx/ReClassicfication/FakeResources.h
@@ -0,0 +1,84 @@
+//
+// FakeResources.h
+// ReClassicfication
+//
+// Created by Uli Kusterer on 21.02.13.
+// Copyright (c) 2013 Uli Kusterer. All rights reserved.
+//
+
+#ifndef ReClassicfication_FakeResources_h
+#define ReClassicfication_FakeResources_h
+
+
+#include "FakeHandles.h"
+
+
+// Possible return values of FakeResError():
+#ifndef __MACERRORS__
+enum
+{
+ resNotFound = -192,
+ resFNotFound = -193,
+ addResFailed = -194,
+ rmvResFailed = -196,
+ resAttrErr = -198,
+ eofErr = -39,
+ fnfErr = -43
+};
+#endif /* __MACERRORS__ */
+
+
+#ifndef __RESOURCES__
+// Resource attribute bit flags:
+enum
+{
+ resReserved = (1 << 0), // Apparently not yet used.
+ resChanged = (1 << 1),
+ resPreload = (1 << 2),
+ resProtected = (1 << 3),
+ resLocked = (1 << 4),
+ resPurgeable = (1 << 5),
+ resSysHeap = (1 << 6),
+ resReserved2 = (1 << 7) // Apparently not yet used.
+};
+#endif
+
+typedef unsigned char FakeStr255[256];
+
+
+int16_t FakeOpenResFile( const unsigned char* inPath );
+void FakeCloseResFile( int16_t resRefNum );
+Handle FakeGet1Resource( uint32_t resType, int16_t resID );
+Handle FakeGetResource( uint32_t resType, int16_t resID );
+int16_t FakeCurResFile();
+void FakeUseResFile( int16_t resRefNum );
+void FakeUpdateResFile( int16_t inFileRefNum );
+int16_t FakeHomeResFile( Handle theResource );
+int16_t FakeCount1Types();
+int16_t FakeCount1Resources( uint32_t resType );
+int16_t FakeCountTypes();
+int16_t FakeCountResources( uint32_t resType );
+
+void FakeGet1IndType( uint32_t * resType, int16_t index );
+Handle FakeGet1IndResource( uint32_t resType, int16_t index );
+void FakeGetResInfo( Handle theResource, int16_t * theID, uint32_t * theType, FakeStr255 * name );
+void FakeSetResInfo( Handle theResource, int16_t theID, FakeStr255 name );
+void FakeAddResource( Handle theData, uint32_t theType, int16_t theID, FakeStr255 name );
+void FakeChangedResource( Handle theResource );
+void FakeRemoveResource( Handle theResource );
+void FakeWriteResource( Handle theResource );
+void FakeLoadResource( Handle theResource );
+void FakeReleaseResource( Handle theResource );
+void FakeSetResLoad(bool load);
+
+int16_t FakeResError();
+
+
+// Private calls for internal use/tests:
+void FakeRedirectResFileToPath( int16_t inFileRefNum, const char* cPath );
+struct FakeResourceMap* FakeResFileOpen( const char* inPath, const char* inMode );
+struct FakeResourceMap* FakeFindResourceMap( int16_t inFileRefNum, struct FakeResourceMap*** outPrevMapPtr );
+int16_t FakeCount1ResourcesInMap( uint32_t resType, struct FakeResourceMap* inMap );
+int16_t FakeCount1TypesInMap( struct FakeResourceMap* inMap );
+
+#endif
diff --git a/macosx/Snes9x/AppDelegate.h b/macosx/Snes9x/AppDelegate.h
new file mode 100644
index 00000000..ec6ff939
--- /dev/null
+++ b/macosx/Snes9x/AppDelegate.h
@@ -0,0 +1,47 @@
+/*****************************************************************************\
+ Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
+
+/***********************************************************************************
+ SNES9X for Mac OS (c) Copyright John Stiles
+
+ Snes9x for Mac OS X
+
+ (c) Copyright 2001 - 2011 zones
+ (c) Copyright 2002 - 2005 107
+ (c) Copyright 2002 PB1400c
+ (c) Copyright 2004 Alexander and Sander
+ (c) Copyright 2004 - 2005 Steven Seeger
+ (c) Copyright 2005 Ryan Vogt
+ (c) Copyright 2019 Michael Donald Buckley
+ ***********************************************************************************/
+
+#import
+#import
+
+@interface AppDelegate : NSObject
+
+@property (nonatomic, readonly, assign) BOOL isRunningEmulation;
+
+- (void)setButtonCode:(S9xButtonCode)buttonCode forKeyCode:(int16)keyCode player:(int8)player;
+- (void)clearButton:(S9xButtonCode)button forPlayer:(int8)player;
+
+- (NSArray *)listJoypads;
+- (void)setPlayer:(int8)player forVendorID:(uint32)vendorID productID:(uint32)productID index:(uint32)index;
+- (BOOL)setButton:(S9xButtonCode)button forVendorID:(uint32)vendorID productID:(uint32)productID index:(uint32)index cookie:(uint32)cookie value:(int32)value;
+- (void)clearJoypadForVendorID:(uint32)vendorID productID:(uint32)productID index:(uint32)index buttonCode:(S9xButtonCode)buttonCode;
+- (NSString *)labelForVendorID:(uint32)vendorID productID:(uint32)productID cookie:(uint32)cookie value:(int32)value;
+
+- (NSString *)prefsKeyForVendorID:(uint32)vendorID productID:(uint32)productID index:(uint32)index;
+- (BOOL)getValuesFromString:(NSString *)str vendorID:(uint32 *)vendorID productID:(uint32 *)productID index:(uint32 *)index;
+
+- (NSString *)prefValueForCookie:(uint32)cookie value:(int32)value;
+- (BOOL)getValuesFromString:(NSString *)str cookie:(uint32 *)cookie value:(int32 *)value;
+
+- (void)setVideoMode:(int)videoMode;
+- (void)setShowFPS:(BOOL)showFPS;
+
+@end
+
diff --git a/macosx/Snes9x/AppDelegate.m b/macosx/Snes9x/AppDelegate.m
new file mode 100644
index 00000000..d7e8e041
--- /dev/null
+++ b/macosx/Snes9x/AppDelegate.m
@@ -0,0 +1,516 @@
+/*****************************************************************************\
+ Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
+
+/***********************************************************************************
+ SNES9X for Mac OS (c) Copyright John Stiles
+
+ Snes9x for Mac OS X
+
+ (c) Copyright 2001 - 2011 zones
+ (c) Copyright 2002 - 2005 107
+ (c) Copyright 2002 PB1400c
+ (c) Copyright 2004 Alexander and Sander
+ (c) Copyright 2004 - 2005 Steven Seeger
+ (c) Copyright 2005 Ryan Vogt
+ (c) Copyright 2019 Michael Donald Buckley
+ ***********************************************************************************/
+
+#import
+
+#import "AppDelegate.h"
+
+#import "S9xPrefsConstants.h"
+#import "S9xPrefsViewController.h"
+
+@interface AppDelegate ()
+@property (nonatomic, strong) S9xEngine *s9xEngine;
+@property (nonatomic, strong) NSMutableDictionary *keys;
+@property (nonatomic, strong) NSWindow *window;
+@property (nonatomic, strong, nullable) NSWindowController *prefsWindowController;
+@end
+
+static NSWindowFrameAutosaveName const kMainWindowIdentifier = @"s9xMainWindow";
+
+@implementation AppDelegate
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
+ self.s9xEngine = [S9xEngine new];
+ self.s9xEngine.inputDelegate = self;
+ [self setupDefaults];
+ [self importRecentItems];
+
+ NSWindow *window = [[NSWindow alloc] initWithContentRect:s9xView.frame styleMask:NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskMiniaturizable|NSWindowStyleMaskResizable backing:NSBackingStoreBuffered defer:NO];
+
+ window.contentView.wantsLayer = YES;
+ window.contentView.layer.backgroundColor = NSColor.blackColor.CGColor;
+
+ window.title = @"Snes9x";
+ window.restorationClass = [self class];
+ window.frameAutosaveName = kMainWindowIdentifier;
+ window.releasedWhenClosed = NO;
+
+ [window.contentView addSubview:s9xView];
+ [s9xView.topAnchor constraintEqualToAnchor:window.contentView.topAnchor].active = YES;
+ [s9xView.bottomAnchor constraintEqualToAnchor:window.contentView.bottomAnchor].active = YES;
+ [s9xView.centerXAnchor constraintEqualToAnchor:window.contentView.centerXAnchor].active = YES;
+ [s9xView.leftAnchor constraintGreaterThanOrEqualToAnchor:window.contentView.leftAnchor].active = YES;
+ [s9xView.rightAnchor constraintLessThanOrEqualToAnchor:window.contentView.rightAnchor].active = YES;
+
+ if ( ![window setFrameUsingName:kMainWindowIdentifier] )
+ {
+ [window center];
+ }
+
+ self.window = window;
+
+ [NSNotificationCenter.defaultCenter addObserverForName:NSWindowWillCloseNotification object:window queue:NSOperationQueue.mainQueue usingBlock:^(NSNotification *notification)
+ {
+ [self.s9xEngine pause];
+ }];
+}
+
+- (void)applicationWillTerminate:(NSNotification *)aNotification {
+ // Insert code here to tear down your application
+}
+
+- (void)setupDefaults
+{
+ NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
+
+ NSDictionary *defaultSettings = @{
+ kKeyboardPrefs : @{
+ @(kUp).stringValue : @(kVK_UpArrow),
+ @(kDown).stringValue : @(kVK_DownArrow),
+ @(kLeft).stringValue : @(kVK_LeftArrow),
+ @(kRight).stringValue : @(kVK_RightArrow),
+ @(kY).stringValue : @(kVK_ANSI_X),
+ @(kB).stringValue : @(kVK_ANSI_C),
+ @(kX).stringValue : @(kVK_ANSI_D),
+ @(kA).stringValue : @(kVK_ANSI_V),
+ @(kL).stringValue : @(kVK_ANSI_A),
+ @(kR).stringValue : @(kVK_ANSI_S),
+ @(kStart).stringValue : @(kVK_Space),
+ @(kSelect).stringValue : @(kVK_Return),
+
+ @(kNumButtons + kUp).stringValue : @(kVK_ANSI_Keypad8),
+ @(kNumButtons + kDown).stringValue : @(kVK_ANSI_Keypad2),
+ @(kNumButtons + kLeft).stringValue : @(kVK_ANSI_Keypad4),
+ @(kNumButtons + kRight).stringValue : @(kVK_ANSI_Keypad6),
+ @(kNumButtons + kY).stringValue : @(kVK_PageDown),
+ @(kNumButtons + kB).stringValue : @(kVK_PageUp),
+ @(kNumButtons + kX).stringValue : @(kVK_End),
+ @(kNumButtons + kA).stringValue : @(kVK_Home),
+ @(kNumButtons + kL).stringValue : @(kVK_ANSI_Keypad0),
+ @(kNumButtons + kR).stringValue : @(kVK_ANSI_KeypadDecimal),
+ @(kNumButtons + kStart).stringValue : @(kVK_ANSI_KeypadEnter),
+ @(kNumButtons + kSelect).stringValue : @(kVK_ANSI_KeypadPlus),
+
+ @(kKeyFastForward).stringValue : @(kVK_ANSI_Backslash),
+ @(kKeyFreeze).stringValue : @(kVK_ANSI_1),
+ @(kKeyDefrost).stringValue : @(kVK_ANSI_0),
+ @(kKeyScreenshot).stringValue : @(kVK_ANSI_Grave),
+ @(kKeySPC).stringValue : @(kVK_ANSI_R),
+ @(kKeyScopeTurbo).stringValue : @(kVK_ANSI_B),
+ @(kKeyScopePause).stringValue : @(kVK_ANSI_N),
+ @(kKeyScopeCursor).stringValue : @(kVK_ANSI_M),
+ @(kKeyOffScreen).stringValue : @(kVK_Tab),
+ @(kKeyFunction).stringValue : @(kVK_ANSI_Slash),
+ @(kKeyAlt).stringValue : @(kVK_ANSI_Period),
+ @(kKeyFFDown).stringValue : @(kVK_ANSI_Q),
+ @(kKeyFFUp).stringValue : @(kVK_ANSI_W),
+ @(kKeyEsc).stringValue : @(kVK_Escape),
+ @(kKeyTC).stringValue : @(kVK_ANSI_Comma)
+ },
+ kShowFPSPref: @(NO),
+ kVideoModePref:@(VIDEOMODE_BLOCKY)
+ };
+
+ [defaults registerDefaults:defaultSettings];
+
+ self.keys = [[defaults objectForKey:kKeyboardPrefs] mutableCopy];
+
+ for (NSString *control in [self.keys copy])
+ {
+ NSInteger key = control.integerValue;
+ NSInteger player = key / kNumButtons;
+ S9xButtonCode buttonCode = (S9xButtonCode)(key - (kNumButtons * player));
+ [self setButtonCode:buttonCode forKeyCode:self.keys[control].integerValue player:player];
+ }
+
+ for ( S9xJoypad *joypad in [self listJoypads])
+ {
+ NSMutableDictionary *joypadPrefs = [[defaults objectForKey:kJoypadInputPrefs] mutableCopy];
+
+ if (joypadPrefs == nil)
+ {
+ joypadPrefs = [NSMutableDictionary new];
+ [defaults synchronize];
+ }
+
+ NSString *key = [self prefsKeyForVendorID:joypad.vendorID productID:joypad.productID index:joypad.index];
+
+ NSMutableDictionary *devicePrefs = [joypadPrefs[key] mutableCopy];
+ if (devicePrefs == nil)
+ {
+ devicePrefs = [NSMutableDictionary new];
+ for (S9xJoypadInput *input in [self.s9xEngine getInputsForVendorID:joypad.vendorID productID:joypad.productID index:joypad.index])
+ {
+ devicePrefs[@(input.buttonCode).stringValue] = [self prefValueForCookie:input.cookie value:input.value];
+ }
+
+ joypadPrefs[key] = devicePrefs;
+ [defaults setObject:joypadPrefs forKey:kJoypadInputPrefs];
+ [defaults synchronize];
+ }
+ else
+ {
+ [self.s9xEngine clearJoypadForVendorID:joypad.vendorID productID:joypad.productID index:joypad.index];
+ for (NSString *buttonCodeString in devicePrefs)
+ {
+ S9xButtonCode buttonCode = (S9xButtonCode)buttonCodeString.intValue;
+ NSString *str = devicePrefs[buttonCodeString];
+ uint32 cookie = 0;
+ int32 value = -1;
+
+ if ([self getValuesFromString:str cookie:&cookie value:&value])
+ {
+ [self setButton:buttonCode forVendorID:joypad.vendorID productID:joypad.productID index:joypad.index cookie:cookie value:value];
+ }
+ }
+ }
+ }
+
+ [self importKeySettings];
+ [self importGraphicsSettings];
+ [defaults synchronize];
+}
+
+- (void)setButtonCode:(S9xButtonCode)buttonCode forKeyCode:(int16)keyCode player:(int8)player
+{
+ if (keyCode < 0)
+ {
+ return;
+ }
+
+ self.keys[@(buttonCode + (kNumButtons * player)).stringValue] = @(keyCode);
+
+ S9xButtonCode oldButton = kNumButtons;
+ int8 oldPlayer = -1;
+ if ([self.s9xEngine setButton:buttonCode forKey:keyCode player:player oldButton:&oldButton oldPlayer:&oldPlayer oldKey:NULL])
+ {
+ if (oldButton >= 0 && oldButton < kNumButtons && oldPlayer >= 0 && oldPlayer < MAC_MAX_PLAYERS && (oldPlayer != player || oldButton != buttonCode))
+ {
+ [self.keys removeObjectForKey:@(oldButton + (kNumButtons * oldPlayer)).stringValue];
+ }
+
+ [NSUserDefaults.standardUserDefaults setObject:[self.keys copy] forKey:kKeyboardPrefs];
+ }
+}
+
+- (void)clearButton:(S9xButtonCode)button forPlayer:(int8)player
+{
+ [self.s9xEngine clearButton:button forPlayer:player];
+ NSMutableDictionary *keyDict = [[NSUserDefaults.standardUserDefaults objectForKey:kKeyboardPrefs] mutableCopy];
+ [keyDict removeObjectForKey:@(button).stringValue];
+ [NSUserDefaults.standardUserDefaults setObject:[keyDict copy] forKey:kKeyboardPrefs];
+ [NSUserDefaults.standardUserDefaults synchronize];
+}
+
+- (NSArray *)listJoypads
+{
+ return [self.s9xEngine listJoypads];
+}
+
+- (NSString *)prefsKeyForVendorID:(uint32)vendorID productID:(uint32)productID index:(uint32)index
+{
+ return [NSString stringWithFormat:@"%@:%@:%@", @(vendorID).stringValue, @(productID).stringValue, @(index).stringValue];
+}
+
+- (BOOL)getValuesFromString:(NSString *)str vendorID:(uint32 *)vendorID productID:(uint32 *)productID index:(uint32 *)index
+{
+ if (vendorID == NULL || productID == NULL || index == NULL)
+ {
+ return NO;
+
+ }
+
+ NSArray *components = [str componentsSeparatedByString:@":"];
+
+ if (components.count != 3)
+ {
+ return NO;
+ }
+
+ *vendorID = components[0].intValue;
+ *productID = components[1].intValue;
+ *index = components[2].intValue;
+
+ return YES;
+}
+
+- (NSString *)prefValueForCookie:(uint32)cookie value:(int32)value
+{
+ return [NSString stringWithFormat:@"%@:%@", @(cookie).stringValue, @(value).stringValue];
+}
+
+- (BOOL)getValuesFromString:(NSString *)str cookie:(uint32 *)cookie value:(int32 *)value
+{
+ if (cookie == NULL || value == NULL)
+ {
+ return NO;
+ }
+
+ NSArray *components = [str componentsSeparatedByString:@":"];
+
+ if (components.count != 2)
+ {
+ return NO;
+ }
+
+ *cookie = components.firstObject.intValue;
+ *value = components.lastObject.intValue;
+
+ return YES;
+}
+
+- (void)setPlayer:(int8)player forVendorID:(uint32)vendorID productID:(uint32)productID index:(uint32)index
+{
+ int8 oldPlayer = -1;
+ [self.s9xEngine setPlayer:player forVendorID:vendorID productID:productID index:index oldPlayer:&oldPlayer];
+
+ NSMutableDictionary *playersDict = [[NSUserDefaults.standardUserDefaults objectForKey:kJoypadPlayerPrefs] mutableCopy];
+ if (playersDict == nil)
+ {
+ playersDict = [NSMutableDictionary new];
+ }
+
+ if (oldPlayer >= 0 && player != oldPlayer)
+ {
+ [playersDict removeObjectForKey:@(oldPlayer).stringValue];
+ }
+
+ playersDict[@(player).stringValue] = [self prefsKeyForVendorID:vendorID productID:productID index:index];
+
+ [NSUserDefaults.standardUserDefaults setObject:[playersDict copy] forKey:kJoypadPlayerPrefs];
+}
+
+- (BOOL)setButton:(S9xButtonCode)button forVendorID:(uint32)vendorID productID:(uint32)productID index:(uint32)index cookie:(uint32)cookie value:(int32)value
+{
+ S9xButtonCode oldButton = (S9xButtonCode)-1;
+ BOOL result = [self.s9xEngine setButton:button forVendorID:vendorID productID:productID index:index cookie:cookie value:value oldButton:&oldButton];
+
+ NSMutableDictionary *prefsDict = [[NSUserDefaults.standardUserDefaults objectForKey:kJoypadInputPrefs] mutableCopy];
+ NSString *key = [self prefsKeyForVendorID:vendorID productID:productID index:index];
+ NSMutableDictionary *joypadDict = [prefsDict[key] mutableCopy];
+
+ if (result && button != oldButton)
+ {
+ [joypadDict removeObjectForKey:@(oldButton).stringValue];
+ }
+
+ joypadDict[@(button).stringValue] = [self prefValueForCookie:cookie value:value];
+
+ prefsDict[key] = [joypadDict copy];
+
+ [NSUserDefaults.standardUserDefaults setObject:[prefsDict copy] forKey:kJoypadInputPrefs];
+
+ return result;
+}
+
+- (void)clearJoypadForVendorID:(uint32)vendorID productID:(uint32)productID index:(uint32)index buttonCode:(S9xButtonCode)buttonCode
+{
+ [self.s9xEngine clearJoypadForVendorID:vendorID productID:productID index:index buttonCode:buttonCode];
+ NSString *key = [self prefsKeyForVendorID:vendorID productID:productID index:index];
+ NSMutableDictionary *joypadsDict = [[NSUserDefaults.standardUserDefaults objectForKey:kJoypadInputPrefs] mutableCopy];
+ NSMutableDictionary *deviceDict = [joypadsDict[key] mutableCopy];
+ [deviceDict removeObjectForKey:@(buttonCode).stringValue];
+ joypadsDict[key] = deviceDict;
+ [NSUserDefaults.standardUserDefaults setObject:[joypadsDict copy] forKey:kJoypadInputPrefs];
+ [NSUserDefaults.standardUserDefaults synchronize];
+}
+
+- (NSString *)labelForVendorID:(uint32)vendorID productID:(uint32)productID cookie:(uint32)cookie value:(int32)value
+{
+ return [self.s9xEngine labelForVendorID:vendorID productID:productID cookie:cookie value:value];
+}
+
+- (void)importRecentItems
+{
+ const NSInteger maxRecents = 20;
+
+ for (NSInteger i = maxRecents - 1; i >= 0; --i)
+ {
+ NSString *key = [NSString stringWithFormat:@"RecentItem_%02tu", i];
+ NSString *recentItem = [NSUserDefaults.standardUserDefaults objectForKey:key];
+
+ if (recentItem != nil)
+ {
+ [NSDocumentController.sharedDocumentController noteNewRecentDocumentURL:[NSURL fileURLWithPath:recentItem]];
+ [NSUserDefaults.standardUserDefaults removeObjectForKey:key];
+ }
+ }
+
+ [[NSUserDefaults standardUserDefaults] synchronize];
+}
+
+- (void)importKeySettings
+{
+ NSData *data = [self objectForPrefOSCode:'keyb'];
+
+ NSUInteger length = data.length;
+ char *bytes = (char*)data.bytes;
+ for ( NSUInteger i = 0; i < length; ++i )
+ {
+ // The enum values for controls changed between the Carbon and Cocoa versions.
+ // The first 24 enum values are the same, but we have to adjust after that.
+ if ( i < 24 )
+ {
+ [self setButtonCode:(S9xButtonCode)(i - (i / 12)) forKeyCode:bytes[i] player:i / 12];
+ }
+ else
+ {
+ [self setButtonCode:(S9xButtonCode)(i - 24 + kKeyFastForward) forKeyCode:bytes[i] player:0];
+ }
+ }
+}
+
+- (void)importGraphicsSettings
+{
+ NSData *data = [self objectForPrefOSCode:'dfps'];
+
+ if (data != nil)
+ {
+ [NSUserDefaults.standardUserDefaults setBool:(data.length > 0 && ((char *)data.bytes)[0]) forKey:kShowFPSPref];
+ }
+
+ [self setShowFPS:[NSUserDefaults.standardUserDefaults boolForKey:kShowFPSPref]];
+
+ data = [self objectForPrefOSCode:'Vmod'];
+
+ if ( data != nil)
+ {
+ [NSUserDefaults.standardUserDefaults setInteger:((data.length >= 0 && ((char *)data.bytes)[0]) ? VIDEOMODE_SMOOTH : VIDEOMODE_BLOCKY) forKey:kVideoModePref];
+ }
+
+ [self setVideoMode:(int)[NSUserDefaults.standardUserDefaults integerForKey:kVideoModePref]];
+}
+
+- (id)objectForPrefOSCode:(uint32_t)osCode
+{
+ NSString *key = [@"Preferences_" stringByAppendingString:[[NSString alloc] initWithBytes:(char *)&osCode length:sizeof(uint32_t) encoding:NSASCIIStringEncoding]];
+
+ id obj = [NSUserDefaults.standardUserDefaults objectForKey:key];
+
+ if (obj == nil)
+ {
+ osCode =CFSwapInt32(osCode);
+ key = [@"Preferences_" stringByAppendingString:[[NSString alloc] initWithBytes:(char *)&osCode length:sizeof(uint32_t) encoding:NSASCIIStringEncoding]];
+
+ obj = [NSUserDefaults.standardUserDefaults objectForKey:key];
+
+ if (obj != nil)
+ {
+ [NSUserDefaults.standardUserDefaults removeObjectForKey:key];
+ }
+ }
+ else
+ {
+ [NSUserDefaults.standardUserDefaults removeObjectForKey:key];
+ }
+
+ return obj;
+}
+
+- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename
+{
+ return [self openURL:[NSURL fileURLWithPath:filename]];
+}
+
+- (IBAction)openDocument:(id)sender
+{
+ NSOpenPanel* panel = [NSOpenPanel new];
+ NSModalResponse response = [panel runModal];
+
+ if ( response == NSModalResponseOK )
+ {
+ [self openURL:panel.URL];
+ }
+}
+
+- (BOOL)openURL:(NSURL *)url
+{
+ if ([self.s9xEngine loadROM:url])
+ {
+
+ [self.window makeKeyAndOrderFront:self];
+ [NSDocumentController.sharedDocumentController noteNewRecentDocumentURL:url];
+ return YES;
+ }
+
+ return NO;
+}
+
+- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
+{
+ return !self.isRunningEmulation;
+}
+
+@dynamic isRunningEmulation;
+- (BOOL)isRunningEmulation
+{
+ return [self.s9xEngine isRunning] && ![self.s9xEngine isPaused];
+}
+
+- (IBAction)terminate:(id)sender
+{
+ [self.s9xEngine stop];
+ [NSApp terminate:sender];
+}
+
+- (IBAction)openPrefs:(id)sender
+{
+ if ( self.prefsWindowController == nil )
+ {
+ NSWindow *prefsWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100) styleMask:NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskMiniaturizable backing:NSBackingStoreBuffered defer:NO];
+ self.prefsWindowController = [[NSWindowController alloc] initWithWindow:prefsWindow];
+
+ prefsWindow.contentViewController = [[S9xPrefsViewController alloc] initWithNibName:@"S9xPrefsViewController" bundle:nil];
+ [prefsWindow center];
+ }
+
+ [self.prefsWindowController.window makeKeyAndOrderFront:self];
+}
+
+- (void)setVideoMode:(int)videoMode
+{
+ [self.s9xEngine setVideoMode:videoMode];
+ [NSUserDefaults.standardUserDefaults setObject:@(videoMode) forKey:kVideoModePref];
+ [NSUserDefaults.standardUserDefaults synchronize];
+}
+
+- (void)setShowFPS:(BOOL)showFPS
+{
+ [self.s9xEngine setShowFPS:showFPS];
+ [NSUserDefaults.standardUserDefaults setObject:@(showFPS) forKey:kShowFPSPref];
+ [NSUserDefaults.standardUserDefaults synchronize];
+}
+
+- (IBAction)resume:(id)sender
+{
+ [self.s9xEngine resume];
+}
+
+- (BOOL)handleInput:(S9xJoypadInput *)input fromJoypad:(S9xJoypad *)joypad
+{
+ if (NSApp.keyWindow != nil && NSApp.keyWindow == self.prefsWindowController.window)
+ {
+ return [((S9xPrefsViewController *) self.prefsWindowController.contentViewController) handleInput:input fromJoypad:joypad];
+ }
+
+ return NO;
+}
+
+@end
diff --git a/macosx/Snes9x/Assets.xcassets/AppIcon.appiconset/APPL-32.png b/macosx/Snes9x/Assets.xcassets/AppIcon.appiconset/APPL-32.png
new file mode 100644
index 00000000..9dcc3988
Binary files /dev/null and b/macosx/Snes9x/Assets.xcassets/AppIcon.appiconset/APPL-32.png differ
diff --git a/macosx/Snes9x/Assets.xcassets/AppIcon.appiconset/APPL.png b/macosx/Snes9x/Assets.xcassets/AppIcon.appiconset/APPL.png
new file mode 100644
index 00000000..ec01a517
Binary files /dev/null and b/macosx/Snes9x/Assets.xcassets/AppIcon.appiconset/APPL.png differ
diff --git a/macosx/Snes9x/Assets.xcassets/AppIcon.appiconset/Contents.json b/macosx/Snes9x/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 00000000..5fc768c2
--- /dev/null
+++ b/macosx/Snes9x/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,60 @@
+{
+ "images" : [
+ {
+ "idiom" : "mac",
+ "size" : "16x16",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "16x16",
+ "scale" : "2x"
+ },
+ {
+ "size" : "32x32",
+ "idiom" : "mac",
+ "filename" : "APPL-32.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "32x32",
+ "scale" : "2x"
+ },
+ {
+ "size" : "128x128",
+ "idiom" : "mac",
+ "filename" : "APPL.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "128x128",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "256x256",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "256x256",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "512x512",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "512x512",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/macosx/Snes9x/Assets.xcassets/Contents.json b/macosx/Snes9x/Assets.xcassets/Contents.json
new file mode 100644
index 00000000..da4a164c
--- /dev/null
+++ b/macosx/Snes9x/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/macosx/Snes9x/Base.lproj/MainMenu.xib b/macosx/Snes9x/Base.lproj/MainMenu.xib
new file mode 100644
index 00000000..106573e8
--- /dev/null
+++ b/macosx/Snes9x/Base.lproj/MainMenu.xib
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/macosx/Info_ppc.plist b/macosx/Snes9x/Info.plist
similarity index 90%
rename from macosx/Info_ppc.plist
rename to macosx/Snes9x/Info.plist
index 3bba90e4..d57cf226 100644
--- a/macosx/Info_ppc.plist
+++ b/macosx/Snes9x/Info.plist
@@ -3,7 +3,31 @@
CFBundleDevelopmentRegion
- English
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ LSMinimumSystemVersion
+ $(MACOSX_DEPLOYMENT_TARGET)
+ NSMainNibFile
+ MainMenu
+ CFBundleHelpBookFolder
+ Snes9x Help
+ CFBundleHelpBookName
+ Snes9x Help
+ NSPrincipalClass
+ S9xApplication
CFBundleDocumentTypes
@@ -159,31 +183,5 @@
- CFBundleExecutable
- Snes9x (ppc)
- CFBundleGetInfoString
- Snes9x 1.60, Copyright 1996-2019 Snes9x developers.
- CFBundleHelpBookFolder
- Snes9x Help
- CFBundleHelpBookName
- Snes9x Help
- CFBundleIconFile
- APPL.icns
- CFBundleIdentifier
- com.snes9x.macos.snes9x
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- Snes9x
- CFBundlePackageType
- APPL
- CFBundleShortVersionString
- 1.60
- CFBundleSignature
- ~9X~
- CFBundleVersion
- 1.60
- CSResourcesFileMapped
-
diff --git a/macosx/Snes9x/S9xApplication.h b/macosx/Snes9x/S9xApplication.h
new file mode 100644
index 00000000..54d737e9
--- /dev/null
+++ b/macosx/Snes9x/S9xApplication.h
@@ -0,0 +1,29 @@
+/*****************************************************************************\
+ Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
+
+/***********************************************************************************
+ SNES9X for Mac OS (c) Copyright John Stiles
+
+ Snes9x for Mac OS X
+
+ (c) Copyright 2001 - 2011 zones
+ (c) Copyright 2002 - 2005 107
+ (c) Copyright 2002 PB1400c
+ (c) Copyright 2004 Alexander and Sander
+ (c) Copyright 2004 - 2005 Steven Seeger
+ (c) Copyright 2005 Ryan Vogt
+ (c) Copyright 2019 Michael Donald Buckley
+ ***********************************************************************************/
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface S9xApplication : NSApplication
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/macosx/Snes9x/S9xApplication.m b/macosx/Snes9x/S9xApplication.m
new file mode 100644
index 00000000..98201a30
--- /dev/null
+++ b/macosx/Snes9x/S9xApplication.m
@@ -0,0 +1,38 @@
+/*****************************************************************************\
+ Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
+
+/***********************************************************************************
+ SNES9X for Mac OS (c) Copyright John Stiles
+
+ Snes9x for Mac OS X
+
+ (c) Copyright 2001 - 2011 zones
+ (c) Copyright 2002 - 2005 107
+ (c) Copyright 2002 PB1400c
+ (c) Copyright 2004 Alexander and Sander
+ (c) Copyright 2004 - 2005 Steven Seeger
+ (c) Copyright 2005 Ryan Vogt
+ (c) Copyright 2019 Michael Donald Buckley
+ ***********************************************************************************/
+
+#import "S9xApplication.h"
+#import "AppDelegate.h"
+
+@implementation S9xApplication
+
+- (void)sendEvent:(NSEvent *)event
+{
+ if (event.modifierFlags * NSEventModifierFlagCommand && event.type == NSEventTypeKeyUp && ((AppDelegate *)self.delegate).isRunningEmulation)
+ {
+ [self.keyWindow sendEvent:event];
+ }
+ else
+ {
+ [super sendEvent:event];
+ }
+}
+
+@end
diff --git a/macosx/Snes9x/S9xButtonConfigTextField.h b/macosx/Snes9x/S9xButtonConfigTextField.h
new file mode 100644
index 00000000..cd868031
--- /dev/null
+++ b/macosx/Snes9x/S9xButtonConfigTextField.h
@@ -0,0 +1,35 @@
+/*****************************************************************************\
+ Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
+
+/***********************************************************************************
+ SNES9X for Mac OS (c) Copyright John Stiles
+
+ Snes9x for Mac OS X
+
+ (c) Copyright 2001 - 2011 zones
+ (c) Copyright 2002 - 2005 107
+ (c) Copyright 2002 PB1400c
+ (c) Copyright 2004 Alexander and Sander
+ (c) Copyright 2004 - 2005 Steven Seeger
+ (c) Copyright 2005 Ryan Vogt
+ (c) Copyright 2019 Michael Donald Buckley
+ ***********************************************************************************/
+
+#import
+
+@class S9xJoypadInput;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface S9xButtonConfigTextField : NSSearchField
+
+@property (nonatomic, assign) CGKeyCode keyCode;
+@property (nonatomic, strong, nullable) S9xJoypadInput *joypadInput;
+@property (nonatomic, assign) BOOL disableKeyboardInput;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/macosx/Snes9x/S9xButtonConfigTextField.m b/macosx/Snes9x/S9xButtonConfigTextField.m
new file mode 100644
index 00000000..00eea7ec
--- /dev/null
+++ b/macosx/Snes9x/S9xButtonConfigTextField.m
@@ -0,0 +1,359 @@
+/*****************************************************************************\
+ Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
+
+/***********************************************************************************
+ SNES9X for Mac OS (c) Copyright John Stiles
+
+ Snes9x for Mac OS X
+
+ (c) Copyright 2001 - 2011 zones
+ (c) Copyright 2002 - 2005 107
+ (c) Copyright 2002 PB1400c
+ (c) Copyright 2004 Alexander and Sander
+ (c) Copyright 2004 - 2005 Steven Seeger
+ (c) Copyright 2005 Ryan Vogt
+ (c) Copyright 2019 Michael Donald Buckley
+ ***********************************************************************************/
+
+#include
+#include
+
+#import "S9xButtonConfigTextField.h"
+
+@implementation S9xButtonConfigTextField
+
+- (void)awakeFromNib
+{
+ self.delegate = self;
+ self.placeholderString = @"";
+ [[self cell] setSearchButtonCell:nil];
+
+ NSButtonCell *cancelButton = [[self cell] cancelButtonCell];
+ cancelButton.target = self;
+ cancelButton.action = @selector(clearSearch:);
+}
+
+- (void)setKeyCode:(CGKeyCode)keyCode
+{
+ if (keyCode == (CGKeyCode)-1)
+ {
+ _keyCode = keyCode;
+ self.stringValue = @"";
+ return;
+ }
+
+ NSString *stringValue = nil;
+
+ switch (keyCode)
+ {
+ case kVK_Shift:
+ stringValue = NSLocalizedString(@"Shift", @"");
+ break;
+
+ case kVK_Command:
+ stringValue = NSLocalizedString(@"Command", @"");
+ break;
+
+ case kVK_Control:
+ stringValue = NSLocalizedString(@"Control", @"");
+ break;
+
+ case kVK_Option:
+ stringValue = NSLocalizedString(@"Option", @"");
+ break;
+
+ case kVK_F1:
+ stringValue = NSLocalizedString(@"F1", @"");
+ break;
+
+ case kVK_F2:
+ stringValue = NSLocalizedString(@"F2", @"");
+ break;
+
+ case kVK_F3:
+ stringValue = NSLocalizedString(@"F3", @"");
+ break;
+
+ case kVK_F4:
+ stringValue = NSLocalizedString(@"F4", @"");
+ break;
+
+ case kVK_F5:
+ stringValue = NSLocalizedString(@"F5", @"");
+ break;
+
+ case kVK_F6:
+ stringValue = NSLocalizedString(@"F6", @"");
+ break;
+
+ case kVK_F7:
+ stringValue = NSLocalizedString(@"F7", @"");
+ break;
+
+ case kVK_F8:
+ stringValue = NSLocalizedString(@"F8", @"");
+ break;
+
+ case kVK_F9:
+ stringValue = NSLocalizedString(@"F9", @"");
+ break;
+
+ case kVK_F10:
+ stringValue = NSLocalizedString(@"F10", @"");
+ break;
+
+ case kVK_F11:
+ stringValue = NSLocalizedString(@"F11", @"");
+ break;
+
+ case kVK_F12:
+ stringValue = NSLocalizedString(@"F12", @"");
+ break;
+
+ case kVK_F13:
+ stringValue = NSLocalizedString(@"F13", @"");
+ break;
+
+ case kVK_F14:
+ stringValue = NSLocalizedString(@"F14", @"");
+ break;
+
+ case kVK_F15:
+ stringValue = NSLocalizedString(@"F15", @"");
+ break;
+
+ case kVK_F16:
+ stringValue = NSLocalizedString(@"F16", @"");
+ break;
+
+ case kVK_F17:
+ stringValue = NSLocalizedString(@"F17", @"");
+ break;
+
+ case kVK_F18:
+ stringValue = NSLocalizedString(@"F18", @"");
+ break;
+
+ case kVK_F19:
+ stringValue = NSLocalizedString(@"F19", @"");
+ break;
+
+ case kVK_F20:
+ stringValue = NSLocalizedString(@"F20", @"");
+ break;
+
+ case kVK_Delete:
+ stringValue = NSLocalizedString(@"Delete", @"");
+ break;
+
+ case kVK_ForwardDelete:
+ stringValue = NSLocalizedString(@"⌦", @"");
+ break;
+
+ case kVK_Home:
+ stringValue = NSLocalizedString(@"Home", @"");
+ break;
+
+ case kVK_End:
+ stringValue = NSLocalizedString(@"End", @"");
+ break;
+
+ case kVK_PageUp:
+ stringValue = NSLocalizedString(@"Page Up", @"");
+ break;
+
+ case kVK_PageDown:
+ stringValue = NSLocalizedString(@"Page Down", @"");
+ break;
+
+ case kVK_Tab:
+ stringValue = NSLocalizedString(@"Tab", @"");
+ break;
+
+ case kVK_Space:
+ stringValue = NSLocalizedString(@"Space", @"");
+ break;
+
+ case kVK_ANSI_KeypadClear:
+ stringValue = NSLocalizedString(@"Clear", @"");
+ break;
+
+ case kVK_LeftArrow:
+ stringValue = NSLocalizedString(@"←", @"");
+ break;
+
+ case kVK_RightArrow:
+ stringValue = NSLocalizedString(@"→", @"");
+ break;
+
+ case kVK_UpArrow:
+ stringValue = NSLocalizedString(@"↑", @"");
+ break;
+
+ case kVK_DownArrow:
+ stringValue = NSLocalizedString(@"↓", @"");
+ break;
+
+ case kVK_Return:
+ stringValue = NSLocalizedString(@"Return", @"");
+ break;
+
+ case kVK_ANSI_KeypadEnter:
+ stringValue = NSLocalizedString(@"Enter", @"");
+ break;
+
+ case kVK_Escape:
+ stringValue = NSLocalizedString(@"Escape", @"");
+ break;
+
+ default:
+ {
+ TISInputSourceRef keyboard = TISCopyCurrentKeyboardInputSource();
+ CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData);
+
+ if ( layoutData != NULL )
+ {
+ const UCKeyboardLayout *layout = (const UCKeyboardLayout*)CFDataGetBytePtr(layoutData);
+ UniCharCount maxStringLength = 0xFF;
+ UniCharCount actualStringLength = 0;
+ UniChar unicodeString[maxStringLength];
+ uint32_t deadKeyState = 0;
+
+ OSErr status = UCKeyTranslate(layout, keyCode, kUCKeyActionDisplay, kUCKeyTranslateNoDeadKeysBit, LMGetKbdType(), 0, &deadKeyState, maxStringLength, &actualStringLength, unicodeString);
+
+ if (status == noErr && actualStringLength > 0)
+ {
+ stringValue = [NSString stringWithCharacters:unicodeString length:actualStringLength];
+
+ switch (keyCode)
+ {
+ case kVK_ANSI_Keypad0:
+ case kVK_ANSI_Keypad1:
+ case kVK_ANSI_Keypad2:
+ case kVK_ANSI_Keypad3:
+ case kVK_ANSI_Keypad4:
+ case kVK_ANSI_Keypad5:
+ case kVK_ANSI_Keypad6:
+ case kVK_ANSI_Keypad7:
+ case kVK_ANSI_Keypad8:
+ case kVK_ANSI_Keypad9:
+ case kVK_ANSI_KeypadPlus:
+ case kVK_ANSI_KeypadMinus:
+ case kVK_ANSI_KeypadDivide:
+ case kVK_ANSI_KeypadMultiply:
+ case kVK_ANSI_KeypadEquals:
+ case kVK_ANSI_KeypadDecimal:
+ stringValue = [[stringValue stringByAppendingString:@" "] stringByAppendingString:NSLocalizedString(@"(Keypad)", @"")];
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if ( stringValue != nil )
+ {
+ stringValue = [[stringValue componentsSeparatedByCharactersInSet:NSCharacterSet.controlCharacterSet] componentsJoinedByString:@""];
+ stringValue = [[stringValue componentsSeparatedByCharactersInSet:NSCharacterSet.newlineCharacterSet] componentsJoinedByString:@""];
+ stringValue = [[stringValue componentsSeparatedByCharactersInSet:NSCharacterSet.illegalCharacterSet] componentsJoinedByString:@""];
+
+ if ( stringValue.length > 0 )
+ {
+ self.stringValue = stringValue.capitalizedString;
+ [self.window makeFirstResponder:self.window.contentView];
+ }
+ }
+
+ _keyCode = keyCode;
+}
+
+- (void)controlTextDidChange:(NSNotification *)obj
+{
+ self.stringValue = @"";
+}
+
+- (void)keyUp:(NSEvent *)event
+{
+ if (!self.disableKeyboardInput )
+ {
+ [self setKeyCode:event.keyCode];
+ }
+}
+
+- (void)flagsChanged:(NSEvent *)event
+{
+ if (self.disableKeyboardInput)
+ {
+ return;
+ }
+
+ NSEventModifierFlags flags = event.modifierFlags;
+
+ if ( flags & NSEventModifierFlagShift )
+ {
+ [self setKeyCode:kVK_Shift];
+ }
+ else if ( flags & NSEventModifierFlagOption )
+ {
+ [self setKeyCode:kVK_Option];
+ }
+ else if ( flags & NSEventModifierFlagCommand )
+ {
+ [self setKeyCode:kVK_Command];
+ }
+ else if ( flags & NSEventModifierFlagControl )
+ {
+ [self setKeyCode:kVK_Control];
+ }
+}
+
+- (void)mouseDown:(NSEvent *)event
+{
+ [super mouseDown:event];
+ [self.currentEditor selectAll:self];
+}
+
+- (void)clearSearch:(id)sender
+{
+ self.stringValue = @"";
+
+ if (self.disableKeyboardInput)
+ {
+ self.joypadInput = nil;
+ }
+ else
+ {
+ self.keyCode = -1;
+ }
+}
+
+- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector
+{
+ if (self.disableKeyboardInput)
+ {
+ return NO;
+ }
+
+ if (commandSelector == @selector(insertTab:))
+ {
+ [self setKeyCode:kVK_Tab];
+ return YES;
+ }
+ else if (commandSelector == @selector(cancelOperation:))
+ {
+ [self setKeyCode:kVK_Escape];
+ return YES;
+ }
+
+ return NO;
+}
+
+- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor
+{
+ return !self.disableKeyboardInput;
+}
+
+@end
diff --git a/macosx/Snes9x/S9xPrefsConstants.h b/macosx/Snes9x/S9xPrefsConstants.h
new file mode 100644
index 00000000..ad6351d0
--- /dev/null
+++ b/macosx/Snes9x/S9xPrefsConstants.h
@@ -0,0 +1,27 @@
+/*****************************************************************************\
+ Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
+
+/***********************************************************************************
+ SNES9X for Mac OS (c) Copyright John Stiles
+
+ Snes9x for Mac OS X
+
+ (c) Copyright 2001 - 2011 zones
+ (c) Copyright 2002 - 2005 107
+ (c) Copyright 2002 PB1400c
+ (c) Copyright 2004 Alexander and Sander
+ (c) Copyright 2004 - 2005 Steven Seeger
+ (c) Copyright 2005 Ryan Vogt
+ (c) Copyright 2019 Michael Donald Buckley
+ ***********************************************************************************/
+
+#import
+
+extern NSString * const kKeyboardPrefs;
+extern NSString * const kJoypadInputPrefs;
+extern NSString * const kJoypadPlayerPrefs;
+extern NSString * const kShowFPSPref;
+extern NSString * const kVideoModePref;
diff --git a/macosx/Snes9x/S9xPrefsConstants.m b/macosx/Snes9x/S9xPrefsConstants.m
new file mode 100644
index 00000000..c4228317
--- /dev/null
+++ b/macosx/Snes9x/S9xPrefsConstants.m
@@ -0,0 +1,27 @@
+/*****************************************************************************\
+ Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
+
+/***********************************************************************************
+ SNES9X for Mac OS (c) Copyright John Stiles
+
+ Snes9x for Mac OS X
+
+ (c) Copyright 2001 - 2011 zones
+ (c) Copyright 2002 - 2005 107
+ (c) Copyright 2002 PB1400c
+ (c) Copyright 2004 Alexander and Sander
+ (c) Copyright 2004 - 2005 Steven Seeger
+ (c) Copyright 2005 Ryan Vogt
+ (c) Copyright 2019 Michael Donald Buckley
+ ***********************************************************************************/
+
+#import "S9xPrefsConstants.h"
+
+NSString * const kKeyboardPrefs = @"KeyboardConfig";
+NSString * const kJoypadInputPrefs = @"JoypadInputs";
+NSString * const kJoypadPlayerPrefs = @"JoypadPlayers";
+NSString * const kShowFPSPref = @"ShowFPS";
+NSString * const kVideoModePref = @"VideoMode";
diff --git a/macosx/Snes9x/S9xPrefsViewController.h b/macosx/Snes9x/S9xPrefsViewController.h
new file mode 100644
index 00000000..bc3b908c
--- /dev/null
+++ b/macosx/Snes9x/S9xPrefsViewController.h
@@ -0,0 +1,28 @@
+/*****************************************************************************\
+ Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
+
+/***********************************************************************************
+ SNES9X for Mac OS (c) Copyright John Stiles
+
+ Snes9x for Mac OS X
+
+ (c) Copyright 2001 - 2011 zones
+ (c) Copyright 2002 - 2005 107
+ (c) Copyright 2002 PB1400c
+ (c) Copyright 2004 Alexander and Sander
+ (c) Copyright 2004 - 2005 Steven Seeger
+ (c) Copyright 2005 Ryan Vogt
+ (c) Copyright 2019 Michael Donald Buckley
+ ***********************************************************************************/
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface S9xPrefsViewController : NSViewController
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/macosx/Snes9x/S9xPrefsViewController.m b/macosx/Snes9x/S9xPrefsViewController.m
new file mode 100644
index 00000000..45478bfd
--- /dev/null
+++ b/macosx/Snes9x/S9xPrefsViewController.m
@@ -0,0 +1,297 @@
+/*****************************************************************************\
+ Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
+
+/***********************************************************************************
+ SNES9X for Mac OS (c) Copyright John Stiles
+
+ Snes9x for Mac OS X
+
+ (c) Copyright 2001 - 2011 zones
+ (c) Copyright 2002 - 2005 107
+ (c) Copyright 2002 PB1400c
+ (c) Copyright 2004 Alexander and Sander
+ (c) Copyright 2004 - 2005 Steven Seeger
+ (c) Copyright 2005 Ryan Vogt
+ (c) Copyright 2019 Michael Donald Buckley
+ ***********************************************************************************/
+
+#import
+
+#import "AppDelegate.h"
+#import "S9xPrefsConstants.h"
+#import "S9xPrefsViewController.h"
+#import "S9xButtonConfigTextField.h"
+
+@interface S9xPrefsViewController ()
+@property (nonatomic, weak) IBOutlet NSPopUpButton *videoModePopup;
+@property (nonatomic, weak) IBOutlet NSButton *showFPSCheckbox;
+@property (nonatomic, weak) IBOutlet NSPopUpButton *devicePopUp;
+@property (nonatomic, weak) IBOutlet NSPopUpButton *playerPopUp;
+@end
+
+@implementation S9xPrefsViewController
+
+- (void)awakeFromNib
+{
+ AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
+ NSUInteger joypadIndex = 0;
+ for (S9xJoypad *joypad in [appDelegate listJoypads])
+ {
+ NSMenuItem *item = [NSMenuItem new];
+ item.title = joypad.name;
+ item.tag = joypadIndex++;
+ item.representedObject = joypad;
+ [self.devicePopUp.menu addItem:item];
+ }
+
+ [self selectDeviceForPlayer:0];
+
+ for (NSView *subview in self.view.subviews)
+ {
+ if ( [subview isKindOfClass:[S9xButtonConfigTextField class]] )
+ {
+ S9xButtonConfigTextField *field = (S9xButtonConfigTextField *)subview;
+ [field addObserver:self forKeyPath:@"keyCode" options:NSKeyValueObservingOptionNew context:NULL];
+ [field addObserver:self forKeyPath:@"joypadInput" options:NSKeyValueObservingOptionNew context:NULL];
+ }
+ }
+}
+
+- (void)selectDeviceForPlayer:(int8_t)player
+{
+ AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
+ NSString* joypadKey = [[NSUserDefaults.standardUserDefaults objectForKey:kJoypadPlayerPrefs] objectForKey:@(player).stringValue];
+
+ [self.devicePopUp selectItemAtIndex:0];
+
+ if (joypadKey != nil)
+ {
+ uint32 vendorID = 0;
+ uint32 productID = 0;
+ uint32 index = 0;
+
+ if ( [appDelegate getValuesFromString:joypadKey vendorID:&vendorID productID:&productID index:&index])
+ {
+ S9xJoypad *joypad = [S9xJoypad new];
+ joypad.vendorID = vendorID;
+ joypad.productID = productID;
+ joypad.index = index;
+
+ for (NSMenuItem *item in self.devicePopUp.menu.itemArray)
+ {
+ if ([joypad isEqual:item.representedObject])
+ {
+ [self.devicePopUp selectItem:item];
+ break;
+ }
+ }
+ }
+ }
+}
+
+- (void)viewDidAppear
+{
+ [super viewDidAppear];
+ [self.view.window makeFirstResponder:self.view];
+ [self refresh];
+}
+
+- (void)refresh
+{
+ NSUInteger index = MIN([NSUserDefaults.standardUserDefaults integerForKey:kVideoModePref], 1);
+ [self.videoModePopup selectItemAtIndex:index];
+ self.showFPSCheckbox.state = [NSUserDefaults.standardUserDefaults boolForKey:kShowFPSPref];
+
+ if (self.devicePopUp.selectedItem.tag < 0)
+ {
+ NSMutableDictionary *controlsDict = [NSMutableDictionary new];
+
+ NSDictionary *keyboardDict = [NSUserDefaults.standardUserDefaults objectForKey:kKeyboardPrefs];
+ NSInteger playerNum = self.playerPopUp.selectedItem.tag;
+
+ for (NSUInteger i = 0; i < kNumButtons; ++i)
+ {
+ controlsDict[@(i)] = keyboardDict[@(i + playerNum).stringValue];
+ }
+
+ for (NSView *subview in self.view.subviews)
+ {
+ if ([subview isKindOfClass:[S9xButtonConfigTextField class]])
+ {
+ S9xButtonConfigTextField *field = (S9xButtonConfigTextField *)subview;
+
+ [field removeObserver:self forKeyPath:@"keyCode"];
+ [field removeObserver:self forKeyPath:@"joypadInput"];
+
+ NSNumber *keyCode = controlsDict[@(field.tag)];
+
+ field.joypadInput = nil;
+
+ if ( keyCode != nil )
+ {
+ field.keyCode = keyCode.intValue;
+ }
+ else
+ {
+ field.keyCode = -1;
+ }
+
+ [field addObserver:self forKeyPath:@"keyCode" options:NSKeyValueObservingOptionNew context:NULL];
+ [field addObserver:self forKeyPath:@"joypadInput" options:NSKeyValueObservingOptionNew context:NULL];
+
+ field.disableKeyboardInput = NO;
+ }
+ }
+ }
+ else
+ {
+ AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
+ S9xJoypad *joypad = self.devicePopUp.selectedItem.representedObject;
+ NSString *joypadKey = [appDelegate prefsKeyForVendorID:joypad.vendorID productID:joypad.productID index:joypad.index];
+ NSDictionary *joypadDIct = [[NSUserDefaults.standardUserDefaults objectForKey:kJoypadInputPrefs] objectForKey:joypadKey];
+
+ for (NSView *subview in self.view.subviews)
+ {
+ if ([subview isKindOfClass:[S9xButtonConfigTextField class]])
+ {
+ S9xButtonConfigTextField *textField = (S9xButtonConfigTextField *)subview;
+
+ [textField removeObserver:self forKeyPath:@"keyCode"];
+ [textField removeObserver:self forKeyPath:@"joypadInput"];
+
+ uint32 cookie = 0;
+ int32 value = 0;
+ S9xButtonCode buttonCode = (S9xButtonCode)textField.tag;
+ NSString *inputString = joypadDIct[@(buttonCode).stringValue];
+
+ textField.keyCode = -1;
+
+ if ([appDelegate getValuesFromString:inputString cookie:&cookie value:&value])
+ {
+ S9xJoypadInput *input = [S9xJoypadInput new];
+ input.cookie = cookie;
+ input.value = value;
+ input.buttonCode = buttonCode;
+ textField.joypadInput = input;
+ textField.stringValue = [appDelegate labelForVendorID:joypad.vendorID productID:joypad.productID cookie:cookie value:value];
+ }
+ else
+ {
+ textField.joypadInput = nil;
+ textField.stringValue = @"";
+ }
+
+ [textField addObserver:self forKeyPath:@"keyCode" options:NSKeyValueObservingOptionNew context:NULL];
+ [textField addObserver:self forKeyPath:@"joypadInput" options:NSKeyValueObservingOptionNew context:NULL];
+
+ textField.disableKeyboardInput = YES;
+ }
+ }
+ }
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
+{
+ if ([keyPath isEqualToString:@"keyCode"])
+ {
+ S9xButtonConfigTextField *field = (S9xButtonConfigTextField *)object;
+ S9xButtonCode buttonCode = (S9xButtonCode)field.tag;
+ uint16_t keyCode = field.keyCode;
+ int8_t player = self.playerPopUp.selectedItem.tag;
+
+ if (keyCode != (CGKeyCode)-1)
+ {
+ [((AppDelegate *) NSApp.delegate) setButtonCode:buttonCode forKeyCode:keyCode player:player];
+ }
+ else
+ {
+ [((AppDelegate *) NSApp.delegate) clearButton:buttonCode forPlayer:player];
+ }
+
+ [NSUserDefaults.standardUserDefaults synchronize];
+
+ [self refresh];
+ }
+ else if ( [keyPath isEqualToString:@"joypadInput"])
+ {
+ S9xButtonConfigTextField *field = (S9xButtonConfigTextField *)object;
+ S9xButtonCode buttonCode = (S9xButtonCode)field.tag;
+ S9xJoypad *joypad = self.devicePopUp.selectedItem.representedObject;
+
+ if ([joypad isKindOfClass:[S9xJoypad class]])
+ {
+ S9xJoypadInput *input = field.joypadInput;
+
+ if (input != nil)
+ {
+ [((AppDelegate *)NSApp.delegate) setButton:buttonCode forVendorID:joypad.vendorID productID:joypad.productID index:joypad.index cookie:input.cookie value:input.value];
+ }
+ else
+ {
+ [((AppDelegate *)NSApp.delegate) clearJoypadForVendorID:joypad.vendorID productID:joypad.productID index:joypad.index buttonCode:buttonCode];
+ }
+ }
+
+ [NSUserDefaults.standardUserDefaults synchronize];
+ [self refresh];
+ }
+}
+
+- (IBAction)playerDropdownChanged:(NSPopUpButton *)sender
+{
+ [self selectDeviceForPlayer:sender.selectedTag];
+ [self refresh];
+}
+
+- (IBAction)deviceDropdownChanged:(NSPopUpButton *)sender
+{
+ if (sender.selectedTag >= 0)
+ {
+ AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
+ S9xJoypad *joypad = sender.selectedItem.representedObject;
+ [appDelegate setPlayer:self.playerPopUp.selectedTag forVendorID:joypad.vendorID productID:joypad.productID index:joypad.index];
+ [NSUserDefaults.standardUserDefaults synchronize];
+ }
+
+ [self refresh];
+}
+
+- (IBAction)showFPS:(NSButton *)sender
+{
+ AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
+ [appDelegate setShowFPS:sender.state == NSOnState];
+}
+
+- (IBAction)setVideoMode:(NSPopUpButton *)sender
+{
+ AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
+ [appDelegate setVideoMode:(int)sender.selectedTag];
+}
+
+- (BOOL)handleInput:(S9xJoypadInput *)input fromJoypad:(S9xJoypad *)joypad
+{
+ id firstResponder = self.view.window.firstResponder;
+
+ if ([firstResponder respondsToSelector:@selector(isFieldEditor)] && [firstResponder isFieldEditor])
+ {
+ firstResponder = [firstResponder delegate];
+ }
+
+ if ([firstResponder respondsToSelector:@selector(setJoypadInput:)])
+ {
+ S9xJoypad *currentJoypad = self.devicePopUp.selectedItem.representedObject;
+
+ if ([joypad isEqual:currentJoypad])
+ {
+ [firstResponder setJoypadInput:input];
+ return YES;
+ }
+ }
+
+ return NO;
+}
+
+@end
diff --git a/macosx/Snes9x/S9xPrefsViewController.xib b/macosx/Snes9x/S9xPrefsViewController.xib
new file mode 100644
index 00000000..60d60bed
--- /dev/null
+++ b/macosx/Snes9x/S9xPrefsViewController.xib
@@ -0,0 +1,817 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/macosx/Snes9x/Snes9x.entitlements b/macosx/Snes9x/Snes9x.entitlements
new file mode 100644
index 00000000..0c67376e
--- /dev/null
+++ b/macosx/Snes9x/Snes9x.entitlements
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/macosx/Snes9x/main.m b/macosx/Snes9x/main.m
new file mode 100644
index 00000000..cc7f4966
--- /dev/null
+++ b/macosx/Snes9x/main.m
@@ -0,0 +1,25 @@
+/*****************************************************************************\
+ Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
+
+/***********************************************************************************
+ SNES9X for Mac OS (c) Copyright John Stiles
+
+ Snes9x for Mac OS X
+
+ (c) Copyright 2001 - 2011 zones
+ (c) Copyright 2002 - 2005 107
+ (c) Copyright 2002 PB1400c
+ (c) Copyright 2004 Alexander and Sander
+ (c) Copyright 2004 - 2005 Steven Seeger
+ (c) Copyright 2005 Ryan Vogt
+ (c) Copyright 2019 Michael Donald Buckley
+ ***********************************************************************************/
+
+#import
+
+int main(int argc, const char * argv[]) {
+ return NSApplicationMain(argc, argv);
+}
diff --git a/macosx/docs/FAQ.rtf b/macosx/docs/FAQ.rtf
index b8154b44..8b468822 100644
--- a/macosx/docs/FAQ.rtf
+++ b/macosx/docs/FAQ.rtf
@@ -1,68 +1,61 @@
-{\rtf1\ansi\ansicpg932\cocoartf1038\cocoasubrtf350
-{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
+{\rtf1\ansi\ansicpg1252\cocoartf1671\cocoasubrtf600
+\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 LucidaGrande;\f1\fnil\fcharset0 LucidaGrande-Bold;}
{\colortbl;\red255\green255\blue255;\red153\green102\blue51;\red0\green0\blue255;}
-\paperw11900\paperh16840\margl1440\margr1440\vieww11500\viewh12340\viewkind0
-\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\ql\qnatural
+{\*\expandedcolortbl;;\csgenericrgb\c60000\c40000\c20000;\csgenericrgb\c0\c0\c100000;}
+\paperw11905\paperh16837\margl1440\margr1440\vieww11500\viewh12340\viewkind0
+\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\partightenfactor0
\f0\fs24 \cf0 \
-\b\fs28 FAQ for Mac port
-\b0\fs24 \
+\f1\b\fs28 FAQ for Mac port
+\f0\b0\fs24 \
\
\
-\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\ql\qnatural
+\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\partightenfactor0
-\b\fs26 \cf2 Differences and similarities among the Mac port and other ports
-\b0\fs24 \cf0 \
-\
-\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\ql\qnatural
-\cf3 Key mapping\cf0 \
- The default settings of key mapping are different. For example, the A-button is the command key on Mac, while it's the D key in Windows.\
+\f1\b\fs26 \cf2 Differences and similarities among the Mac port and other ports
+\f0\b0\fs24 \cf0 \
\
+\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\partightenfactor0
\cf3 User interface\cf0 \
All of the menus and dialogs are different.\
\
-\cf3 AVI or QuickTime export\cf0 \
- Mac port supports QuickTime export instead of AVI export in Windows port.\
-\
-\cf3 Sound effect and Core Image filter\cf0 \
- These features are for Mac only because they use Mac OS X's own technologies.\
-\
-\cf3 Netplay\cf0 \
- Snes9x's netplay is incompatible between ports.\
-\
-\cf3 Command-line options\cf0 \
- Mac port doesn't support command-line options.\
-\
\cf3 Preferences file\cf0 \
Mac port doesn't support 'snes9x.conf' file.\
\
\
-\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\ql\qnatural
+\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\partightenfactor0
-\b\fs26 \cf2 Emulator Specific Questions
-\b0\fs24 \cf0 \
+\f1\b\fs26 \cf2 Emulator Specific Questions
+\f0\b0\fs24 \cf0 \
\
-\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\ql\qnatural
+\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\partightenfactor0
\cf3 Everything is fine when I play the game, but the next time I play, my save data is not there. Why?\cf0 \
Saving files into a locked volume and folders where you don't have permission to write will fail. Make sure where you are saving files in 'Preferences' dialog. The most common case for Mac beginners is launching Snes9x directly from the disk image with choosing 'Snes9x folder' for saving destination.\
\
+\cf3 Where did Cheats/Movie Recording/Netplay/most of the preferences go?\
+\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\partightenfactor0
+\cf0 Snes9x is currently being ported from Carbon to Cocoa in order to work with macOS Catalina. Because this process is time-consuming, features are being added back over time. If there\'92s a specific feature you\'92d like to see return before others, please upvote an issue, or create one if none exists, at {\field{\*\fldinst{HYPERLINK "https://github.com/snes9xgit/snes9x/issues"}}{\fldrslt https://github.com/snes9xgit/snes9x/issues}}.\
+\
+\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\partightenfactor0
+\cf3 Why did my keyboard controls change when I upgraded?\
+\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\partightenfactor0
+\cf0 The Cocoa port of Snes9x \
+\
+\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\partightenfactor0
\cf3 Why can't I press many buttons at once? Especially in Chrono Trigger.\cf0 \
Some keyboards can only output two pressed keys at a time, except for modifier keys (shift, command, option and control). Set modifier keys to some of the necessary buttons.\
\
-\cf3 How can I enter the Game Genie / PAR code in 'Cheat Entry' dialog?\cf0 \
- Simply enter the code directly into the address column. Snes9x automatically translates it to the general format.\
-\
\cf3 I recently purchased a gamepad controller. Will it work on Snes9x?\
-\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\ql\qnatural
+\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\partightenfactor0
\cf0 If your gamepad is conformable to USB Device Class Definition for Human Interface Devices, it may work. Note that most gamepads don't officially support Mac OS X even if they work without problems.\cf3 \
\
I connected my gamepad but it doesn't work.\cf0 \
Gamepads cannot be used until you configure its settings in 'Configure Controllers' dialog.\
\
-\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\ql\qnatural
+\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\partightenfactor0
\cf3 I think my options in Snes9x got screwed up, how do I reset them?\cf0 \
- Quit Snes9x and trash the preferences file 'com.snes9x.macos.snes9x.plist' in ~/Library/Preferences.\
+ Quit Snes9x and trash the preferences files 'com.snes9x.macos.snes9x.plist' in ~/Library/Preferences and in /Library/Preferences. You may need to reboot afterwords. Alternately, you can use the command \'91defaults delete com.snes9x.macos.snes9x\'92 in Terminal.app to avoid restarting.\
\
\cf3 I had a bad checksummed game that didn't work so I adjusted the header, but it still doesn't work :( Why?\cf0 \
It should be noted that while it is possible to plop a ROM into Snestool, or several other programs, and adjust the header size to be the same as a proper 'good checksum' ROM, this merely mimics the appearance of a good ROM. Any problems still found within its evil will remain. One could compare it to covering up a circumorbital haematoma with a paper bag.\
@@ -74,12 +67,12 @@ I connected my gamepad but it doesn't work.\cf0 \
Chances are it will be coming out when enough changes have been made to suitably make a release. You can generally guesstimate the release date by paying attention to the Developers forum at snes9x.com. But don't ask them when the next release will be.\
\
\
-\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\ql\qnatural
+\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\partightenfactor0
-\b\fs26 \cf2 Miscellaneous Questions
-\b0\fs24 \cf0 \
+\f1\b\fs26 \cf2 Miscellaneous Questions
+\f0\b0\fs24 \cf0 \
\
-\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\ql\qnatural
+\pard\tx285\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\partightenfactor0
\cf3 Is it legal?\cf0 \
This has been asked time and again, and the answer is yes. Developing, downloading, or using the emulator, Snes9x, is completely legal. Downloading games, called ROMS, however is not. If you own the original cartridge of a game, you are still not entitled to download the ROM image of that game. You may create a single backup image of your own cartridge via proper hardware, but it must be YOUR cartridge and is only usable in place of the original... so only one may be active at any time. Many sites claim that you may legally download ROMs for up to 24 hours before they must be deleted. This is also wrong; you can't legally download these for "trial" purposes. You can't download ROMs for educational purposes either. If you wish to use Super Nintendo Entertainment System games for educational purposes, contact your closest Nintendo Outlet and discuss educational programming with them. Finally, a small number of ROMs are labeled "(PD)". This means public domain, and these games are not under copyright. As such they are legal to download at your hearts content. These include programs created by internet users such as yourself for use in Super Nintendo emulators. As of this time there are no commercial videogames in the public domain.\
\
diff --git a/macosx/English.lproj/InfoPlist.strings b/macosx/en.lproj/InfoPlist.strings
similarity index 100%
rename from macosx/English.lproj/InfoPlist.strings
rename to macosx/en.lproj/InfoPlist.strings
diff --git a/macosx/English.lproj/Localizable.strings b/macosx/en.lproj/Localizable.strings
similarity index 100%
rename from macosx/English.lproj/Localizable.strings
rename to macosx/en.lproj/Localizable.strings
diff --git a/macosx/English.lproj/Snes9x Help/Snes9x Help.helpindex b/macosx/en.lproj/Snes9x Help/Snes9x Help.helpindex
similarity index 100%
rename from macosx/English.lproj/Snes9x Help/Snes9x Help.helpindex
rename to macosx/en.lproj/Snes9x Help/Snes9x Help.helpindex
diff --git a/macosx/English.lproj/Snes9x Help/gfx/s9xic128.png b/macosx/en.lproj/Snes9x Help/gfx/s9xic128.png
similarity index 100%
rename from macosx/English.lproj/Snes9x Help/gfx/s9xic128.png
rename to macosx/en.lproj/Snes9x Help/gfx/s9xic128.png
diff --git a/macosx/English.lproj/Snes9x Help/gfx/s9xic16.png b/macosx/en.lproj/Snes9x Help/gfx/s9xic16.png
similarity index 100%
rename from macosx/English.lproj/Snes9x Help/gfx/s9xic16.png
rename to macosx/en.lproj/Snes9x Help/gfx/s9xic16.png
diff --git a/macosx/English.lproj/Snes9x Help/index.html b/macosx/en.lproj/Snes9x Help/index.html
similarity index 100%
rename from macosx/English.lproj/Snes9x Help/index.html
rename to macosx/en.lproj/Snes9x Help/index.html
diff --git a/macosx/English.lproj/Snes9x Help/pgs/01.html b/macosx/en.lproj/Snes9x Help/pgs/01.html
similarity index 94%
rename from macosx/English.lproj/Snes9x Help/pgs/01.html
rename to macosx/en.lproj/Snes9x Help/pgs/01.html
index c0eb0bed..98e5bb98 100644
--- a/macosx/English.lproj/Snes9x Help/pgs/01.html
+++ b/macosx/en.lproj/Snes9x Help/pgs/01.html
@@ -30,11 +30,10 @@
As with all things there are disadvantages though :
- if you have an ancient computer, you aren't likely to get a playable experience.
some games are still unemulated (though this a very tiny minority.)
the emulator can be difficult for new users to configure.
-
Getting Started
- Copy the Snes9x application from the disk image (.dmg) to your hard disk and double-click it.
+ Copy the Snes9x application to your hard Applications Folder and double-click it.
Loading Games
@@ -64,7 +64,7 @@
SNES Joypad Emulation
- The default key mapping for joypad 1 is as follows:
+ The Mac port now uses the same default key mapping as the Windows port. The default key mapping for joypad 1 is as follows:
@@ -86,35 +86,35 @@
Right direction
- command
+ V
A button
- option
+ C
B button
- control
+ D
X button
- shift
+ X
Y button
- Z
+ A
L button
- X
+ S
R button
- tab
+ return
Select button
- return
+ space
Start button
@@ -122,9 +122,9 @@
Pausing and Resuming the Game
- To pause the game, press pause key (esc key by default), choose 'Pause' in 'Emulation' menu, or click the game screen in case you aren't playing the game that uses a mouse. Double-click the game window or choose 'Resume' in 'Emulation' menu to resume the game.
+ To pause the game, press pause key (esc key by default) or choose 'Pause' in 'Emulation' menu. Choose 'Resume' in 'Emulation' menu to resume the game.
-