This commit is contained in:
yoshisuga 2021-09-24 19:39:36 +02:00 committed by GitHub
commit d3d52ad8f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 5805 additions and 807 deletions

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.user-fonts</key>
<array>
<string>app-usage</string>
<string>system-installation</string>
</array>
</dict>
</plist>

View File

@ -131,6 +131,11 @@
"idiom" : "ipad",
"filename" : "icon@167.png",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {

View File

@ -1,77 +1,58 @@
{
"images" : [
{
"orientation" : "portrait",
"extent" : "full-screen",
"idiom" : "iphone",
"extent" : "full-screen",
"scale" : "1x"
"subtype" : "2688h",
"filename" : "activegs-launch-iphonexsmax.png",
"minimum-system-version" : "12.0",
"orientation" : "portrait",
"scale" : "3x"
},
{
"orientation" : "portrait",
"extent" : "full-screen",
"idiom" : "iphone",
"extent" : "full-screen",
"scale" : "2x"
"subtype" : "2688h",
"filename" : "activegs-launch-iphonexsmaxland.png",
"minimum-system-version" : "12.0",
"orientation" : "landscape",
"scale" : "3x"
},
{
"orientation" : "portrait",
"extent" : "full-screen",
"idiom" : "iphone",
"extent" : "full-screen",
"subtype" : "retina4",
"scale" : "2x"
},
{
"subtype" : "1792h",
"filename" : "activegs-launch-iphonexr.png",
"minimum-system-version" : "12.0",
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "activegs-launch-iPadios5.png",
"extent" : "to-status-bar",
"scale" : "1x"
"scale" : "2x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "1792h",
"filename" : "activegs-launch-iphonexrland.png",
"minimum-system-version" : "12.0",
"orientation" : "landscape",
"scale" : "2x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "2436h",
"filename" : "activegs-launch-iphonex.png",
"minimum-system-version" : "11.0",
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "activegs-launch-iPad-ios5.png",
"scale" : "3x"
},
{
"extent" : "full-screen",
"scale" : "1x"
},
{
"idiom" : "iphone",
"subtype" : "2436h",
"filename" : "activegs-launch-iphonexland.png",
"minimum-system-version" : "11.0",
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "activegs-launch-iPadland-ios5.png",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "activegs-launch-iPadretina-ios5.png",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "activegs-launch-iPadretina-ios5-1.png",
"extent" : "full-screen",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "activegs-launch-iPadretinaland-iOS5.png",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "full-screen",
"scale" : "2x"
"scale" : "3x"
},
{
"extent" : "full-screen",
@ -148,6 +129,79 @@
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"extent" : "full-screen",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"extent" : "full-screen",
"subtype" : "retina4",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "activegs-launch-iPadios5.png",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "activegs-launch-iPad-ios5.png",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "activegs-launch-iPadland-ios5.png",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "activegs-launch-iPadretina-ios5.png",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "activegs-launch-iPadretina-ios5-1.png",
"extent" : "full-screen",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "activegs-launch-iPadretinaland-iOS5.png",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "full-screen",
"scale" : "2x"
}
],
"info" : {

Binary file not shown.

After

Width:  |  Height:  |  Size: 732 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 643 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10116" systemVersion="15A284" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="KeyCapView">
<rect key="frame" x="0.0" y="0.0" width="183" height="156"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Key" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WuS-sc-nnF" userLabel="Key">
<rect key="frame" x="4" y="4" width="18" height="12"/>
<fontDescription key="fontDescription" type="system" pointSize="10"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Mapped Button" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CsD-e8-zpW">
<rect key="frame" x="100" y="140" width="79" height="12"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="10"/>
<color key="textColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="S-Key" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DoM-mH-zdu" userLabel="Key Alt Label">
<rect key="frame" x="4" y="140" width="29" height="12"/>
<fontDescription key="fontDescription" type="system" pointSize="10"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="CsD-e8-zpW" secondAttribute="trailing" constant="4" id="0QF-nq-bp4"/>
<constraint firstItem="WuS-sc-nnF" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="4" id="EG2-YO-isI"/>
<constraint firstAttribute="bottom" secondItem="DoM-mH-zdu" secondAttribute="bottom" constant="4" id="XtK-Xm-l8n"/>
<constraint firstAttribute="bottom" secondItem="CsD-e8-zpW" secondAttribute="bottom" constant="4" id="bLA-GT-HXu"/>
<constraint firstItem="DoM-mH-zdu" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="4" id="iGg-gd-FfI"/>
<constraint firstItem="WuS-sc-nnF" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="4" id="oKU-fu-MTZ"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="keyLabel" destination="WuS-sc-nnF" id="Fge-Us-qip"/>
<outlet property="keyLabelAlt" destination="DoM-mH-zdu" id="AOv-CK-LvA"/>
<outlet property="mappedButtonLabel" destination="CsD-e8-zpW" id="p4m-si-1HQ"/>
</connections>
<point key="canvasLocation" x="190.5" y="137"/>
</view>
</objects>
</document>

View File

@ -6,6 +6,63 @@
<string>English</string>
<key>CFBundleDisplayName</key>
<string>ActiveGS</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeIconFiles</key>
<array/>
<key>CFBundleTypeName</key>
<string>Apple // 2MG Image</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>com.apple.disk-image-2mg</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFiles</key>
<array/>
<key>CFBundleTypeName</key>
<string>Apple // DSK Image</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>com.apple.disk-image-dsk</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFiles</key>
<array/>
<key>CFBundleTypeName</key>
<string>Apple // ZIP Disk Image</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>com.apple.disk-image-zip</string>
</array>
</dict>
<dict>
<key>CFBundleTypeIconFiles</key>
<array/>
<key>CFBundleTypeName</key>
<string>Unknown File</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>public.item</string>
</array>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
@ -17,13 +74,15 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.42</string>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
@ -32,6 +91,7 @@
<key>UIAppFonts</key>
<array>
<string>ShastonHi640.ttf</string>
<string>PrintChar21.ttf</string>
</array>
<key>UIFileSharingEnabled</key>
<true/>
@ -50,5 +110,71 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.archive</string>
<string>public-data</string>
<string>public.disk-image</string>
</array>
<key>UTTypeDescription</key>
<string>Apple // Disk Image - 2MG</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>com.apple.disk-image-2mg</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>Item 0</key>
<string>2MG</string>
<key>public.filename-extension</key>
<array/>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.archive</string>
<string>public-data</string>
<string>public.disk-image</string>
</array>
<key>UTTypeDescription</key>
<string>Apple // Disk Image - DSK</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>com.apple.disk-image-dsk</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>DSK</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.archive</string>
<string>public-data</string>
<string>public.disk-image</string>
</array>
<key>UTTypeDescription</key>
<string>Apple // Disk Image -ZIP</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>com.apple.disk-image-zip</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>ZIP</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>

View File

@ -214,7 +214,6 @@
09FD36F31278CCEB009C31AB /* BLUE_HELMET.FTA in Resources */ = {isa = PBXBuildFile; fileRef = 09FD36F01278CCEB009C31AB /* BLUE_HELMET.FTA */; };
09FD36F41278CCEB009C31AB /* bluehelmet_1.png in Resources */ = {isa = PBXBuildFile; fileRef = 09FD36F11278CCEB009C31AB /* bluehelmet_1.png */; };
09FD36F51278CCEB009C31AB /* bluehelmet_2.png in Resources */ = {isa = PBXBuildFile; fileRef = 09FD36F21278CCEB009C31AB /* bluehelmet_2.png */; };
1D60589B0D05DD56006BFB54 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.mm */; };
1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; };
288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765A40DF7441C002DB57D /* CoreGraphics.framework */; };
@ -237,9 +236,36 @@
7E51482F1CA6B5CE005DA0A6 /* ShastonHi640.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7E51481C1CA6B5CE005DA0A6 /* ShastonHi640.ttf */; };
7E5148301CA6B5CE005DA0A6 /* Spin Up Search 1.wav in Resources */ = {isa = PBXBuildFile; fileRef = 7E51481D1CA6B5CE005DA0A6 /* Spin Up Search 1.wav */; };
7E5148311CA6B5CE005DA0A6 /* Spin Up Search 2.wav in Resources */ = {isa = PBXBuildFile; fileRef = 7E51481E1CA6B5CE005DA0A6 /* Spin Up Search 2.wav */; };
9222DD461CBECF2300B321B9 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.mm */; };
924A1BAC1CB81B5800D69162 /* GameControllerKeyRemapController.m in Sources */ = {isa = PBXBuildFile; fileRef = 924A1BAA1CB81B5800D69162 /* GameControllerKeyRemapController.m */; };
924A1BAD1CB81B5800D69162 /* GameControllerKeyRemapController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 924A1BAB1CB81B5800D69162 /* GameControllerKeyRemapController.xib */; };
924A1BAF1CB9671400D69162 /* KeyCapView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 924A1BAE1CB9671400D69162 /* KeyCapView.xib */; };
924A1BB21CB9685700D69162 /* KeyCapView.m in Sources */ = {isa = PBXBuildFile; fileRef = 924A1BB11CB9685700D69162 /* KeyCapView.m */; };
924A1BB51CBA049D00D69162 /* KeyMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 924A1BB41CBA049D00D69162 /* KeyMapper.m */; };
9250DCB31CAEEF990093CE9A /* MfiGameControllerHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9250DCB21CAEEF990093CE9A /* MfiGameControllerHandler.m */; };
9250DCB51CAEFD3B0093CE9A /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9250DCB41CAEFD3B0093CE9A /* GameController.framework */; };
927E431A25C48592008E5517 /* CheatFinderManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927E431925C48592008E5517 /* CheatFinderManager.swift */; };
927E436425C94C12008E5517 /* Stream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927E435925C94C12008E5517 /* Stream.swift */; };
927E436525C94C12008E5517 /* Bus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927E435A25C94C12008E5517 /* Bus.swift */; };
927E436625C94C12008E5517 /* CPU+Instructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927E435C25C94C12008E5517 /* CPU+Instructions.swift */; };
927E436725C94C12008E5517 /* CPU+Flags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927E435D25C94C12008E5517 /* CPU+Flags.swift */; };
927E436825C94C12008E5517 /* CPU+Stack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927E435E25C94C12008E5517 /* CPU+Stack.swift */; };
927E436925C94C12008E5517 /* CPU.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927E435F25C94C12008E5517 /* CPU.swift */; };
927E436A25C94C12008E5517 /* Instruction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927E436125C94C12008E5517 /* Instruction.swift */; };
927E436B25C94C12008E5517 /* Mnemonic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927E436225C94C12008E5517 /* Mnemonic.swift */; };
927E436C25C94C12008E5517 /* AddressingMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927E436325C94C12008E5517 /* AddressingMode.swift */; };
927E437025C99A11008E5517 /* Debug6502Interpreter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927E436F25C99A11008E5517 /* Debug6502Interpreter.swift */; };
928410581CA8443A00DC5D93 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 928410571CA8443A00DC5D93 /* Images.xcassets */; };
92A9D66E25CC5A96008F5031 /* DebuggerUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92A9D66D25CC5A96008F5031 /* DebuggerUtils.swift */; };
92A9D67125CC5AF4008F5031 /* EmuMemoryModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92A9D67025CC5AF4008F5031 /* EmuMemoryModel.swift */; };
92A9D67525CC5B7D008F5031 /* DebugMemoryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92A9D67425CC5B7D008F5031 /* DebugMemoryButton.swift */; };
92A9D67925CC5BB6008F5031 /* DebugMemoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92A9D67825CC5BB6008F5031 /* DebugMemoryCell.swift */; };
92A9D67F25CC5C66008F5031 /* DebugMemoryActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92A9D67E25CC5C66008F5031 /* DebugMemoryActionViewController.swift */; };
92B9EADF24D3369700E6CFB2 /* EmulatorKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92B9EADE24D3369700E6CFB2 /* EmulatorKeyboard.swift */; };
92E2063225AADFB000AE3F28 /* PreviewUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92E2063125AADF6E00AE3F28 /* PreviewUI.swift */; };
92FA0F2425B52EA200663577 /* EmuWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92FA0F2325B52EA200663577 /* EmuWrapper.mm */; };
92FA0F2A25B5353D00663577 /* DebugMemoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92FA0F2925B5353D00663577 /* DebugMemoryViewController.swift */; };
92FA0F2D25B59EF100663577 /* PrintChar21.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 92FA0F2C25B59EF100663577 /* PrintChar21.ttf */; };
/* End PBXBuildFile section */
/* Begin PBXBuildRule section */
@ -247,6 +273,8 @@
isa = PBXBuildRule;
compilerSpec = com.apple.compilers.proxy.script;
fileType = pattern.proxy;
inputFiles = (
);
isEditable = 1;
outputFiles = (
);
@ -576,10 +604,42 @@
7E51481C1CA6B5CE005DA0A6 /* ShastonHi640.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = ShastonHi640.ttf; sourceTree = "<group>"; };
7E51481D1CA6B5CE005DA0A6 /* Spin Up Search 1.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = "Spin Up Search 1.wav"; sourceTree = "<group>"; };
7E51481E1CA6B5CE005DA0A6 /* Spin Up Search 2.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = "Spin Up Search 2.wav"; sourceTree = "<group>"; };
924A1BA91CB81B5800D69162 /* GameControllerKeyRemapController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GameControllerKeyRemapController.h; sourceTree = "<group>"; };
924A1BAA1CB81B5800D69162 /* GameControllerKeyRemapController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GameControllerKeyRemapController.m; sourceTree = "<group>"; };
924A1BAB1CB81B5800D69162 /* GameControllerKeyRemapController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = GameControllerKeyRemapController.xib; path = ../Common.iphone/GameControllerKeyRemapController.xib; sourceTree = "<group>"; };
924A1BAE1CB9671400D69162 /* KeyCapView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = KeyCapView.xib; sourceTree = "<group>"; };
924A1BB01CB9685700D69162 /* KeyCapView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyCapView.h; sourceTree = "<group>"; };
924A1BB11CB9685700D69162 /* KeyCapView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeyCapView.m; sourceTree = "<group>"; };
924A1BB31CBA049D00D69162 /* KeyMapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyMapper.h; sourceTree = "<group>"; };
924A1BB41CBA049D00D69162 /* KeyMapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeyMapper.m; sourceTree = "<group>"; };
9250DCB11CAEEF990093CE9A /* MfiGameControllerHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MfiGameControllerHandler.h; sourceTree = "<group>"; };
9250DCB21CAEEF990093CE9A /* MfiGameControllerHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MfiGameControllerHandler.m; sourceTree = "<group>"; };
9250DCB41CAEFD3B0093CE9A /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; };
927E431925C48592008E5517 /* CheatFinderManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatFinderManager.swift; sourceTree = "<group>"; };
927E435925C94C12008E5517 /* Stream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Stream.swift; sourceTree = "<group>"; };
927E435A25C94C12008E5517 /* Bus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bus.swift; sourceTree = "<group>"; };
927E435C25C94C12008E5517 /* CPU+Instructions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CPU+Instructions.swift"; sourceTree = "<group>"; };
927E435D25C94C12008E5517 /* CPU+Flags.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CPU+Flags.swift"; sourceTree = "<group>"; };
927E435E25C94C12008E5517 /* CPU+Stack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CPU+Stack.swift"; sourceTree = "<group>"; };
927E435F25C94C12008E5517 /* CPU.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CPU.swift; sourceTree = "<group>"; };
927E436125C94C12008E5517 /* Instruction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Instruction.swift; sourceTree = "<group>"; };
927E436225C94C12008E5517 /* Mnemonic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mnemonic.swift; sourceTree = "<group>"; };
927E436325C94C12008E5517 /* AddressingMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddressingMode.swift; sourceTree = "<group>"; };
927E436F25C99A11008E5517 /* Debug6502Interpreter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Debug6502Interpreter.swift; sourceTree = "<group>"; };
928410571CA8443A00DC5D93 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = ActiveGS/Images.xcassets; sourceTree = "<group>"; };
92A9D66D25CC5A96008F5031 /* DebuggerUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebuggerUtils.swift; sourceTree = "<group>"; };
92A9D67025CC5AF4008F5031 /* EmuMemoryModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmuMemoryModel.swift; sourceTree = "<group>"; };
92A9D67425CC5B7D008F5031 /* DebugMemoryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugMemoryButton.swift; sourceTree = "<group>"; };
92A9D67825CC5BB6008F5031 /* DebugMemoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugMemoryCell.swift; sourceTree = "<group>"; };
92A9D67E25CC5C66008F5031 /* DebugMemoryActionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugMemoryActionViewController.swift; sourceTree = "<group>"; };
92AF5B1325D1B7A00025578D /* ActiveGS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = ActiveGS.entitlements; path = ActiveGS/ActiveGS.entitlements; sourceTree = "<group>"; };
92B9EADD24D3369600E6CFB2 /* ActiveGS-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ActiveGS-Bridging-Header.h"; sourceTree = "<group>"; };
92B9EADE24D3369700E6CFB2 /* EmulatorKeyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmulatorKeyboard.swift; sourceTree = "<group>"; };
92E2063125AADF6E00AE3F28 /* PreviewUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewUI.swift; sourceTree = "<group>"; };
92FA0F2325B52EA200663577 /* EmuWrapper.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = EmuWrapper.mm; sourceTree = "<group>"; };
92FA0F2625B52EC000663577 /* EmuWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EmuWrapper.h; sourceTree = "<group>"; };
92FA0F2925B5353D00663577 /* DebugMemoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugMemoryViewController.swift; sourceTree = "<group>"; };
92FA0F2C25B59EF100663577 /* PrintChar21.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = PrintChar21.ttf; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -712,6 +772,8 @@
0916BB03129473CE001727AF /* infoViewController-ipad.xib */,
09A5CE75125D422D0018DC22 /* infoViewController.xib */,
099CD904125E6F6E008EFD6C /* detailViewController.xib */,
924A1BAE1CB9671400D69162 /* KeyCapView.xib */,
924A1BAB1CB81B5800D69162 /* GameControllerKeyRemapController.xib */,
);
name = xib;
sourceTree = "<group>";
@ -985,6 +1047,16 @@
09FA608B125A7B3E00B07F77 /* KBDController.mm */,
9250DCB11CAEEF990093CE9A /* MfiGameControllerHandler.h */,
9250DCB21CAEEF990093CE9A /* MfiGameControllerHandler.m */,
924A1BA91CB81B5800D69162 /* GameControllerKeyRemapController.h */,
924A1BAA1CB81B5800D69162 /* GameControllerKeyRemapController.m */,
924A1BB01CB9685700D69162 /* KeyCapView.h */,
924A1BB11CB9685700D69162 /* KeyCapView.m */,
924A1BB31CBA049D00D69162 /* KeyMapper.h */,
924A1BB41CBA049D00D69162 /* KeyMapper.m */,
92B9EADE24D3369700E6CFB2 /* EmulatorKeyboard.swift */,
92E2063125AADF6E00AE3F28 /* PreviewUI.swift */,
92B9EADD24D3369600E6CFB2 /* ActiveGS-Bridging-Header.h */,
927E435725C94BE7008E5517 /* Debugger */,
);
name = Common.iphone;
path = ../Common.iphone;
@ -1001,6 +1073,7 @@
29B97314FDCFA39411CA2CEA /* CustomTemplate */ = {
isa = PBXGroup;
children = (
92AF5B1325D1B7A00025578D /* ActiveGS.entitlements */,
096604C819127DB700A22C51 /* activegs.plist */,
09052B4219053C9F00853FAE /* Libraries */,
09520D8516AEF8250065E84A /* Drivers */,
@ -1084,6 +1157,7 @@
7E5148141CA6B5CE005DA0A6 /* floppy_eject.wav */,
7E5148151CA6B5CE005DA0A6 /* logo_apple2.png */,
7E5148161CA6B5CE005DA0A6 /* logo_apple2gs.png */,
92FA0F2C25B59EF100663577 /* PrintChar21.ttf */,
7E5148171CA6B5CE005DA0A6 /* Search Skip Search 1.wav */,
7E5148181CA6B5CE005DA0A6 /* Search Skip Search 2.wav */,
7E5148191CA6B5CE005DA0A6 /* Search Skip Search 3.wav */,
@ -1097,6 +1171,72 @@
path = ../Common.res;
sourceTree = SOURCE_ROOT;
};
927E435725C94BE7008E5517 /* Debugger */ = {
isa = PBXGroup;
children = (
927E435825C94C12008E5517 /* 65C02Interpreter */,
92A9D67325CC5B63008F5031 /* Views */,
92A9D67B25CC5C24008F5031 /* ViewControllers */,
92FA0F2325B52EA200663577 /* EmuWrapper.mm */,
92FA0F2625B52EC000663577 /* EmuWrapper.h */,
92A9D67025CC5AF4008F5031 /* EmuMemoryModel.swift */,
927E431925C48592008E5517 /* CheatFinderManager.swift */,
92A9D66D25CC5A96008F5031 /* DebuggerUtils.swift */,
);
path = Debugger;
sourceTree = "<group>";
};
927E435825C94C12008E5517 /* 65C02Interpreter */ = {
isa = PBXGroup;
children = (
927E436F25C99A11008E5517 /* Debug6502Interpreter.swift */,
927E435925C94C12008E5517 /* Stream.swift */,
927E435A25C94C12008E5517 /* Bus.swift */,
927E435B25C94C12008E5517 /* CPU */,
927E436025C94C12008E5517 /* Instruction */,
);
path = 65C02Interpreter;
sourceTree = "<group>";
};
927E435B25C94C12008E5517 /* CPU */ = {
isa = PBXGroup;
children = (
927E435C25C94C12008E5517 /* CPU+Instructions.swift */,
927E435D25C94C12008E5517 /* CPU+Flags.swift */,
927E435E25C94C12008E5517 /* CPU+Stack.swift */,
927E435F25C94C12008E5517 /* CPU.swift */,
);
path = CPU;
sourceTree = "<group>";
};
927E436025C94C12008E5517 /* Instruction */ = {
isa = PBXGroup;
children = (
927E436125C94C12008E5517 /* Instruction.swift */,
927E436225C94C12008E5517 /* Mnemonic.swift */,
927E436325C94C12008E5517 /* AddressingMode.swift */,
);
path = Instruction;
sourceTree = "<group>";
};
92A9D67325CC5B63008F5031 /* Views */ = {
isa = PBXGroup;
children = (
92A9D67425CC5B7D008F5031 /* DebugMemoryButton.swift */,
92A9D67825CC5BB6008F5031 /* DebugMemoryCell.swift */,
);
path = Views;
sourceTree = "<group>";
};
92A9D67B25CC5C24008F5031 /* ViewControllers */ = {
isa = PBXGroup;
children = (
92FA0F2925B5353D00663577 /* DebugMemoryViewController.swift */,
92A9D67E25CC5C66008F5031 /* DebugMemoryActionViewController.swift */,
);
path = ViewControllers;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -1128,6 +1268,7 @@
LastUpgradeCheck = 0820;
TargetAttributes = {
1D6058900D05DD3D006BFB54 = {
LastSwiftMigration = 1160;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.DataProtection = {
@ -1212,6 +1353,7 @@
09087F3B12244C0500C52D88 /* delta_2.png in Resources */,
09087F3C12244C0500C52D88 /* delta_3.png in Resources */,
09087F3D12244C0500C52D88 /* delta_4.png in Resources */,
924A1BAD1CB81B5800D69162 /* GameControllerKeyRemapController.xib in Resources */,
09087F3E12244C0500C52D88 /* delta_5.png in Resources */,
09087F3F12244C0500C52D88 /* delta_6.png in Resources */,
7E5148311CA6B5CE005DA0A6 /* Spin Up Search 2.wav in Resources */,
@ -1267,11 +1409,13 @@
09AF98051283F0DF00083D60 /* Oil_Landers.fta in Resources */,
09AF980C1283F12200083D60 /* StarWizard (2002).fta in Resources */,
09AF980D1283F12200083D60 /* starwizard_2.png in Resources */,
924A1BAF1CB9671400D69162 /* KeyCapView.xib in Resources */,
09AF980E1283F12200083D60 /* starwizard_3.png in Resources */,
7E5148271CA6B5CE005DA0A6 /* floppy_eject.wav in Resources */,
09AF980F1283F12200083D60 /* starwizard_4.png in Resources */,
09AF98101283F12200083D60 /* starwizard_5.png in Resources */,
09AF98111283F12200083D60 /* starwizard.png in Resources */,
92FA0F2D25B59EF100663577 /* PrintChar21.ttf in Resources */,
7E51482C1CA6B5CE005DA0A6 /* Search Skip Search 3.wav in Resources */,
09D8BCF91285EFE900B6D785 /* miniprix_1.png in Resources */,
09D8BCFC1285EFFA00B6D785 /* miniprix_2.png in Resources */,
@ -1304,15 +1448,21 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
1D60589B0D05DD56006BFB54 /* main.mm in Sources */,
9222DD461CBECF2300B321B9 /* main.mm in Sources */,
09BB434511D92F65005ADA46 /* ActiveDownloadMac.cpp in Sources */,
09BB434711D92F65005ADA46 /* CEmulatorCtrlMac.cpp in Sources */,
92FA0F2A25B5353D00663577 /* DebugMemoryViewController.swift in Sources */,
09BB43B011D92F70005ADA46 /* activeconfig.cpp in Sources */,
09BB43B111D92F70005ADA46 /* ActiveDownload.cpp in Sources */,
92B9EADF24D3369700E6CFB2 /* EmulatorKeyboard.swift in Sources */,
927E436B25C94C12008E5517 /* Mnemonic.swift in Sources */,
09052B9419053C9F00853FAE /* uncompr.cpp in Sources */,
09BB43B211D92F70005ADA46 /* ActiveZip.cpp in Sources */,
09052B8619053C9F00853FAE /* pngwtran.cpp in Sources */,
09052B8B19053C9F00853FAE /* zip.cpp in Sources */,
927E436825C94C12008E5517 /* CPU+Stack.swift in Sources */,
927E436725C94C12008E5517 /* CPU+Flags.swift in Sources */,
927E436925C94C12008E5517 /* CPU.swift in Sources */,
09BB43B311D92F70005ADA46 /* CA2Text.cpp in Sources */,
09BB43B411D92F70005ADA46 /* CEmulatorCtrl.cpp in Sources */,
09BB43B511D92F70005ADA46 /* interface.cpp in Sources */,
@ -1321,6 +1471,7 @@
09BB43B711D92F70005ADA46 /* rom.cpp in Sources */,
09FA6095125A7B3E00B07F77 /* activegsAppDelegate.mm in Sources */,
09052B8119053C9F00853FAE /* pngset.cpp in Sources */,
927E436425C94C12008E5517 /* Stream.swift in Sources */,
09FA6096125A7B3E00B07F77 /* activegsList.mm in Sources */,
09FA6097125A7B3E00B07F77 /* activegsViewController.mm in Sources */,
09052B8D19053C9F00853FAE /* compress.cpp in Sources */,
@ -1328,14 +1479,19 @@
09FA609A125A7B3E00B07F77 /* asyncimageview.mm in Sources */,
09FA609C125A7B3E00B07F77 /* GTMUIView+SubtreeDescription.m in Sources */,
09052B8F19053C9F00853FAE /* deflate.cpp in Sources */,
92A9D66E25CC5A96008F5031 /* DebuggerUtils.swift in Sources */,
09FA609F125A7B3E00B07F77 /* KBDController.mm in Sources */,
09AADC78125C560A00654DF1 /* detailViewController.mm in Sources */,
09A5CE60125D41860018DC22 /* infoViewController.mm in Sources */,
92A9D67525CC5B7D008F5031 /* DebugMemoryButton.swift in Sources */,
0972554713CF2232006194F9 /* activegsEmulatorController.mm in Sources */,
924A1BB51CBA049D00D69162 /* KeyMapper.m in Sources */,
92E2063225AADFB000AE3F28 /* PreviewUI.swift in Sources */,
0907BCC9142F567A0051CA0A /* asynccommand.mm in Sources */,
09052B7D19053C9F00853FAE /* pngread.cpp in Sources */,
09C81A781657ACAE008539D5 /* adb.cpp in Sources */,
09C81A791657ACAE008539D5 /* async_event.cpp in Sources */,
927E437025C99A11008E5517 /* Debug6502Interpreter.swift in Sources */,
09C81A7A1657ACAE008539D5 /* clock.cpp in Sources */,
09052B9119053C9F00853FAE /* inflate.cpp in Sources */,
09C81A7B1657ACAE008539D5 /* compile_time.cpp in Sources */,
@ -1343,6 +1499,7 @@
09C81A7D1657ACAE008539D5 /* config_generic.cpp in Sources */,
09052B8C19053C9F00853FAE /* adler32.cpp in Sources */,
09C81A7F1657ACAE008539D5 /* dis.cpp in Sources */,
92A9D67125CC5AF4008F5031 /* EmuMemoryModel.swift in Sources */,
09C81A801657ACAE008539D5 /* engine_c.cpp in Sources */,
09C81A811657ACAE008539D5 /* GraphCounter.cpp in Sources */,
09C81A821657ACAE008539D5 /* iwm.cpp in Sources */,
@ -1353,13 +1510,17 @@
09C81A861657ACAE008539D5 /* openalasync_snddriver.cpp in Sources */,
09052B8219053C9F00853FAE /* pngtrans.cpp in Sources */,
09C81A871657ACAE008539D5 /* paddles.cpp in Sources */,
924A1BAC1CB81B5800D69162 /* GameControllerKeyRemapController.m in Sources */,
09C81A881657ACAE008539D5 /* SaveState.cpp in Sources */,
09C81A891657ACAE008539D5 /* scc.cpp in Sources */,
927E436625C94C12008E5517 /* CPU+Instructions.swift in Sources */,
09C81A8A1657ACAE008539D5 /* scc_socket_driver.cpp in Sources */,
09052B8319053C9F00853FAE /* pngvcrd.cpp in Sources */,
927E436C25C94C12008E5517 /* AddressingMode.swift in Sources */,
09C81A8B1657ACAE008539D5 /* sim65816.cpp in Sources */,
09C81A8C1657ACAE008539D5 /* smartport.cpp in Sources */,
09052B9019053C9F00853FAE /* inffast.cpp in Sources */,
927E436A25C94C12008E5517 /* Instruction.swift in Sources */,
09C81A8D1657ACAE008539D5 /* sound.cpp in Sources */,
09052B7819053C9F00853FAE /* pngerror.cpp in Sources */,
09052B7B19053C9F00853FAE /* pngmem.cpp in Sources */,
@ -1371,14 +1532,19 @@
09C81A9C1657ACDD008539D5 /* macdriver_generic.cpp in Sources */,
09052B8919053C9F00853FAE /* iowin32.cpp in Sources */,
09C81A9F1657ACDD008539D5 /* scc_macdriver.cpp in Sources */,
927E436525C94C12008E5517 /* Bus.swift in Sources */,
09C81AA71657AD18008539D5 /* emulatorView.mm in Sources */,
09C81AA81657AD18008539D5 /* joystick_iphone.cpp in Sources */,
09C81AA91657AD18008539D5 /* zoomEmulatorView.mm in Sources */,
09052B7F19053C9F00853FAE /* pngrtran.cpp in Sources */,
92A9D67925CC5BB6008F5031 /* DebugMemoryCell.swift in Sources */,
09052B7A19053C9F00853FAE /* pngget.cpp in Sources */,
924A1BB21CB9685700D69162 /* KeyCapView.m in Sources */,
09052B7919053C9F00853FAE /* pnggccrd.cpp in Sources */,
09052B9219053C9F00853FAE /* inftrees.cpp in Sources */,
927E431A25C48592008E5517 /* CheatFinderManager.swift in Sources */,
09052B8819053C9F00853FAE /* ioapi.cpp in Sources */,
92A9D67F25CC5C66008F5031 /* DebugMemoryActionViewController.swift in Sources */,
09052B7C19053C9F00853FAE /* pngpread.cpp in Sources */,
09052B8419053C9F00853FAE /* pngwio.cpp in Sources */,
09052B8719053C9F00853FAE /* pngwutil.cpp in Sources */,
@ -1390,6 +1556,7 @@
0941E6AF16720886003E0411 /* simplexml.cpp in Sources */,
09520D8316AEF8130065E84A /* driver.cpp in Sources */,
09520D8916AEF8250065E84A /* activegs_driver.cpp in Sources */,
92FA0F2425B52EA200663577 /* EmuWrapper.mm in Sources */,
09520D8E16AEF8650065E84A /* apple2e.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -1433,12 +1600,13 @@
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CODE_SIGN_ENTITLEMENTS = "";
CODE_SIGN_ENTITLEMENTS = ActiveGS/ActiveGS.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
DEVELOPMENT_TEAM = TFQRCMRWP4;
DEVELOPMENT_TEAM = R72X3BF4KE;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = activegs_Prefix.pch;
GCC_PREPROCESSOR_DEFINITIONS = (
@ -1453,16 +1621,19 @@
GCC_THUMB_SUPPORT = NO;
GCC_VERSION = "";
INFOPLIST_FILE = activegs.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks/GraphicsServices.framework\"",
);
PRODUCT_BUNDLE_IDENTIFIER = com.activeGS.test;
PRODUCT_BUNDLE_IDENTIFIER = com.yoshisuga.activeGS;
PRODUCT_NAME = ActiveGS;
PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = iphoneos;
SWIFT_OBJC_BRIDGING_HEADER = "../Common.iphone/ActiveGS-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
@ -1474,12 +1645,13 @@
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CODE_SIGN_ENTITLEMENTS = "";
CODE_SIGN_ENTITLEMENTS = ActiveGS/ActiveGS.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEVELOPMENT_TEAM = TFQRCMRWP4;
DEVELOPMENT_TEAM = R72X3BF4KE;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
@ -1496,16 +1668,20 @@
GCC_THUMB_SUPPORT = NO;
GCC_VERSION = "";
INFOPLIST_FILE = activegs.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks/GraphicsServices.framework\"",
);
PRODUCT_BUNDLE_IDENTIFIER = com.activeGS.test;
PRODUCT_BUNDLE_IDENTIFIER = com.yoshisuga.activeGS;
PRODUCT_NAME = ActiveGS;
PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = iphoneos;
SWIFT_OBJC_BRIDGING_HEADER = "../Common.iphone/ActiveGS-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
@ -1516,12 +1692,13 @@
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CODE_SIGN_ENTITLEMENTS = "";
CODE_SIGN_ENTITLEMENTS = ActiveGS/ActiveGS.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
DEVELOPMENT_TEAM = TFQRCMRWP4;
DEVELOPMENT_TEAM = R72X3BF4KE;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = activegs_Prefix.pch;
GCC_PREPROCESSOR_DEFINITIONS = (
@ -1535,16 +1712,19 @@
GCC_THUMB_SUPPORT = NO;
GCC_VERSION = "";
INFOPLIST_FILE = activegs.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks/GraphicsServices.framework\"",
);
PRODUCT_BUNDLE_IDENTIFIER = com.activeGS.test;
PRODUCT_BUNDLE_IDENTIFIER = com.yoshisuga.activeGS;
PRODUCT_NAME = ActiveGS;
PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = iphoneos;
SWIFT_OBJC_BRIDGING_HEADER = "../Common.iphone/ActiveGS-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -131,91 +131,13 @@ Cg
<attributes>
<font key="NSFont" size="11" name="CourierNewPSMT"/>
<font key="NSOriginalFont" size="11" name="CourierNewPSMT"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment content=".zip">
<attributes>
<font key="NSFont" size="11" name="CourierNewPSMT"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment>
@ -224,365 +146,53 @@ Cgo
</string>
<attributes>
<font key="NSFont" size="14" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment content="(">
<attributes>
<font key="NSFont" size="10" name="HelveticaNeue"/>
<font key="NSOriginalFont" size="10" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment content="N">
<attributes>
<font key="NSFont" size="10" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment content="ote: ">
<attributes>
<font key="NSFont" size="10" name="HelveticaNeue"/>
<font key="NSOriginalFont" size="10" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment content="Square-Enix canceled plans to release ">
<attributes>
<font key="NSFont" size="10" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment content="Final Fantasy XV ">
<attributes>
<font key="NSFont" size="10" name="HelveticaNeue"/>
<font key="NSOriginalFont" size="10" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment content="on the Apple IIGS due to excessive shipping costs, therefore it remains unreleased">
<attributes>
<font key="NSFont" size="10" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment content=")">
<attributes>
<font key="NSFont" size="10" name="HelveticaNeue"/>
<font key="NSOriginalFont" size="10" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment>
@ -591,46 +201,7 @@ Cgo
</string>
<attributes>
<font key="NSFont" size="10" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment>
@ -643,92 +214,14 @@ Cgo
</string>
<attributes>
<font key="NSFont" size="14" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment content="Gamepad">
<attributes>
<font key="NSFont" size="14" name="HelveticaNeue-Bold"/>
<font key="NSOriginalFont" size="14" name="HelveticaNeue-Bold"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment>
@ -736,46 +229,7 @@ Cgo
</string>
<attributes>
<font key="NSFont" size="14" name="HelveticaNeue-Bold"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment>
@ -788,92 +242,14 @@ Cgo
</string>
<attributes>
<font key="NSFont" size="14" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment content="Save States">
<attributes>
<font key="NSFont" size="14" name="HelveticaNeue-Bold"/>
<font key="NSOriginalFont" size="14" name="HelveticaNeue-Bold"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
<fragment>
@ -881,46 +257,7 @@ Cgo
- Are supported and they work..most of the time! Save states are specific to each program and you have 6 available slots.</string>
<attributes>
<font key="NSFont" size="14" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
<tabStops>
<textTab alignment="left" location="28">
<options/>
</textTab>
<textTab alignment="left" location="56">
<options/>
</textTab>
<textTab alignment="left" location="84">
<options/>
</textTab>
<textTab alignment="left" location="112">
<options/>
</textTab>
<textTab alignment="left" location="140">
<options/>
</textTab>
<textTab alignment="left" location="168">
<options/>
</textTab>
<textTab alignment="left" location="196">
<options/>
</textTab>
<textTab alignment="left" location="224">
<options/>
</textTab>
<textTab alignment="left" location="252">
<options/>
</textTab>
<textTab alignment="left" location="280">
<options/>
</textTab>
<textTab alignment="left" location="308">
<options/>
</textTab>
<textTab alignment="left" location="336">
<options/>
</textTab>
</tabStops>
</paragraphStyle>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
</attributes>
</fragment>
</attributedString>

View File

@ -0,0 +1,9 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import <UIKit/UIKit.h>
#import "KeyMapper.h"
#import "EmuWrapper.h"

View File

@ -0,0 +1,14 @@
//
// BUS.swift
// Monitor
//
// Created by Michał Kałużny on 08.01.18.
//
import Foundation
public protocol Bus {
func read(from address: UInt16) throws -> UInt8
func read(from address: UInt16) throws -> UInt16
func write(to address: UInt16, value: UInt8) throws
}

View File

@ -0,0 +1,72 @@
//
// Flags.swift
// 6502
//
// Created by Michał Kałużny on 17/11/2016.
//
//
import Foundation
extension CPU {
struct Flags: OptionSet {
let rawValue: UInt8
static let negative = Flags(rawValue: 1 << 7)
static let overflow = Flags(rawValue: 1 << 6)
static let always = Flags(rawValue: 1 << 5)
static let `break` = Flags(rawValue: 1 << 4)
static let decimal = Flags(rawValue: 1 << 3)
static let interrupt = Flags(rawValue: 1 << 2)
static let zero = Flags(rawValue: 1 << 1)
static let carry = Flags(rawValue: 1 << 0)
init(rawValue: UInt8) {
self.rawValue = rawValue | 0b0010_0000
}
}
internal func recalculateStatus(flags: Flags, for value: UInt8) {
if flags.contains(.carry) {
calculateCarry(value: value)
}
if flags.contains(.overflow) {
calculateCarry(value: value)
}
if flags.contains(.negative) {
calculateSign(value: value)
}
if flags.contains(.zero) {
calculateZero(value: value)
}
}
private func calculateCarry(value: UInt8) {
}
private func calculateOverflow(value: UInt8) {
}
private func calculateSign(value: UInt8) {
let bit = (value & (1 << 7)) != 0
if bit {
Status.insert(.negative)
} else {
Status.remove(.negative)
}
}
private func calculateZero(value: UInt8) {
if value != 0 {
Status.remove(.zero)
} else {
Status.insert(.zero)
}
}
}

View File

@ -0,0 +1,246 @@
//
// CPU+Instructions.swift
// MOS6502PackageDescription
//
// Created by Michał Kałużny on 09.01.18.
//
import Foundation
extension CPU {
internal func execute(instruction: Instruction) throws {
switch instruction.mnemonic {
//MARK: Branch Instructions
case .BNE:
PC += instruction.size
if Status.contains(.zero) != true {
PC = try instruction.addressingMode.value(with: self, bus: bus)
}
case .BEQ:
PC += instruction.size
if Status.contains(.zero) == true {
PC = try instruction.addressingMode.value(with: self, bus: bus)
}
case .BPL:
PC += instruction.size
if Status.contains(.negative) != true {
PC = try instruction.addressingMode.value(with: self, bus: bus)
}
case .BCC:
PC += instruction.size
if Status.contains(.carry) != true {
PC = try instruction.addressingMode.value(with: self, bus: bus)
}
case .BCS:
PC += instruction.size
if Status.contains(.carry) == true {
PC = try instruction.addressingMode.value(with: self, bus: bus)
}
case .BMI:
PC += instruction.size
if Status.contains(.negative) == true {
PC = try instruction.addressingMode.value(with: self, bus: bus)
}
case .BVC:
PC += instruction.size
if Status.contains(.overflow) != true {
PC = try instruction.addressingMode.value(with: self, bus: bus)
}
case .BVS:
PC += instruction.size
if Status.contains(.overflow) == true {
PC = try instruction.addressingMode.value(with: self, bus: bus)
}
//MARK: Stack Operations
case .TXS:
SP = X
PC += instruction.size
case .TSX:
X = SP
recalculateStatus(flags: [.zero, .negative], for: X)
PC += instruction.size
case .PLP:
let value = try pop() as UInt8
Status = Flags(rawValue: value)
PC += instruction.size
case .PHP:
try push(Status.rawValue | 0b0001_0000)
PC += instruction.size
case .PHA:
try push(A)
PC += instruction.size
case .PLA:
A = try pop()
recalculateStatus(flags: [.zero, .negative], for: A)
PC += instruction.size
case .JSR:
// JSR writes the *address of the last byte* of the instruction.
try push(PC + instruction.size - 1)
PC = try instruction.addressingMode.value(with: self, bus: bus)
case .RTS:
PC += instruction.size
PC = try pop()
// We would land on the *last byte* of the JSR, just before the jump, we need to advance the PC
PC += 1
//MARK: Register Operations
case .INX:
X = X &+ 1
recalculateStatus(flags: [.zero, .negative], for: X)
PC += instruction.size
case .DEX:
X = X &- 1
recalculateStatus(flags: [.zero, .negative], for: X)
PC += instruction.size
case .INY:
Y = Y &+ 1
recalculateStatus(flags: [.zero, .negative], for: Y)
PC += instruction.size
case .DEY:
Y = Y &- 1
recalculateStatus(flags: [.zero, .negative], for: Y)
PC += instruction.size
case .TYA:
A = Y
recalculateStatus(flags: [.negative, .zero], for: A)
PC += instruction.size
case .TXA:
A = X
recalculateStatus(flags: [.negative, .zero], for: A)
PC += instruction.size
case .TAX:
X = A
recalculateStatus(flags: [.negative, .zero], for: X)
PC += instruction.size
case .TAY:
Y = A
recalculateStatus(flags: [.negative, .zero], for: Y)
PC += instruction.size
//MARK: Flags Operations:
case .SEI:
Status.insert(.interrupt)
PC += instruction.size
case .CLD:
Status.remove(.decimal)
PC += instruction.size
case .CLC:
Status.remove(.carry)
PC += instruction.size
//MARK: Interrupt Operations:
case .BRK:
try push(PC)
try push(Status.rawValue)
PC = try bus.read(from: CPU.interruptVector)
Status.insert(.break)
//MARK: Other Instructions, clean me up please.
case .LDA:
A = try instruction.addressingMode.value(with: self, bus: bus)
recalculateStatus(flags: [.zero, .negative], for: A)
PC += instruction.size
case .STA:
let address: UInt16 = try instruction.addressingMode.value(with: self, bus: bus)
try bus.write(to: address, value: A)
PC += instruction.size
case .LDX:
X = try instruction.addressingMode.value(with: self, bus: bus)
recalculateStatus(flags: [.zero, .negative], for: X)
PC += instruction.size
case .STX:
let address = try instruction.addressingMode.value(with: self, bus: bus) as UInt16
try bus.write(to: address, value: X)
PC += instruction.size
case .LDY:
Y = try instruction.addressingMode.value(with: self, bus: bus)
recalculateStatus(flags: [.zero, .negative], for: Y)
PC += instruction.size
case .STY:
let address = try instruction.addressingMode.value(with: self, bus: bus) as UInt16
try bus.write(to: address, value: Y)
PC += instruction.size
case .JMP:
PC = try instruction.addressingMode.value(with: self, bus: bus)
case .CMP:
let value = try instruction.addressingMode.value(with: self, bus: bus) as UInt8
if A >= value {
Status.insert(.carry)
} else {
Status.remove(.carry)
}
let result = A &- value
recalculateStatus(flags: [.negative, .zero], for: result)
PC += instruction.size
case .CPY:
let value = try instruction.addressingMode.value(with: self, bus: bus) as UInt8
if Y >= value {
Status.insert(.carry)
} else {
Status.remove(.carry)
}
let result = Y &- value
recalculateStatus(flags: [.negative, .zero], for: result)
PC += instruction.size
case .CPX:
let value = try instruction.addressingMode.value(with: self, bus: bus) as UInt8
if X >= value {
Status.insert(.carry)
} else {
Status.remove(.carry)
}
let result = X &- value
recalculateStatus(flags: [.negative, .zero], for: result)
PC += instruction.size
case .ADC:
let value = try instruction.addressingMode.value(with: self, bus: bus) as UInt8
let carry: UInt8 = Status.contains(.carry) ? 1 : 0
let result = [A, value, carry].map(UInt16.init).reduce(0, +)
if result > UInt8.max {
Status.insert(.carry)
} else {
Status.remove(.carry)
}
let final: UInt8 = UInt8(result & 0xFF)
let overflow = (((A ^ final) & 0x80) != 0) && (((UInt16(A) ^ result) & 0x80) == 0)
if overflow {
Status.insert(.overflow)
} else {
Status.remove(.overflow)
}
A = final
recalculateStatus(flags: [.negative, .zero], for: A)
PC += instruction.size
case .EOR:
let value = try instruction.addressingMode.value(with: self, bus: bus) as UInt8
A = A ^ value
recalculateStatus(flags: [.negative, .zero], for: A)
PC += instruction.size
case .NOP:
PC += instruction.size
case _:
throw Error.unimplementedInstruction(instruction: instruction)
}
}
}

View File

@ -0,0 +1,45 @@
//
// CPU+Stack.swift
// MOS6502PackageDescription
//
// Created by Michał Kałużny on 09.01.18.
//
import Foundation
extension CPU {
static let stackPointerBase: UInt16 = 0x100
internal func pop() throws -> UInt8 {
SP += 1
let value: UInt8 = try bus.read(from: UInt16(SP) + CPU.stackPointerBase)
print("Popping value: \(value.hex)")
return value
}
internal func pop() throws -> UInt16 {
let low: UInt8 = try pop()
let high: UInt8 = try pop()
return UInt16(low) | UInt16(high) << 8
}
internal func push(_ value: UInt8) throws {
try bus.write(to: UInt16(SP) + CPU.stackPointerBase, value: value)
print("Pushing value: \(value.hex)")
SP -= 1
}
internal func push(_ value: UInt16) throws {
let low: UInt8 = UInt8(value & 0xFF)
let high: UInt8 = UInt8(value >> 8) & 0xFF
try push(high)
try push(low)
}
}

View File

@ -0,0 +1,99 @@
//
// CPU.swift
// 6502
//
// Created by Michał Kałużny on 15/11/2016.
//
//
import Foundation
public class CPU {
static let nmiVector: UInt16 = 0xFFFA
static let resetVector: UInt16 = 0xFFFC
static let interruptVector: UInt16 = 0xFFFE
enum Error: Swift.Error {
case unimplementedInstruction(instruction: Instruction)
}
public enum Register {
case X
case Y
}
//MARK: Registers
public var PC: UInt16 = 0
var A: UInt8 = 0
var X: UInt8 = 0
var Y: UInt8 = 0
var SP: UInt8 = 0
var Status: Flags = []
let bus: Bus
let breakpoints: [UInt16] = [0x378A]
public init(bus: Bus) {
self.bus = bus
}
public func reset() throws {
PC = try bus.read(from: CPU.resetVector)
A = 0
X = 0
Y = 0
SP = 0xFF
Status = [.break, .interrupt, .always]
}
public func step() throws {
if breakpoints.contains(PC) {
print("Breakpoint!")
}
print(self)
let instruction = try fetch()
print(instruction)
try execute(instruction: instruction)
print(self)
print("=============================")
}
public func run() throws {
while true {
try step()
}
}
public func fetch() throws -> Instruction {
return try Instruction(from: bus, PC: PC)
}
subscript(register: Register) -> UInt8 {
switch register {
case .X:
return X
case .Y:
return Y
}
}
}
extension CPU: CustomStringConvertible {
public var description: String {
return "PC: \(PC.hex) SP: \(SP.hex) A: \(A.hex) X: \(X.hex) Y: \(Y.hex) \nFlags: \(Status.rawValue.bin)"
}
}
extension FixedWidthInteger {
public var hex: String {
return String(self, radix: 16, uppercase: true)
}
var bin: String {
return String(self, radix: 2, uppercase: true)
}
}

View File

@ -0,0 +1,71 @@
//
// Debug6502Interpreter.swift
// ActiveGS
//
// Created by Yoshi Sugawara on 2/2/21.
//
import Foundation
public struct AddressedInstruction: CustomStringConvertible {
let address: UInt16
let instruction: Instruction
public var description: String {
return String(format: "$%04X : \(instruction.description)", address)
}
}
enum InterpreterError: Error {
case instructionError(String)
}
public class Debug6502Interpreter: Bus {
public func read(from address: UInt16) throws -> UInt8 {
if address >= memory.count {
return 0
}
return memory[Int(address)]
}
public func read(from address: UInt16) throws -> UInt16 {
if address + 1 >= memory.count {
throw InterpreterError.instructionError("Tried to read beyond memory bus")
}
let low: UInt8 = try read(from: address)
let high: UInt8 = try read(from: address + 1)
return (UInt16(high) << 8 | UInt16(low))
}
public func write(to address: UInt16, value: UInt8) throws {
// no-op, interpreter only
}
var memory: [UInt8]
var cpu: CPU! = nil
init(memory: [UInt8]) {
self.memory = memory
self.cpu = CPU(bus: self)
}
public func interpret(startAt address:UInt16 = 0) -> [AddressedInstruction] {
cpu.PC = address
var instructions = [AddressedInstruction]()
while cpu.PC < memory.count {
do {
let instruction = try cpu.fetch()
instructions.append(AddressedInstruction(address: cpu.PC, instruction: instruction))
cpu.PC += instruction.size
} catch Instruction.Error.unknownOpcode(let opcode) {
print("Unknown opcode: \(opcode), skipping...")
cpu.PC += 1
} catch {
print("Error when interpreting, stopping...")
break
}
}
return instructions
}
}

View File

@ -0,0 +1,97 @@
//
// AddressingMode.swift
// 6502
//
// Created by Michał Kałużny on 16/11/2016.
//
//
import Foundation
public extension Instruction {
enum AddressingMode {
enum Error: Swift.Error {
case addressingModeNotImplemented
}
case accumulator
case immediate(data: UInt8)
case implied
case relative(data: Int8)
case absolute(data: UInt16)
case zeroPage(data: UInt8)
case indirect(data: UInt16)
case indexedIndirect(data: UInt8, register: CPU.Register)
case indirectIndexed(data: UInt8, register: CPU.Register)
case absoluteIndexed(data: UInt16, register: CPU.Register)
case zeroPageIndexed(data: UInt8, register: CPU.Register)
func value(with cpu: CPU, bus: Bus) throws -> UInt8 {
switch self {
case .immediate(let data):
return data
case .absolute(let data):
return try bus.read(from: data)
case .absoluteIndexed(let data, let register):
// Check if we should be overflowing here?
return try bus.read(from: data &+ UInt16(cpu[register]))
case _: throw Error.addressingModeNotImplemented
}
}
func value(with cpu: CPU, bus: Bus) throws -> UInt16 {
switch self {
case .absolute(let data):
return data
case .zeroPageIndexed(let base, let register):
switch register {
case .X:
return UInt16(base &+ cpu.X)
case .Y:
return UInt16(base &+ cpu.Y)
}
case .indirect(let data):
return try bus.read(from: data)
case .relative(let data):
return UInt16(Int32(cpu.PC) + Int32(data))
case .zeroPage(let data):
return UInt16(data)
case _: throw Error.addressingModeNotImplemented
}
}
public var dataSize: UInt16 {
switch self {
case .absolute: return 2
case .absoluteIndexed: return 1
case .implied: return 0
case .immediate: return 1
case .indirect: return 2
case .accumulator: return 0
case .relative: return 1
case .zeroPage: return 1
case .indirectIndexed: return 1
case .indexedIndirect: return 1
case .zeroPageIndexed: return 1
}
}
}
}
extension Instruction.AddressingMode: CustomStringConvertible {
public var description: String {
switch self {
case .accumulator: return "A"
case .implied: return ""
case .immediate(let data): return "#$\(String(format: "%02x", data))"
case .relative(let data): return "$\(String(format: "%0X", data))"
case .zeroPage(let data): return "$\(String(format: "%02x", data))"
case .indirect(let data): return "$\(String(format: "%02x", data))"
case .absolute(let data): return "$\(String(format: "%04x", data))"
case .indirectIndexed(let data, let register): return "($\(String(format: "%02x", data)), \(register))"
case .indexedIndirect(let data, let register): return "($\(String(format: "%02x", data))), \(register)"
case .absoluteIndexed(let data, let register): return "$\(String(format: "%04x", data)), \(register)"
case .zeroPageIndexed(let data, let register): return "$\(String(format: "%02x", data)), \(register)"
}
}
}

View File

@ -0,0 +1,215 @@
//
// Instruction.swift
// 6502
//
// Created by Michał Kałużny on 15/11/2016.
//
//
import Foundation
public struct Instruction {
public let opcode: UInt8
public let mnemonic: Mnemonic
public let addressingMode: AddressingMode
public enum Error: Swift.Error {
case unknownOpcode(opcode: UInt8)
}
public init(from bus: Bus, PC: UInt16) throws {
opcode = try bus.read(from: PC) as UInt8
mnemonic = try Mnemonic(opcode)
//MARK: Addressing Mode
switch opcode {
case 0x20: fallthrough
case 0x0d: fallthrough
case 0x0e: fallthrough
case 0x2c: fallthrough
case 0x2d: fallthrough
case 0x2e: fallthrough
case 0x4c: fallthrough
case 0x4d: fallthrough
case 0x4e: fallthrough
case 0x6d: fallthrough
case 0x7e: fallthrough
case 0x8c: fallthrough
case 0x8d: fallthrough
case 0x8e: fallthrough
case 0xac: fallthrough
case 0xad: fallthrough
case 0xae: fallthrough
case 0xcc: fallthrough
case 0xcd: fallthrough
case 0xce: fallthrough
case 0xec: fallthrough
case 0xed: fallthrough
case 0xee:
let data = try bus.read(from: PC + 1) as UInt16
addressingMode = .absolute(data: data)
case 0x1d: fallthrough
case 0x1e: fallthrough
case 0x3d: fallthrough
case 0x3e: fallthrough
case 0x5d: fallthrough
case 0x5e: fallthrough
case 0x6e: fallthrough
case 0x7d: fallthrough
case 0x9d: fallthrough
case 0xbc: fallthrough
case 0xbd: fallthrough
case 0xdd: fallthrough
case 0xde: fallthrough
case 0xfd: fallthrough
case 0xfe:
let data = try bus.read(from: PC + 1) as UInt16
addressingMode = .absoluteIndexed(data: data, register: .X)
case 0x19: fallthrough
case 0x39: fallthrough
case 0x59: fallthrough
case 0x79: fallthrough
case 0x99: fallthrough
case 0xb9: fallthrough
case 0xbe: fallthrough
case 0xd9: fallthrough
case 0xf9:
let data = try bus.read(from: PC + 1) as UInt16
addressingMode = .absoluteIndexed(data: data, register: .Y)
case 0x0a: fallthrough
case 0x2a: fallthrough
case 0x4a: fallthrough
case 0x6a:
addressingMode = .accumulator
case 0x09: fallthrough
case 0x29: fallthrough
case 0x49: fallthrough
case 0x69: fallthrough
case 0xa0: fallthrough
case 0xa2: fallthrough
case 0xa9: fallthrough
case 0xc0: fallthrough
case 0xc9: fallthrough
case 0xe0: fallthrough
case 0xe9:
let data = try bus.read(from: PC + 1) as UInt8
addressingMode = .immediate(data: data)
case 0x0: fallthrough
case 0x8: fallthrough
case 0x18: fallthrough
case 0x28: fallthrough
case 0x38: fallthrough
case 0x40: fallthrough
case 0x48: fallthrough
case 0x58: fallthrough
case 0x60: fallthrough
case 0x68: fallthrough
case 0x78: fallthrough
case 0x88: fallthrough
case 0x98: fallthrough
case 0x8a: fallthrough
case 0x9a: fallthrough
case 0xa8: fallthrough
case 0xaa: fallthrough
case 0xb8: fallthrough
case 0xba: fallthrough
case 0xc8: fallthrough
case 0xca: fallthrough
case 0xd8: fallthrough
case 0xe8: fallthrough
case 0xea: fallthrough
case 0xf8:
addressingMode = .implied
case 0x1: fallthrough
case 0x21: fallthrough
case 0x41: fallthrough
case 0x61: fallthrough
case 0x81: fallthrough
case 0xa1: fallthrough
case 0xc1: fallthrough
case 0xe1:
let data = try bus.read(from: PC + 1) as UInt8
addressingMode = .indexedIndirect(data: data, register: .X)
case 0x6c:
let data = try bus.read(from: PC + 1) as UInt16
addressingMode = .indirect(data: data)
case 0x11: fallthrough
case 0x31: fallthrough
case 0x51: fallthrough
case 0x71: fallthrough
case 0x91: fallthrough
case 0xb1: fallthrough
case 0xd1: fallthrough
case 0xf1:
let data = try bus.read(from: PC + 1) as UInt8
addressingMode = .indirectIndexed(data: data, register: .Y)
case 0x10: fallthrough
case 0x30: fallthrough
case 0x50: fallthrough
case 0x70: fallthrough
case 0x90: fallthrough
case 0xb0: fallthrough
case 0xd0: fallthrough
case 0xf0:
let data = try bus.read(from: PC + 1) as UInt8
addressingMode = .relative(data: Int8(bitPattern: data))
case 0x5: fallthrough
case 0x6: fallthrough
case 0x24: fallthrough
case 0x25: fallthrough
case 0x26: fallthrough
case 0x45: fallthrough
case 0x46: fallthrough
case 0x65: fallthrough
case 0x66: fallthrough
case 0x84: fallthrough
case 0x85: fallthrough
case 0x86: fallthrough
case 0xa4: fallthrough
case 0xa5: fallthrough
case 0xa6: fallthrough
case 0xc4: fallthrough
case 0xc5: fallthrough
case 0xc6: fallthrough
case 0xe4: fallthrough
case 0xe5: fallthrough
case 0xe6:
let data = try bus.read(from: PC + 1) as UInt8
addressingMode = .zeroPage(data: data)
case 0x15: fallthrough
case 0x16: fallthrough
case 0x35: fallthrough
case 0x36: fallthrough
case 0x55: fallthrough
case 0x56: fallthrough
case 0x75: fallthrough
case 0x76: fallthrough
case 0x94: fallthrough
case 0x95: fallthrough
case 0xb4: fallthrough
case 0xb5: fallthrough
case 0xd5: fallthrough
case 0xd6: fallthrough
case 0xf5: fallthrough
case 0xf6:
let data = try bus.read(from: PC + 1) as UInt8
addressingMode = .zeroPageIndexed(data: data, register: .X)
case 0x96: fallthrough
case 0xb6:
let data = try bus.read(from: PC + 1) as UInt8
addressingMode = .zeroPageIndexed(data: data, register: .Y)
default:
throw Error.unknownOpcode(opcode: opcode)
}
}
public var size: UInt16 {
return addressingMode.dataSize + 1
}
}
extension Instruction: CustomStringConvertible {
public var description: String {
return "\(mnemonic) \(addressingMode)"
}
}

View File

@ -0,0 +1,123 @@
//
// Opcode.swift
// 6502
//
// Created by Michał Kałużny on 16/11/2016.
//
//
import Foundation
private let mnemonicTable: [Instruction.Mnemonic?] = [
/* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */
/* 0 */ .BRK, .ORA, nil, .SLO, nil, .ORA, .ASL, .SLO, .PHP, .ORA, .ASL, nil, nil, .ORA, .ASL, .SLO, /* 0 */
/* 1 */ .BPL, .ORA, nil, .SLO, nil, .ORA, .ASL, .SLO, .CLC, .ORA, nil, .SLO, nil, .ORA, .ASL, .SLO, /* 1 */
/* 2 */ .JSR, .AND, nil, .RLA, .BIT, .AND, .ROL, .RLA, .PLP, .AND, .ROL, nil, .BIT, .AND, .ROL, .RLA, /* 2 */
/* 3 */ .BMI, .AND, nil, .RLA, nil, .AND, .ROL, .RLA, .SEC, .AND, nil, .RLA, nil, .AND, .ROL, .RLA, /* 3 */
/* 4 */ .RTI, .EOR, nil, .SRE, nil, .EOR, .LSR, .SRE, .PHA, .EOR, .LSR, nil, .JMP, .EOR, .LSR, .SRE, /* 4 */
/* 5 */ .BVC, .EOR, nil, .SRE, nil, .EOR, .LSR, .SRE, .CLI, .EOR, nil, .SRE, nil, .EOR, .LSR, .SRE, /* 5 */
/* 6 */ .RTS, .ADC, nil, .RRA, nil, .ADC, .ROR, .RRA, .PLA, .ADC, .ROR, nil, .JMP, .ADC, .ROR, .RRA, /* 6 */
/* 7 */ .BVS, .ADC, nil, .RRA, nil, .ADC, .ROR, .RRA, .SEI, .ADC, nil, .RRA, nil, .ADC, .ROR, .RRA, /* 7 */
/* 8 */ nil, .STA, nil, .SAX, .STY, .STA, .STX, .SAX, .DEY, nil, .TXA, nil, .STY, .STA, .STX, .SAX, /* 8 */
/* 9 */ .BCC, .STA, nil, nil, .STY, .STA, .STX, .SAX, .TYA, .STA, .TXS, nil, nil, .STA, nil, nil, /* 9 */
/* A */ .LDY, .LDA, .LDX, .LAX, .LDY, .LDA, .LDX, .LAX, .TAY, .LDA, .TAX, nil, .LDY, .LDA, .LDX, .LAX, /* A */
/* B */ .BCS, .LDA, nil, .LAX, .LDY, .LDA, .LDX, .LAX, .CLV, .LDA, .TSX, .LAX, .LDY, .LDA, .LDX, .LAX, /* B */
/* C */ .CPY, .CMP, nil, .DCP, .CPY, .CMP, .DEC, .DCP, .INY, .CMP, .DEX, nil, .CPY, .CMP, .DEC, .DCP, /* C */
/* D */ .BNE, .CMP, nil, .DCP, nil, .CMP, .DEC, .DCP, .CLD, .CMP, nil, .DCP, nil, .CMP, .DEC, .DCP, /* D */
/* E */ .CPX, .SBC, nil, .ISB, .CPX, .SBC, .INC, .ISB, .INX, .SBC, .NOP, .SBC, .CPX, .SBC, .INC, .ISB, /* E */
/* F */ .BEQ, .SBC, nil, .ISB, nil, .SBC, .INC, .ISB, .SED, .SBC, nil, .ISB, nil, .SBC, .INC, .ISB /* F */
]
public extension Instruction {
enum Mnemonic: String {
enum Error: Swift.Error {
case unknownMnemonic(opcode: String)
}
init(_ opcode: UInt8) throws {
guard let mnemonic = mnemonicTable[Int(opcode)] else {
throw Instruction.Error.unknownOpcode(opcode: opcode)
}
self = mnemonic
}
init(_ string: String) throws {
guard let value = Mnemonic(rawValue: string) else {
throw Error.unknownMnemonic(opcode: string)
}
self = value
}
case ADC
case AND
case ASL
case BCC
case BCS
case BEQ
case BIT
case BMI
case BNE
case BPL
case BRK
case BVC
case BVS
case CLC
case CLD
case CLI
case CLV
case CMP
case CPX
case CPY
case DCP
case DEC
case DEX
case DEY
case EOR
case INC
case INX
case INY
case ISB
case JMP
case JSR
case LAX
case LDA
case LDX
case LDY
case LSR
case NOP
case ORA
case PHA
case PHP
case PLA
case PLP
case RLA
case ROL
case ROR
case RRA
case RTI
case RTS
case SBC
case SEC
case SED
case SEI
case SLO
case SRE
case SAX
case STA
case STX
case STY
case TAX
case TAY
case TSX
case TXA
case TXS
case TYA
}
}
extension Instruction.Mnemonic: CustomStringConvertible {
public var description: String {
return "\(rawValue)"
}
}

View File

@ -0,0 +1,60 @@
//
// Stream.swift
// 6502
//
// Created by Michał Kałużny on 15/11/2016.
//
//
import Foundation
protocol RawStreamReadable {}
extension UInt8: RawStreamReadable {}
extension UInt16: RawStreamReadable {}
extension InputStream: Stream {
func read(_ length: Int) -> [UInt8] {
var buffer = Array<UInt8>(repeating: 0, count: length)
_ = read(&buffer, maxLength: length)
return buffer
}
}
class MemoryStream: Stream {
let storage: [UInt8]
var position: Int = 0
init(storage: [UInt8]) {
self.storage = storage
}
open func read(_ length: Int) -> [UInt8] {
if position+length > storage.count {
return [UInt8](repeating: 0, count: length)
}
let slice = storage[position..<position+length]
position += length
return Array(slice)
}
}
protocol Stream {
func read(_ length: Int) -> [UInt8]
}
extension Stream {
func read<T: RawStreamReadable>() -> T {
let size = MemoryLayout<T>.size
let bytes = read(size)
let data = Data(bytes: bytes)
let value: T = data.withUnsafeBytes { $0.pointee }
return value
}
func skip(_ count: Int) {
_ = read(count)
}
}

View File

@ -0,0 +1,84 @@
//
// CheatFinderManager.swift
// ActiveGS
//
// Created by Yoshi Sugawara on 1/29/21.
//
import Foundation
class CheatFinderManager {
private(set) var matchedMemoryAddresses = [Int: UInt8]()
var comparisonMemory = [UInt8]()
private let dispatchQueue = DispatchQueue(label: "CheatFinderManager", qos: .background)
var timer: DispatchSourceTimer?
var savedMatches = [Int: (value: UInt8, enabled: Bool)]()
enum UIState {
case initial, startedNewSearch, isSearching, didSearch, showSaved
}
enum SearchMode {
case less, greater, same
case equalTo(Int)
}
var uiState = UIState.initial
func start() {
if timer == nil {
timer = DispatchSource.makeTimerSource(queue: dispatchQueue)
timer?.setEventHandler(handler: {
self.updateMemoryWithCheats()
})
timer?.schedule(deadline: .now(), repeating: .seconds(1))
timer?.resume()
}
}
func updateMemoryWithCheats() {
print("CheatFinderManager updating memory...")
let memory = EmuWrapper.memory()
for (address, memoryValue) in savedMatches {
if let memory = memory, memoryValue.enabled {
print("updating memory at \(String(format: "%05X",address)) to \(memoryValue.value)")
memory[address] = memoryValue.value
}
}
}
func update(with memory: UnsafeMutablePointer<UInt8>) {
for address in 0..<EmuMemoryModel.maxMemorySize {
matchedMemoryAddresses[address] = memory[address]
}
}
func findNewMatches(searchMode: SearchMode) {
var newMatches = [Int: UInt8]()
for (address, oldValue) in matchedMemoryAddresses {
let newValue = comparisonMemory[address]
var matched = false
switch searchMode {
case .less:
matched = newValue < oldValue
case .greater:
matched = newValue > oldValue
case .same:
matched = newValue == oldValue
case .equalTo(let searchValue):
matched = newValue == searchValue
}
if matched {
newMatches[address] = newValue
}
// // avoid having too many matches
// if newMatches.count > 10000 {
// break
// }
}
matchedMemoryAddresses = newMatches
}
}

View File

@ -0,0 +1,37 @@
//
// DebuggerUtils.swift
// ActiveGS
//
// Created by Yoshi Sugawara on 2/4/21.
//
import Foundation
struct Orientation {
// indicate current device is in the LandScape orientation
static var isLandscape: Bool {
get {
return UIDevice.current.orientation.isValidInterfaceOrientation
? UIDevice.current.orientation.isLandscape
: (UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isLandscape)!
}
}
// indicate current device is in the Portrait orientation
static var isPortrait: Bool {
get {
return UIDevice.current.orientation.isValidInterfaceOrientation
? UIDevice.current.orientation.isPortrait
: (UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isPortrait)!
}
}
}
extension UIView {
func getSnapshot() -> UIImage {
UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main.scale)
drawHierarchy(in: self.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}

View File

@ -0,0 +1,137 @@
//
// EmuMemoryModel.swift
// ActiveGS
//
// Created by Yoshi Sugawara on 2/4/21.
//
import Foundation
class EmuMemoryModel {
let numToDisplayPerCell = 8
static let maxMemorySize = 256 * 1024
private(set) var memory = EmuWrapper.memory()
private(set) var referencedAddresses = [UInt16: [AddressedInstruction]]()
var selectedAddress: Int?
func offset(for indexPath: IndexPath) -> Int {
let memMapSection = EmuMemoryMapSection(rawValue: indexPath.section)!
return memMapSection.range.lowerBound + (indexPath.row * numToDisplayPerCell)
}
func hexStrings(for indexPath: IndexPath) -> [String] {
let memMapSection = EmuMemoryMapSection(rawValue: indexPath.section)!
let startIndex = offset(for: indexPath)
let endIndex = min(startIndex + numToDisplayPerCell, memMapSection.range.upperBound)
guard startIndex < memMapSection.range.upperBound,
endIndex <= memMapSection.range.upperBound else {
print("indexes are out of range of this section: startIndex=\(startIndex) endIndex=\(endIndex) section range: \(memMapSection.range.lowerBound) - \(memMapSection.range.upperBound)")
return []
}
var row = [String]()
guard let memory = memory else {
return row
}
for i in startIndex..<endIndex {
row.append(String(format: "%02X", memory[i]))
}
return row
}
func indexPath(for address: Int) -> IndexPath {
let section = EmuMemoryMapSection.section(for: address)
let offset = (address - section.range.lowerBound) / numToDisplayPerCell
return IndexPath(item: offset, section: section.rawValue)
}
func getMemoryHexString(at address: Int) -> String {
guard address > 0 && address < Self.maxMemorySize else {
print("Cannot get memory: address out of range \(address) > \(Self.maxMemorySize)")
return ""
}
guard let memory = memory else {
return ""
}
let value = memory[address]
return String(format: "%02X", value)
}
func getMemoryHeaderString(for address: Int) -> String {
return String(format: "%02X", address)
}
func setMemory(at address:Int, value: UInt8) {
guard address > 0 && address < Self.maxMemorySize else {
print("Cannot set memory: address out of range \(address) > \(Self.maxMemorySize)")
return
}
guard let memory = memory else {
return
}
print("Setting memory address %04X to %02X",address,value)
memory[address] = value
refresh()
}
func getMemory(at address:Int) -> UInt8 {
guard address > 0 && address < Self.maxMemorySize else {
print("Cannot get memory: address out of range \(address) > \(Self.maxMemorySize)")
return 0
}
guard let memory = memory else {
return 0
}
return memory[address]
}
var memoryAsArray: [UInt8] {
var buffer = [UInt8]()
guard let memory = memory else {
return buffer
}
for address in 0..<0x95ff {
buffer.append(memory[address])
}
return buffer
}
lazy var interpretedInstructions: [AddressedInstruction] = {
return interpreted()
}()
private func interpreted() -> [AddressedInstruction] {
let interpreter = Debug6502Interpreter(memory: memoryAsArray)
let instructions = interpreter.interpret()
referencedAddresses = [UInt16: [AddressedInstruction]]()
let updateBlock: ((UInt16, AddressedInstruction) -> Void) = { address, instruction in
var instructions: [AddressedInstruction] = {
if let existingInstructions = self.referencedAddresses[address] {
return existingInstructions
}
return [AddressedInstruction]()
}()
instructions.append(instruction)
self.referencedAddresses[address] = instructions
}
for instruction in instructions {
switch instruction.instruction.addressingMode {
case .absolute(let address):
updateBlock(address, instruction)
case .zeroPage(let zeroPageAddress):
updateBlock(UInt16(zeroPageAddress), instruction)
case .indirect(let fromAddress):
updateBlock(fromAddress, instruction)
default:
break
}
}
return instructions
}
func refresh() {
memory = EmuWrapper.memory()
interpretedInstructions = interpreted()
}
}

View File

@ -0,0 +1,24 @@
//
// EmuWrapper.h
// activegs
//
// Created by Yoshi Sugawara on 1/17/21.
//
#ifndef EmuWrapper_h
#define EmuWrapper_h
#endif /* EmuWrapper_h */
#import <Foundation/Foundation.h>
@interface EmuWrapper: NSObject
+(unsigned char*) memory;
+(void)pause;
+(void)resume;
+(UIView*)getEmulatorView;
+(unsigned int)cpuGetProgramCounter;
@end

View File

@ -0,0 +1,39 @@
//
// EmuWrapper.m
// ActiveGS
//
// Created by Yoshi Sugawara on 1/17/21.
//
#import <Foundation/Foundation.h>
#import "activegsAppDelegate.h"
#import "EmuWrapper.h"
#include "../../Common.osx/cemulatorctrlmac.h"
#include "../../kegs/Src/defc.h"
#include "../../kegs/Src/sim65816.h"
@implementation EmuWrapper
+(unsigned char*) memory {
return g_memory_ptr;
}
+(void)pause {
r_sim65816.pause();
}
+(void)resume {
r_sim65816.resume();
}
+(word32)cpuGetProgramCounter {
return g_sim65816.engine.kpc;
}
+(UIView*)getEmulatorView {
return [pManager getEmulatorView].zv.ew;
}
@end

View File

@ -0,0 +1,785 @@
//
// DebugMemoryActionViewController.swift
// ActiveGS
//
// Created by Yoshi Sugawara on 2/4/21.
//
import Foundation
protocol DebugMemoryActionViewControllerDelegate: class {
func jump(to address: Int)
func memoryHex(at address: Int) -> String
func updateMemory(at address: Int, with memory:UInt8)
var memory: UnsafeMutablePointer<UInt8>? { get }
var selectedAddress: Int? { get }
var referencedMemoryAddresses: [UInt16: [AddressedInstruction]] { get }
}
class DebugMemoryActionViewController: UIViewController {
enum Mode {
case jumpToAddress, changeMemory, cheat, screen
}
var mode: Mode = .jumpToAddress
let cheatFinder: CheatFinderManager
var matchedInstructions = [AddressedInstruction]()
weak var delegate:DebugMemoryActionViewControllerDelegate?
let segmentedControl: UISegmentedControl = {
let control = UISegmentedControl(items: ["Jump", "Edit", "Cheat", "Screen"])
control.translatesAutoresizingMaskIntoConstraints = false
control.tintColor = .orange
control.selectedSegmentIndex = 0
control.addTarget(self, action: #selector(segmentedControlChanged(_:)), for: .valueChanged)
control.setTitleTextAttributes([NSAttributedString.Key.font: UIFont(name: "Print Char 21", size: 14)!], for: .normal)
return control
}()
let memoryField: UITextField = {
let field = UITextField(frame: .zero)
field.translatesAutoresizingMaskIntoConstraints = false
field.font = UIFont(name: "Print Char 21", size: 14)
field.isUserInteractionEnabled = false
field.text = ""
field.textColor = .cyan
field.layer.borderWidth = 1.0
field.layer.borderColor = UIColor.cyan.cgColor
field.textAlignment = .center
field.widthAnchor.constraint(equalToConstant: 80).isActive = true
field.heightAnchor.constraint(equalToConstant: 40).isActive = true
return field
}()
let updateMemoryButton: UIButton = {
let button = UIButton(type: .custom)
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 12)
button.setTitle("Update", for: .normal)
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.orange.cgColor
button.addTarget(self, action: #selector(updateButtonPressed(_:)), for: .touchUpInside)
return button
}()
let resetMemoryButton: UIButton = {
let button = UIButton(type: .custom)
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 12)
button.setTitle("Reset", for: .normal)
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.orange.cgColor
return button
}()
let addToCheatsButton: UIButton = {
let button = UIButton(type: .custom)
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 12)
button.setTitle("Add to Cheats", for: .normal)
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.orange.cgColor
button.addTarget(self, action: #selector(addToCheatButtonPressed(_:)), for: .touchUpInside )
return button
}()
lazy var editFieldsStackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [memoryField, updateMemoryButton, resetMemoryButton, addToCheatsButton])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
stackView.spacing = 4
return stackView
}()
let keyboardModel: EmulatorKeyboardViewModel = {
let model = EmulatorKeyboardViewModel(keys:
[
[
AppleIIKey(label: "0", code: 0),
AppleIIKey(label: "1", code: 1),
AppleIIKey(label: "2", code: 2),
AppleIIKey(label: "3", code: 3)
],
[
AppleIIKey(label: "4", code: 4),
AppleIIKey(label: "5", code: 5),
AppleIIKey(label: "6", code: 6),
AppleIIKey(label: "7", code: 7)
],
[
AppleIIKey(label: "8", code: 8),
AppleIIKey(label: "9", code: 9),
AppleIIKey(label: "A", code: 10),
AppleIIKey(label: "B", code: 11)
],
[
AppleIIKey(label: "C", code: 12),
AppleIIKey(label: "D", code: 13),
AppleIIKey(label: "E", code: 14),
AppleIIKey(label: "F", code: 15)
]
]
)
model.isDraggable = false
return model
}()
lazy var keyboardView: EmulatorKeyboardView = {
let view = keyboardModel.createView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let titleLabel: UILabel = {
let label = UILabel(frame: .zero)
label.font = UIFont(name: "Print Char 21", size: 14)
label.text = "Memory Tools"
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .orange
label.heightAnchor.constraint(equalToConstant: 20).isActive = true
return label
}()
let cheatFinderNewSearchButton: UIButton = {
let button = UIButton(type: .custom)
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 12)
button.setTitle("New Search", for: .normal)
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.purple.cgColor
button.addTarget(self, action: #selector(cheatFinderNewSearchButtonPressed(_:)), for: .touchUpInside)
return button
}()
let cheatFinderContinueSearchButton: UIButton = {
let button = UIButton(type: .custom)
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 12)
button.setTitle("Continue Search", for: .normal)
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.red.cgColor
button.addTarget(self, action: #selector(cheatFinderContinueSearchButtonPressed(_:)), for: .touchUpInside)
return button
}()
lazy var cheatFinderInitialActionsStackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [cheatFinderNewSearchButton, cheatFinderContinueSearchButton, cheatFinderSearchLessButton, cheatFinderSearchGreaterButton, cheatFinderSearchEqualButton,
cheatFinderShowSavedButton])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
stackView.spacing = 4
return stackView
}()
let cheatFinderSearchLessButton: UIButton = {
let button = UIButton(type: .custom)
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 12)
button.setTitle("LT", for: .normal)
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.purple.cgColor
button.addTarget(self, action: #selector(cheatFinderSearchButtonPressed(_:)), for: .touchUpInside)
button.tag = 0
button.translatesAutoresizingMaskIntoConstraints = false
button.widthAnchor.constraint(equalToConstant: 30).isActive = true
return button
}()
let cheatFinderSearchGreaterButton: UIButton = {
let button = UIButton(type: .custom)
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 12)
button.setTitle("GT", for: .normal)
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.purple.cgColor
button.addTarget(self, action: #selector(cheatFinderSearchButtonPressed(_:)), for: .touchUpInside)
button.tag = 1
button.translatesAutoresizingMaskIntoConstraints = false
button.widthAnchor.constraint(equalToConstant: 30).isActive = true
return button
}()
let cheatFinderSearchEqualButton: UIButton = {
let button = UIButton(type: .custom)
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 12)
button.setTitle("EQ", for: .normal)
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.purple.cgColor
button.addTarget(self, action: #selector(cheatFinderSearchButtonPressed(_:)), for: .touchUpInside)
button.tag = 2
button.translatesAutoresizingMaskIntoConstraints = false
button.widthAnchor.constraint(equalToConstant: 30).isActive = true
return button
}()
lazy var cheatFinderShowSavedButton: ToggleButton = {
let button = ToggleButton()
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 12)
button.setTitle("Matched", for: .normal)
button.setTitle("Saved", for: .selected)
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.purple.cgColor
button.onTapped = { [weak self] wasSelected in
if wasSelected {
self?.cheatFinder.uiState = .showSaved
} else {
self?.cheatFinder.uiState = .didSearch
}
self?.cheatFinderUpdateUI()
}
button.tag = 3
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let findCodeButton: DebugMemoryButton = {
let button = DebugMemoryButton()
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 9)
button.setTitle("Find in Code >", for: .normal)
button.setTitle("Cancel", for: .selected)
button.setTitleColor(.red, for: .selected)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
// lazy var cheatFinderSearchStackView: UIStackView = {
// let stackView = UIStackView(arrangedSubviews: [cheatFinderSearchLessButton, cheatFinderSearchGreaterButton])
// stackView.translatesAutoresizingMaskIntoConstraints = false
// stackView.axis = .horizontal
// stackView.spacing = 4
// return stackView
// }()
let cheatFinderPromptLabel: UILabel = {
let label = UILabel(frame: .zero)
label.font = UIFont(name: "Print Char 21", size: 11)
label.text = "Start a new search to begin!"
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .red
label.textAlignment = .center
label.numberOfLines = 0
return label
}()
lazy var cheatFinderMatchesTableView: UITableView = {
let view = UITableView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .clear
view.dataSource = self
view.delegate = self
view.register(UITableViewCell.self, forCellReuseIdentifier: "CheatFinderMatchCell")
return view
}()
lazy var cheatFinderSavedTableView: UITableView = {
let view = UITableView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .clear
view.dataSource = self
view.delegate = self
view.register(UITableViewCell.self, forCellReuseIdentifier: "CheatFinderMatchCell")
return view
}()
init(cheatFinderManager: CheatFinderManager) {
self.cheatFinder = cheatFinderManager
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var emulatorScreenView: UIImageView = {
let screenView = UIImageView(frame: .zero)
screenView.translatesAutoresizingMaskIntoConstraints = false
return screenView
}()
@objc func cheatFinderNewSearchButtonPressed(_ sender: UIButton) {
if let memory = delegate?.memory {
cheatFinder.update(with: memory)
}
cheatFinder.uiState = .startedNewSearch
cheatFinderUpdateUI()
}
@objc func cheatFinderContinueSearchButtonPressed(_ sender: UIButton) {
cheatFinder.uiState = .isSearching
cheatFinderUpdateUI()
}
func cheatFinderSetupView() {
view.addSubview(cheatFinderInitialActionsStackView)
// view.addSubview(cheatFinderSearchStackView)
view.addSubview(cheatFinderPromptLabel)
view.addSubview(cheatFinderMatchesTableView)
view.addSubview(cheatFinderSavedTableView)
cheatFinderInitialActionsStackView.topAnchor.constraint(equalTo: segmentedControl.bottomAnchor, constant: 8).isActive = true
cheatFinderInitialActionsStackView.centerXAnchor.constraint(equalTo: segmentedControl.centerXAnchor).isActive = true
// cheatFinderInitialActionsStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16).isActive = true
// cheatFinderInitialActionsStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16).isActive = true
// cheatFinderSearchStackView.topAnchor.constraint(equalTo: cheatFinderInitialActionsStackView.bottomAnchor, constant: 8).isActive = true
// cheatFinderSearchStackView.centerXAnchor.constraint(equalTo: segmentedControl.centerXAnchor).isActive = true
cheatFinderPromptLabel.topAnchor.constraint(equalTo: cheatFinderInitialActionsStackView.bottomAnchor, constant: 16).isActive = true
cheatFinderPromptLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 48).isActive = true
cheatFinderPromptLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -48).isActive = true
cheatFinderMatchesTableView.topAnchor.constraint(equalTo: cheatFinderPromptLabel.bottomAnchor, constant: 4).isActive = true
cheatFinderMatchesTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24).isActive = true
cheatFinderMatchesTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24).isActive = true
cheatFinderMatchesTableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 8).isActive = true
cheatFinderSavedTableView.topAnchor.constraint(equalTo: cheatFinderMatchesTableView.topAnchor).isActive = true
cheatFinderSavedTableView.leadingAnchor.constraint(equalTo: cheatFinderMatchesTableView.leadingAnchor).isActive = true
cheatFinderSavedTableView.trailingAnchor.constraint(equalTo: cheatFinderMatchesTableView.trailingAnchor).isActive = true
cheatFinderSavedTableView.bottomAnchor.constraint(equalTo: cheatFinderMatchesTableView.bottomAnchor).isActive = true
[cheatFinderInitialActionsStackView, cheatFinderPromptLabel, cheatFinderMatchesTableView, cheatFinderSavedTableView].forEach{ $0.isHidden = true }
}
func cheatFinderHide() {
[cheatFinderInitialActionsStackView, cheatFinderPromptLabel, cheatFinderMatchesTableView, cheatFinderSearchLessButton, cheatFinderSearchGreaterButton, cheatFinderNewSearchButton, cheatFinderContinueSearchButton, cheatFinderSearchEqualButton, cheatFinderShowSavedButton, cheatFinderSavedTableView].forEach{ $0.isHidden = true }
}
func cheatFinderUpdateUI() {
cheatFinderHide()
switch cheatFinder.uiState {
case .initial:
[cheatFinderInitialActionsStackView, cheatFinderNewSearchButton, cheatFinderPromptLabel].forEach{ $0.isHidden = false }
cheatFinderPromptLabel.text = "Start a new search to begin!"
case .startedNewSearch:
[cheatFinderInitialActionsStackView, cheatFinderNewSearchButton,
cheatFinderSearchLessButton, cheatFinderSearchGreaterButton,
cheatFinderSearchEqualButton,
cheatFinderPromptLabel, cheatFinderShowSavedButton].forEach{ $0.isHidden = false }
cheatFinderPromptLabel.text = "New search started! Search to find matches..."
case .isSearching:
[cheatFinderInitialActionsStackView, cheatFinderNewSearchButton, cheatFinderSearchLessButton, cheatFinderSearchGreaterButton,
cheatFinderSearchEqualButton, cheatFinderPromptLabel, cheatFinderShowSavedButton].forEach{ $0.isHidden = false }
cheatFinderPromptLabel.text = "Search for values..."
case .didSearch:
[cheatFinderInitialActionsStackView, cheatFinderNewSearchButton,
cheatFinderSearchLessButton, cheatFinderSearchGreaterButton,
cheatFinderSearchEqualButton,
cheatFinderPromptLabel, cheatFinderMatchesTableView, cheatFinderShowSavedButton].forEach{ $0.isHidden = false }
cheatFinderPromptLabel.text = "Number of matches: \(cheatFinder.matchedMemoryAddresses.count)"
cheatFinderMatchesTableView.reloadData()
case .showSaved:
[cheatFinderInitialActionsStackView, cheatFinderNewSearchButton,
cheatFinderSearchLessButton, cheatFinderSearchGreaterButton,
cheatFinderSearchEqualButton,
cheatFinderPromptLabel, cheatFinderShowSavedButton, cheatFinderSavedTableView].forEach{ $0.isHidden = false }
cheatFinderSavedTableView.reloadData()
}
}
@objc func cheatFinderSearchButtonPressed(_ sender: UIButton) {
guard let memory = delegate?.memory else {
print("Cannot proceed cheat search without reference to memory!")
return
}
cheatFinder.comparisonMemory = [UInt8]()
for address in 0..<EmuMemoryModel.maxMemorySize {
cheatFinder.comparisonMemory.append(memory[address])
}
switch sender.tag {
case 0:
cheatFinder.findNewMatches(searchMode: CheatFinderManager.SearchMode.less)
case 1:
cheatFinder.findNewMatches(searchMode: CheatFinderManager.SearchMode.greater)
case 2:
cheatFinder.findNewMatches(searchMode: CheatFinderManager.SearchMode.same)
default:
break
}
cheatFinder.uiState = .didSearch
cheatFinderUpdateUI()
}
func setupView() {
view.addSubview(titleLabel)
view.addSubview(segmentedControl)
view.addSubview(editFieldsStackView)
view.addSubview(emulatorScreenView)
// view.addSubview(memoryField)
view.addSubview(keyboardView)
titleLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 16).isActive = true
titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
segmentedControl.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8).isActive = true
segmentedControl.centerXAnchor.constraint(equalTo: titleLabel.centerXAnchor).isActive = true
editFieldsStackView.topAnchor.constraint(equalTo: segmentedControl.bottomAnchor, constant: 8).isActive = true
// memoryField.widthAnchor.constraint(equalToConstant: 80).isActive = true
// memoryField.heightAnchor.constraint(equalToConstant: 40).isActive = true
editFieldsStackView.centerXAnchor.constraint(equalTo: keyboardView.centerXAnchor).isActive = true
keyboardView.topAnchor.constraint(equalTo: editFieldsStackView.bottomAnchor, constant: 8).isActive = true
// keyboardView.widthAnchor.constraint(equalToConstant: 200).isActive = true
keyboardView.heightAnchor.constraint(equalToConstant: 200).isActive = true
keyboardView.viewModel.delegate = self
emulatorScreenView.topAnchor.constraint(equalTo: segmentedControl.bottomAnchor, constant: 8).isActive = true
emulatorScreenView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 4.0).isActive = true
emulatorScreenView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -4.0).isActive = true
emulatorScreenView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -16).isActive = true
emulatorScreenView.isHidden = true
view.backgroundColor = UIColor.init(red: 0.14, green: 0.13, blue: 0.14, alpha: 1)
}
// Jump tab: normal constraints
private var keyboardViewCenterXConstraint: NSLayoutConstraint!
private var findCodeButtonLeadingConstraint: NSLayoutConstraint!
private var findCodeButtonCenterYConstraint: NSLayoutConstraint!
private var findInCodeTableViewLeadingConstraintOutOfView: NSLayoutConstraint!
private var findInCodeTableViewBottomConstraintOutOfView: NSLayoutConstraint!
var jumpTabNormalModeConstraints: [NSLayoutConstraint] {
[
keyboardViewCenterXConstraint,
findCodeButtonLeadingConstraint,
findCodeButtonCenterYConstraint,
findInCodeTableViewLeadingConstraintOutOfView,
findInCodeTableViewBottomConstraintOutOfView
]
}
// Jump tab: find in code constraints
private var keyboardViewLeadingConstraint: NSLayoutConstraint!
private var findCodeButtonBottomConstraint: NSLayoutConstraint!
private var findCodeButtonCenterXConstraint: NSLayoutConstraint!
private var findInCodeTableViewLeadingConstraint: NSLayoutConstraint!
private var findInCodeTableViewTrailingConstraint: NSLayoutConstraint!
private var findInCodeTableViewBottomConstraint: NSLayoutConstraint!
var jumpTabFindInCodeConstraints: [NSLayoutConstraint] {
[
keyboardViewLeadingConstraint,
findCodeButtonBottomConstraint,
findInCodeTableViewLeadingConstraint,
findInCodeTableViewTrailingConstraint,
findCodeButtonCenterXConstraint,
findInCodeTableViewBottomConstraint
]
}
// Jump tab: find in code table
lazy var findInCodeResultsTableView: UITableView = {
let view = UITableView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .clear
view.dataSource = self
view.delegate = self
view.register(UITableViewCell.self, forCellReuseIdentifier: "FindInCodeResultsCell")
return view
}()
func findInCodeSetupView() {
view.addSubview(findCodeButton)
view.addSubview(findInCodeResultsTableView)
// Find Code Button Normal config
keyboardViewCenterXConstraint = keyboardView.centerXAnchor.constraint(equalTo: titleLabel.centerXAnchor)
findCodeButtonLeadingConstraint = findCodeButton.leadingAnchor.constraint(equalTo: keyboardView.trailingAnchor, constant: 8)
findCodeButtonCenterYConstraint = findCodeButton.centerYAnchor.constraint(equalTo: keyboardView.centerYAnchor)
findInCodeTableViewLeadingConstraintOutOfView = findInCodeResultsTableView.leadingAnchor.constraint(equalTo: view.trailingAnchor, constant: 50)
findInCodeTableViewBottomConstraintOutOfView = findInCodeResultsTableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -8)
// Find Code Button Searching Config
keyboardViewLeadingConstraint = keyboardView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 8)
findCodeButtonBottomConstraint = findCodeButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 4)
findCodeButtonCenterXConstraint = findCodeButton.centerXAnchor.constraint(equalTo: findInCodeResultsTableView.centerXAnchor)
findInCodeTableViewBottomConstraint = findInCodeResultsTableView.bottomAnchor.constraint(equalTo: findCodeButton.topAnchor, constant: -4)
findInCodeResultsTableView.topAnchor.constraint(equalTo: segmentedControl.bottomAnchor, constant: 8).isActive = true
findInCodeTableViewLeadingConstraint = findInCodeResultsTableView.leadingAnchor.constraint(equalTo: keyboardView.trailingAnchor, constant: 8)
findInCodeTableViewTrailingConstraint = findInCodeResultsTableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -8)
NSLayoutConstraint.deactivate(jumpTabFindInCodeConstraints)
NSLayoutConstraint.activate(jumpTabNormalModeConstraints)
findCodeButton.onTapped = { isSelected in
self.updateKeyboardPosition(isFindingCode: isSelected)
self.updateMatchedInstructions()
}
}
private func updateMatchedInstructions() {
if let delegate = delegate,
let text = memoryField.text,
let address = getAddressFromText(text),
address < 0x10000 {
matchedInstructions = delegate.referencedMemoryAddresses[UInt16(address)] ?? [AddressedInstruction]()
findInCodeResultsTableView.reloadData()
}
}
private func updateKeyboardPosition(isFindingCode: Bool = false) {
let animator = UIViewPropertyAnimator(duration: 0.2, curve: .linear) {
if isFindingCode {
NSLayoutConstraint.deactivate(self.jumpTabNormalModeConstraints)
NSLayoutConstraint.activate(self.jumpTabFindInCodeConstraints)
} else {
NSLayoutConstraint.deactivate(self.jumpTabFindInCodeConstraints)
NSLayoutConstraint.activate(self.jumpTabNormalModeConstraints)
}
self.view.layoutIfNeeded()
}
animator.startAnimation()
}
override func viewDidLoad() {
super.viewDidLoad()
setupView()
cheatFinderSetupView()
findInCodeSetupView()
update()
}
func getAddressFromText(_ text: String?) -> UInt64? {
guard let text = text else {
return nil
}
let scanner = Scanner(string: text)
var address: UInt64 = 0
if scanner.scanHexInt64(&address) && address < EmuMemoryModel.maxMemorySize {
return address
}
return nil
}
func updateTextField(with keyCode: Int) {
guard var text = memoryField.text else {
print("no text in address field!")
return
}
text.append(String(format: "%1X",keyCode))
let charLimit: Int = {
switch mode {
case .jumpToAddress:
return 5
case .changeMemory:
return 2
default:
return 5
}
}()
if text.count > charLimit {
text.removeFirst()
}
if mode == .jumpToAddress, let address = getAddressFromText(text) {
delegate?.jump(to: Int(address))
if findCodeButton.isSelected {
updateMatchedInstructions()
}
}
memoryField.text = text
}
@objc func segmentedControlChanged(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
mode = .jumpToAddress
case 1:
mode = .changeMemory
case 2:
mode = .cheat
case 3:
mode = .screen
default:
mode = .jumpToAddress
}
update()
}
func update() {
cheatFinderHide()
emulatorScreenView.isHidden = true
findCodeButton.isHidden = true
findInCodeResultsTableView.isHidden = true
switch mode {
case .jumpToAddress:
memoryField.isHidden = false
memoryField.layer.borderColor = UIColor.cyan.cgColor
memoryField.textColor = .cyan
editFieldsStackView.isHidden = false
updateMemoryButton.isHidden = true
resetMemoryButton.isHidden = true
keyboardView.isHidden = false
findCodeButton.isHidden = false
findInCodeResultsTableView.isHidden = false
if let selectedAddress = delegate?.selectedAddress {
memoryField.text = String(format: "%04X", selectedAddress)
}
updateKeyboardPosition(isFindingCode: findCodeButton.isSelected)
case .changeMemory:
memoryField.isHidden = false
memoryField.layer.borderColor = UIColor.orange.cgColor
memoryField.textColor = .orange
editFieldsStackView.isHidden = false
updateMemoryButton.isHidden = false
resetMemoryButton.isHidden = false
keyboardView.isHidden = false
if let selectedAddress = delegate?.selectedAddress {
memoryField.text = delegate?.memoryHex(at: selectedAddress)
}
updateKeyboardPosition()
case .cheat:
memoryField.isHidden = true
editFieldsStackView.isHidden = true
keyboardView.isHidden = true
cheatFinderUpdateUI()
case .screen:
memoryField.isHidden = true
editFieldsStackView.isHidden = true
keyboardView.isHidden = true
emulatorScreenView.isHidden = false
updateEmulatorScreen()
}
}
@objc func updateButtonPressed(_ sender: UIButton) {
guard let selectedAddress = delegate?.selectedAddress,
let enteredText = memoryField.text,
let memory = UInt8(enteredText, radix: 16) else {
print("Could not get memory to update!")
return
}
delegate?.updateMemory(at: selectedAddress, with: memory)
}
@objc func addToCheatButtonPressed(_ sender: UIButton) {
guard let selectedAddress = delegate?.selectedAddress,
let enteredText = memoryField.text,
let memory = UInt8(enteredText, radix: 16) else {
print("Could not get memory to update!")
return
}
cheatFinder.savedMatches[selectedAddress] = (value: memory, enabled: true)
cheatFinderSavedTableView.reloadData()
}
@objc func cheatTableCellActionButtonPressed(_ sender: UIButton) {
let address = sender.tag
guard let matched = cheatFinder.matchedMemoryAddresses[address] else {
print("Could not find matched address: \(address)")
return
}
if cheatFinder.savedMatches[address] != nil {
cheatFinder.savedMatches.removeValue(forKey: address)
} else {
cheatFinder.savedMatches[address] = (value: matched, enabled: true)
}
cheatFinderSavedTableView.reloadData()
}
@objc func cheatSavedTableSwitchPressed(_ sender: UISwitch) {
let address = sender.tag
guard let matched = cheatFinder.savedMatches[address] else {
print("could not find saved entry!")
return
}
cheatFinder.savedMatches[address] = (value: matched.value, enabled: sender.isOn)
cheatFinderSavedTableView.reloadData()
}
}
extension DebugMemoryActionViewController: EmulatorKeyboardKeyPressedDelegate {
func keyDown(_ key: KeyCoded) {
print("DebugMemoryActionViewController keydown: \(key.keyLabel) ( \(key.keyCode) )")
}
func keyUp(_ key: KeyCoded) {
print("DebugMemoryActionViewController keyUp: \(key.keyLabel) ( \(key.keyCode) )")
updateTextField(with: key.keyCode)
}
func updateTransparency(toAlpha alpha: CGFloat) {
// no op
}
}
extension DebugMemoryActionViewController: DebugMemoryViewControllerDelegate {
func refreshActionController() {
update()
updateMatchedInstructions()
}
func updateEmulatorScreen() {
let emulatorView = EmuWrapper.getEmulatorView()
if let snapshot = emulatorView?.getSnapshot() {
let flipped = UIImage(cgImage: snapshot.cgImage!, scale: 1.0, orientation: .downMirrored)
emulatorScreenView.image = flipped
}
}
}
extension DebugMemoryActionViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == findInCodeResultsTableView {
return matchedInstructions.count
} else if tableView == cheatFinderSavedTableView {
return cheatFinder.savedMatches.keys.count
} else {
return cheatFinder.matchedMemoryAddresses.keys.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == findInCodeResultsTableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "FindInCodeResultsCell", for: indexPath)
let instruction = matchedInstructions[indexPath.row]
cell.textLabel?.text = instruction.description
cell.textLabel?.font = UIFont(name: "Print Char 21", size: 11)
cell.textLabel?.textColor = .yellow
cell.textLabel?.textAlignment = .center
return cell
} else if tableView == cheatFinderSavedTableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "CheatFinderMatchCell", for: indexPath)
let addresses = cheatFinder.savedMatches.keys.sorted()
let index = addresses.index(addresses.startIndex, offsetBy: indexPath.row)
let address = addresses[index]
let saved = cheatFinder.savedMatches[address]!
cell.textLabel?.text = String(format: "%04X: %02X",address,saved.value)
cell.textLabel?.font = UIFont(name: "Print Char 21", size: 14)
cell.textLabel?.textColor = .red
cell.textLabel?.textAlignment = .left
let enableSwitch = UISwitch(frame: .zero)
enableSwitch.isOn = saved.enabled
enableSwitch.addTarget(self, action: #selector(cheatSavedTableSwitchPressed(_:)), for: .valueChanged)
enableSwitch.tag = address
cell.accessoryView = enableSwitch
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "CheatFinderMatchCell", for: indexPath)
let addresses = cheatFinder.matchedMemoryAddresses.keys.sorted()
let index = addresses.index(addresses.startIndex, offsetBy: indexPath.row)
let address = addresses[index]
cell.textLabel?.text = String(format: "%04X: %02X",address,cheatFinder.matchedMemoryAddresses[address]!)
cell.textLabel?.font = UIFont(name: "Print Char 21", size: 14)
cell.textLabel?.textColor = .red
cell.textLabel?.textAlignment = .center
let isSaved = cheatFinder.savedMatches[address] != nil
let actionButton = isSaved ? UIButton(type: .custom) : UIButton(type: .contactAdd)
actionButton.tag = address
if isSaved {
actionButton.setTitle("Remove", for: .normal)
}
actionButton.addTarget(self, action: #selector(cheatTableCellActionButtonPressed(_:)), for: .touchUpInside)
cell.accessoryView = actionButton
return cell
}
}
}
extension DebugMemoryActionViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView == findInCodeResultsTableView {
let instruction = matchedInstructions[indexPath.row]
let address = instruction.address
delegate?.jump(to: Int(address))
} else {
let addresses = tableView == cheatFinderSavedTableView ? cheatFinder.savedMatches.keys.sorted() : cheatFinder.matchedMemoryAddresses.keys.sorted()
let index = addresses.index(addresses.startIndex, offsetBy: indexPath.row)
let address = addresses[index]
delegate?.jump(to: address)
tableView.deselectRow(at: indexPath, animated: true)
}
}
}

View File

@ -0,0 +1,519 @@
//
// DebugMemoryViewController.swift
// ActiveGS
//
// Created by Yoshi Sugawara on 1/17/21.
//
import Foundation
import UIKit
enum EmuMemoryMapSection: Int {
case zeroPage = 0
case processorStack
case getlnBuffer
case freeSpace
case dosProdosInterruptVectors
case textVideoPageAndPeripheralScreenholes
case textVideoPageTwoOrApplesoftProgramVariables
case freespace2
case highResGraphicsPage1
case highResGraphicsPage2
case applesoftStringData
case ioArea
case bankSwitched
case auxBanks
var range:Range<Int> {
switch self {
case .zeroPage: return 0..<0x100
case .processorStack: return 0x100..<0x200
case .getlnBuffer: return 0x200..<0x300
case .freeSpace: return 0x300..<0x3d0
case .dosProdosInterruptVectors: return 0x3d0..<0x400
case .textVideoPageAndPeripheralScreenholes: return 0x400..<0x800
case .textVideoPageTwoOrApplesoftProgramVariables: return 0x800..<0xc00
case .freespace2: return 0xc00..<0x2000
case .highResGraphicsPage1: return 0x2000..<0x4000
case .highResGraphicsPage2: return 0x4000..<0x6000
case .applesoftStringData: return 0x6000..<0xc000
case .ioArea: return 0xc000..<0xd000
case .bankSwitched: return 0xd000..<0x10000
case .auxBanks: return 0x10000..<0x30000
}
}
var numberOfItems: Int {
self.range.count
}
var title: String {
switch self {
case .zeroPage: return "Zero Page"
case .processorStack: return "6502 Processor Stack"
case .getlnBuffer: return "GETLN Line Input Buffer"
case .freeSpace: return "Free Space for Machine Language, Shape Table, etc."
case .dosProdosInterruptVectors: return "DOS, ProDOS, and Interrupt Vectors"
case .textVideoPageAndPeripheralScreenholes: return "Text Video Page and Peripheral Screenholes"
case .textVideoPageTwoOrApplesoftProgramVariables: return "Text Video Page 2 or Applesoft Program and Variables"
case .freespace2: return "Free Space for Machine Language, Shapes, etc."
case .highResGraphicsPage1: return "High Resolution Graphics Page 1"
case .highResGraphicsPage2: return "High Resolution Graphics Page 2"
case .applesoftStringData: return "Applesoft String Data"
case .ioArea: return "IO Area"
case .bankSwitched: return "Bank Switched"
case .auxBanks: return "Auxilliary Memory? 😅"
}
}
static func section(for address:Int) -> EmuMemoryMapSection {
if EmuMemoryMapSection.zeroPage.range.contains(address) {
return .zeroPage
} else if EmuMemoryMapSection.processorStack.range.contains(address) {
return .processorStack
} else if EmuMemoryMapSection.getlnBuffer.range.contains(address) {
return .getlnBuffer
} else if EmuMemoryMapSection.freeSpace.range.contains(address) {
return .freeSpace
} else if EmuMemoryMapSection.dosProdosInterruptVectors.range.contains(address) {
return .dosProdosInterruptVectors
} else if EmuMemoryMapSection.textVideoPageAndPeripheralScreenholes.range.contains(address) {
return .textVideoPageAndPeripheralScreenholes
} else if EmuMemoryMapSection.textVideoPageTwoOrApplesoftProgramVariables.range.contains(address) {
return .textVideoPageTwoOrApplesoftProgramVariables
} else if EmuMemoryMapSection.freespace2.range.contains(address) {
return .freespace2
} else if EmuMemoryMapSection.highResGraphicsPage1.range.contains(address) {
return .highResGraphicsPage1
} else if EmuMemoryMapSection.highResGraphicsPage2.range.contains(address) {
return .highResGraphicsPage2
} else if EmuMemoryMapSection.applesoftStringData.range.contains(address) {
return .applesoftStringData
} else if EmuMemoryMapSection.ioArea.range.contains(address) {
return .ioArea
} else if EmuMemoryMapSection.bankSwitched.range.contains(address) {
return .bankSwitched
} else if EmuMemoryMapSection.auxBanks.range.contains(address) {
return .auxBanks
} else {
return .auxBanks
}
}
}
protocol DebugMemoryViewControllerDelegate: class {
func refreshActionController()
func updateEmulatorScreen()
}
@objc class DebugMemoryViewController: UIViewController {
let memoryModel = EmuMemoryModel()
weak var delegate: DebugMemoryViewControllerDelegate?
// Landscape constraints
var actionControllerTopToViewTopConstraint: NSLayoutConstraint?
var actionControllerWidthConstraint: NSLayoutConstraint?
var actionControllerLeadingToTableViewTrailingConstraint: NSLayoutConstraint?
var tableViewToViewBottomConstraint: NSLayoutConstraint?
// Portrait constraints
var actionControllerLeadingToViewLeadingConstraint: NSLayoutConstraint?
var actionControllerTopToTableViewBottomConstraint: NSLayoutConstraint?
var actionControllerHeightConstraint: NSLayoutConstraint?
var tableViewTrailingToViewTrailingConstraint: NSLayoutConstraint?
var actionControllerBottomConstraint: NSLayoutConstraint?
var isShowingActionController = false
var actionControllerAnimatorProgress = 0.0
var animator: UIViewPropertyAnimator?
var cheatFinder = CheatFinderManager()
private var displayLink: CADisplayLink?
private var framesSince = 0
private var framesSinceUpdateScreen = 0
let titleLabel: UILabel = {
let label = UILabel(frame: .zero)
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont(name: "Print Char 21", size: 14)
label.textColor = .white
label.text = "Apple II Memory Debugger"
return label
}()
let dismissButton: UIButton = {
let button = UIButton(type: .custom)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("[X]", for: .normal)
button.addTarget(self, action: #selector(closeTapped(_:)), for: .touchUpInside)
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 12)
button.setTitleColor(.red, for: .normal)
return button
}()
let dataTableView: UITableView = {
let view = UITableView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .clear
view.separatorStyle = .none
return view
}()
let codeTableView: UITableView = {
let view = UITableView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .clear
view.separatorStyle = .none
return view
}()
let resumePauseEmulationButton: DebugPauseResumeButton = {
let button = DebugPauseResumeButton()
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let memoryViewModeControl: UISegmentedControl = {
let control = UISegmentedControl(items: ["Data","Code"])
control.translatesAutoresizingMaskIntoConstraints = false
control.tintColor = .green
control.setTitleTextAttributes([NSAttributedString.Key.font: UIFont(name: "Print Char 21", size: 14)!], for: .normal)
control.addTarget(self, action: #selector(memoryViewModeControlChanged(_:)), for: .valueChanged)
control.selectedSegmentIndex = 0
return control
}()
init() {
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupView() {
view.addSubview(titleLabel)
view.addSubview(memoryViewModeControl)
view.addSubview(dataTableView)
view.addSubview(codeTableView)
view.addSubview(dismissButton)
view.addSubview(resumePauseEmulationButton)
titleLabel.centerXAnchor.constraint(equalTo: dataTableView.centerXAnchor).isActive = true
titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16).isActive = true
memoryViewModeControl.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8).isActive = true
memoryViewModeControl.centerXAnchor.constraint(equalTo: dataTableView.centerXAnchor).isActive = true
dataTableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 8).isActive = true
// tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -8).isActive = true
dataTableView.topAnchor.constraint(equalTo: memoryViewModeControl.bottomAnchor, constant: 16).isActive = true
codeTableView.leadingAnchor.constraint(equalTo: dataTableView.leadingAnchor).isActive = true
codeTableView.trailingAnchor.constraint(equalTo: dataTableView.trailingAnchor).isActive = true
codeTableView.topAnchor.constraint(equalTo: dataTableView.topAnchor).isActive = true
codeTableView.bottomAnchor.constraint(equalTo: dataTableView.bottomAnchor).isActive = true
// tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
dismissButton.trailingAnchor.constraint(equalTo: dataTableView.trailingAnchor, constant: -8).isActive = true
dismissButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 8.0).isActive = true
resumePauseEmulationButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 8).isActive = true
resumePauseEmulationButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 8).isActive = true
view.backgroundColor = .black
}
func setupTableView() {
dataTableView.dataSource = self
dataTableView.delegate = self
dataTableView.register(DebugMemoryCell.self, forCellReuseIdentifier: DebugMemoryCell.identifier)
codeTableView.dataSource = self
codeTableView.delegate = self
codeTableView.register(DebugMemoryCell.self, forCellReuseIdentifier: DebugMemoryCell.identifier)
}
func setupActionController() {
let actionController = DebugMemoryActionViewController(cheatFinderManager: cheatFinder)
delegate = actionController
actionController.delegate = self
addChild(actionController)
actionController.didMove(toParent: self)
actionController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(actionController.view)
actionController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
actionControllerBottomConstraint = actionController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 250)
actionControllerBottomConstraint?.isActive = true
actionControllerHeightConstraint = actionController.view.heightAnchor.constraint(equalToConstant: 380)
actionControllerLeadingToViewLeadingConstraint = actionController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor)
actionControllerTopToTableViewBottomConstraint = actionController.view.topAnchor.constraint(equalTo: dataTableView.bottomAnchor)
tableViewTrailingToViewTrailingConstraint = dataTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8)
actionControllerWidthConstraint = actionController.view.widthAnchor.constraint(equalToConstant: 400)
actionControllerTopToViewTopConstraint = actionController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
actionControllerLeadingToTableViewTrailingConstraint = actionController.view.leadingAnchor.constraint(equalTo: dataTableView.trailingAnchor)
tableViewToViewBottomConstraint = dataTableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
actionController.view.addGestureRecognizer(pan)
}
func setupActionControllerOrientationConstraints(orientation: UIInterfaceOrientation? = nil) {
actionControllerLeadingToViewLeadingConstraint?.isActive = false
actionControllerTopToTableViewBottomConstraint?.isActive = false
actionControllerHeightConstraint?.isActive = false
actionControllerTopToViewTopConstraint?.isActive = false
actionControllerWidthConstraint?.isActive = false
actionControllerLeadingToTableViewTrailingConstraint?.isActive = false
tableViewToViewBottomConstraint?.isActive = false
tableViewTrailingToViewTrailingConstraint?.isActive = false
let isPortrait = orientation != nil ? orientation!.isPortrait : Orientation.isPortrait
if isPortrait {
actionControllerLeadingToViewLeadingConstraint?.isActive = true
actionControllerTopToTableViewBottomConstraint?.isActive = true
actionControllerHeightConstraint?.isActive = true
tableViewTrailingToViewTrailingConstraint?.isActive = true
} else {
actionControllerTopToViewTopConstraint?.isActive = true
actionControllerWidthConstraint?.isActive = true
actionControllerLeadingToTableViewTrailingConstraint?.isActive = true
tableViewToViewBottomConstraint?.isActive = true
actionControllerBottomConstraint?.constant = 0
}
}
func setupPauseResumeButton() {
resumePauseEmulationButton.onTapped = { selected in
if selected {
EmuWrapper.resume()
self.displayLink = CADisplayLink(target: self, selector: #selector(self.updateMemoryIfNeeded))
self.displayLink?.isPaused = false
self.displayLink?.add(to: RunLoop.main, forMode: .common)
} else {
EmuWrapper.pause()
self.displayLink?.isPaused = true
self.displayLink = nil
}
}
}
@objc func memoryViewModeControlChanged(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 1:
codeTableView.isHidden = false
dataTableView.isHidden = true
default:
codeTableView.isHidden = true
dataTableView.isHidden = false
}
}
@objc func updateMemoryIfNeeded() {
// maybe apply cheats here?
if framesSinceUpdateScreen > 3 {
delegate?.updateEmulatorScreen()
framesSinceUpdateScreen = 1
}
if framesSince > 30 {
memoryModel.refresh()
dataTableView.reloadData()
delegate?.refreshActionController()
framesSince = 1
}
framesSince += 1
framesSinceUpdateScreen += 1
}
func registerAppleIIFont() {
let fontUrl = Bundle.main.url(forResource: "PrintChar21", withExtension: "ttf")
CTFontManagerRegisterFontURLs([fontUrl] as CFArray, .persistent, true) { errors, done -> Bool in
if(done) {
print("Done installing custom font!")
}
print(errors as Array)
return true
}
}
override func viewDidLoad() {
super.viewDidLoad()
setupView()
setupActionController()
setupTableView()
setupPauseResumeButton()
memoryViewModeControlChanged(memoryViewModeControl)
// registerAppleIIFont()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
memoryModel.refresh()
setupActionControllerOrientationConstraints()
resumePauseEmulationButton.isSelected = false
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
dataTableView.reloadData()
delegate?.refreshActionController()
cheatFinder.start()
}
@objc func handlePan(_ recognizer: UIPanGestureRecognizer) {
switch recognizer.state {
case .began:
animator = UIViewPropertyAnimator(duration: 0.2, curve: .linear, animations: {
self.actionControllerBottomConstraint?.constant = self.isShowingActionController ? 250 : 0
self.view.layoutIfNeeded()
})
animator?.addCompletion { _ in
self.isShowingActionController = !self.isShowingActionController
}
animator?.pauseAnimation()
case .changed:
let translation = recognizer.translation(in: self.view)
var fraction = -translation.y / 300
if self.isShowingActionController { fraction *= -1 }
animator?.fractionComplete = fraction
case .ended:
animator?.continueAnimation(withTimingParameters: nil, durationFactor: 0)
default:
break
}
}
@objc func closeTapped(_ sender: UIButton) {
displayLink?.isPaused = true
displayLink = nil
dismiss(animated: true) {
EmuWrapper.resume()
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
setupActionControllerOrientationConstraints()
}
}
extension DebugMemoryViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == codeTableView {
return memoryModel.interpretedInstructions.count
} else {
let numItems = EmuMemoryMapSection(rawValue: section)!.numberOfItems
var numRows = numItems / memoryModel.numToDisplayPerCell
if numItems % memoryModel.numToDisplayPerCell > 0 {
numRows += 1
}
return numRows
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == codeTableView {
let cell = tableView.dequeueReusableCell(withIdentifier: DebugMemoryCell.identifier, for: indexPath) as! DebugMemoryCell
if indexPath.row >= memoryModel.interpretedInstructions.count {
return cell
}
let instruction = memoryModel.interpretedInstructions[indexPath.row]
let values = [
instruction.instruction.mnemonic.description,
instruction.instruction.addressingMode.description
]
cell.updateWith(delegate: self, offset: Int(instruction.address), hexMemoryValues: values)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: DebugMemoryCell.identifier, for: indexPath) as! DebugMemoryCell
let memoryVals = memoryModel.hexStrings(for: indexPath)
let offset = memoryModel.offset(for: indexPath)
cell.updateWith(delegate: self, offset: offset, hexMemoryValues: memoryVals)
return cell
}
}
func numberOfSections(in tableView: UITableView) -> Int {
if tableView == codeTableView {
return 1
} else {
return EmuMemoryMapSection.auxBanks.rawValue + 1
}
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if tableView == dataTableView {
return EmuMemoryMapSection.init(rawValue: section)!.title
}
return nil
}
}
extension DebugMemoryViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if tableView == dataTableView {
let title = self.tableView(tableView, titleForHeaderInSection: section)
let label = UILabel(frame: .zero)
label.text = title
label.font = UIFont(name: "Print Char 21", size: 12)
label.textColor = .cyan
label.translatesAutoresizingMaskIntoConstraints = false
let view = UIView(frame: .zero)
view.addSubview(label)
label.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8).isActive = true
view.backgroundColor = .black
view.layer.borderColor = UIColor.cyan.cgColor
view.layer.borderWidth = 1.0
view.heightAnchor.constraint(equalToConstant: 30).isActive = true
return view
}
return nil
}
}
extension DebugMemoryViewController: DebugMemoryCellDelegate {
func updateSelection(to address: Int) {
memoryModel.selectedAddress = address
self.dataTableView.reloadData()
// communicate selected address to action controller
delegate?.refreshActionController()
}
func isAddressSelected(_ address: Int) -> Bool {
if let selectedAddress = memoryModel.selectedAddress,
selectedAddress == address {
return true
}
return false
}
}
extension DebugMemoryViewController: DebugMemoryActionViewControllerDelegate {
func updateMemory(at address: Int, with memory:UInt8) {
memoryModel.setMemory(at: address, value: memory)
self.dataTableView.reloadData()
}
func jump(to address: Int) {
print("jumping to address: \(String(format: "%04X",address)) decimal: \(address)")
let indexPath = memoryModel.indexPath(for: address)
dataTableView.scrollToRow(at: indexPath, at: .middle, animated: true)
if let codeIndex = memoryModel.interpretedInstructions.firstIndex(where: { $0.address == address }) {
let indexPath = IndexPath(row: codeIndex, section: 0)
codeTableView.scrollToRow(at: indexPath, at: .middle, animated: true)
}
updateSelection(to: address)
}
func memoryHex(at address: Int) -> String {
return memoryModel.getMemoryHexString(at: address)
}
var memory: UnsafeMutablePointer<UInt8>? {
return memoryModel.memory
}
var selectedAddress: Int? {
return memoryModel.selectedAddress
}
var referencedMemoryAddresses: [UInt16: [AddressedInstruction]] {
return memoryModel.referencedAddresses
}
}

View File

@ -0,0 +1,48 @@
//
// DebugMemoryButton.swift
// ActiveGS
//
// Created by Yoshi Sugawara on 2/4/21.
//
import Foundation
class ToggleButton: UIButton {
var onTapped: ((Bool) -> Void)?
convenience init() {
self.init(type: .custom)
addTarget(self, action: #selector(tapped(_:)), for: .touchUpInside)
}
@objc func tapped(_ sender: UIButton) {
isSelected.toggle()
onTapped?(isSelected)
}
}
class DebugMemoryButton: ToggleButton {
override open var isSelected: Bool {
didSet {
backgroundColor = isSelected ? .white : .clear
}
}
}
class DebugPauseResumeButton: ToggleButton {
override open var isSelected: Bool {
didSet {
backgroundColor = isSelected ? .red : .clear
}
}
convenience init() {
self.init(type: .custom)
addTarget(self, action: #selector(tapped(_:)), for: .touchUpInside)
setTitle("RESUME", for: .normal)
setTitleColor(.green, for: .normal)
setTitle("PAUSE", for: .selected)
setTitleColor(.white, for: .selected)
titleLabel?.font = UIFont(name: "Print Char 21", size: 11)
}
}

View File

@ -0,0 +1,93 @@
//
// DebugMemoryCell.swift
// ActiveGS
//
// Created by Yoshi Sugawara on 2/4/21.
//
import Foundation
protocol DebugMemoryCellDelegate: class {
func updateSelection(to address: Int)
func isAddressSelected(_ address: Int) -> Bool
}
class DebugMemoryCell: UITableViewCell {
static let identifier = "DebugMemoryCell"
weak var delegate: DebugMemoryCellDelegate?
var updateSelection: ((Int) -> Void)?
var offset: Int?
lazy var stackView: UIStackView = {
let view = UIStackView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.axis = .horizontal
view.spacing = 8.0
view.alignment = .center
return view
}()
let addressLabel: UILabel = {
let label = UILabel(frame: .zero)
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont(name: "Print Char 21", size: 16)
label.textColor = .yellow
label.setContentHuggingPriority(.defaultHigh, for: .horizontal)
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(stackView)
stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0).isActive = true
stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 8.0).isActive = true
stackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8.0).isActive = true
stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 8.0).isActive = true
backgroundColor = .clear
selectionStyle = .none
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func updateWith(
delegate: DebugMemoryCellDelegate,
offset: Int,
hexMemoryValues: [String]
) {
self.delegate = delegate
self.offset = offset
stackView.arrangedSubviews.forEach{ $0.removeFromSuperview() }
addressLabel.text = String(format: "%05X:", offset)
stackView.addArrangedSubview(addressLabel)
stackView.setCustomSpacing(3, after: addressLabel)
for (index, hexValue) in hexMemoryValues.enumerated() {
let button = DebugMemoryButton()
let address = offset + index
button.setTitle(hexValue, for: .normal)
button.titleLabel?.font = UIFont(name: "Print Char 21", size: 16)
button.setTitleColor(.green, for: .normal)
button.tag = index
button.setTitleColor(.black, for: .selected)
button.onTapped = { didSelect in
if didSelect {
self.delegate?.updateSelection(to: address)
}
}
button.isSelected = self.delegate?.isAddressSelected(address) ?? false
// button.addTarget(self, action: #selector(didTapOnButton(_:)), for: .touchUpInside)
stackView.addArrangedSubview(button)
}
let spacer = UIView()
spacer.setContentHuggingPriority(.defaultLow, for: .horizontal)
stackView.addArrangedSubview(spacer)
}
@objc func didTapOnButton(_ button: UIButton) {
let memoryAddr = String(format:"%04X",(offset ?? 0) + button.tag)
print("tapped on button index \(button.tag), address: \(memoryAddr) ")
}
}

View File

@ -0,0 +1,888 @@
//
// EmulatorKeyboard.swift
// ActiveGS
//
// Created by Yoshi Sugawara on 7/30/20.
//
// TODO: shift key should change the label of the keys to uppercase (need callback mechanism?)
// pan gesture to outer edges of keyboard view for better dragging
// double tap modifier to toggle
// taller keys?
// alt key: add shift to left
import Foundation
import UIKit
class KeyboardButton: UIButton {
let key: KeyCoded
var toggleState = false
// MARK: - Functions
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
let newArea = CGRect(
x: self.bounds.origin.x - 5.0,
y: self.bounds.origin.y - 5.0,
width: self.bounds.size.width + 20.0,
height: self.bounds.size.height + 20.0
)
return newArea.contains(point)
}
override open var isHighlighted: Bool {
didSet {
// this is the problem - the isHighlighted sets to false for the touchesEnded callback
// need to look ask something else
// let shouldHighlight = isModifierToggle ? toggleState : isHighlighted
if !isHighlighted && toggleState {
// don't update the highlught
} else {
backgroundColor = isHighlighted ? .white : .clear
}
}
}
override open var isSelected: Bool {
didSet {
let shouldHighlight = key.isModifier ? toggleState : isSelected
backgroundColor = shouldHighlight ? .red : .clear
}
}
required init(key: KeyCoded) {
self.key = key
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
@objc protocol EmulatorKeyboardKeyPressedDelegate: class {
func keyDown(_ key: KeyCoded)
func keyUp(_ key: KeyCoded)
func updateTransparency(toAlpha alpha: CGFloat)
}
@objc protocol EmulatorKeyboardModifierPressedDelegate: class {
func modifierPressedWithKey(_ key: KeyCoded, enable: Bool)
func isModifierEnabled(key: KeyCoded) -> Bool
}
protocol EmulatorKeyboardViewDelegate: class {
func toggleAlternateKeys()
func refreshModifierStates()
}
class EmulatorKeyboardView: UIView {
var viewModel = EmulatorKeyboardViewModel(keys: [[KeyCoded]]()) {
didSet {
setupWithModel(viewModel)
}
}
var modifierButtons = Set<KeyboardButton>()
weak var delegate: EmulatorKeyboardViewDelegate?
private lazy var keyRowsStackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.distribution = .equalCentering
stackView.spacing = 12
return stackView
}()
private lazy var alternateKeyRowsStackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.distribution = .equalCentering
stackView.spacing = 12
stackView.isHidden = true
return stackView
}()
let dragMeView: UIView = {
let view = UIView(frame: .zero)
view.backgroundColor = .white
view.translatesAutoresizingMaskIntoConstraints = false
view.widthAnchor.constraint(equalToConstant: 80).isActive = true
view.heightAnchor.constraint(equalToConstant: 2).isActive = true
let outerView = UIView(frame: .zero)
outerView.backgroundColor = .clear
outerView.translatesAutoresizingMaskIntoConstraints = false
outerView.addSubview(view)
view.centerXAnchor.constraint(equalTo: outerView.centerXAnchor).isActive = true
view.centerYAnchor.constraint(equalTo: outerView.centerYAnchor).isActive = true
outerView.heightAnchor.constraint(equalToConstant: 20).isActive = true
outerView.widthAnchor.constraint(equalToConstant: 100).isActive = true
return outerView
}()
private var pressedKeyLabels = [String: UILabel]()
convenience init() {
self.init(frame: CGRect.zero)
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
backgroundColor = .clear
// layer.borderColor = UIColor.white.cgColor
// layer.borderWidth = 1.0
// layer.cornerRadius = 15.0
layoutMargins = UIEdgeInsets(top: 16, left: 4, bottom: 16, right: 4)
insetsLayoutMarginsFromSafeArea = false
addSubview(keyRowsStackView)
keyRowsStackView.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true
keyRowsStackView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor, constant: 4.0).isActive = true
keyRowsStackView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor, constant: -4.0).isActive = true
addSubview(alternateKeyRowsStackView)
alternateKeyRowsStackView.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true
alternateKeyRowsStackView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor, constant: 4.0).isActive = true
alternateKeyRowsStackView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor, constant: -4.0).isActive = true
addSubview(dragMeView)
dragMeView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
dragMeView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
@objc private func keyPressed(_ sender: KeyboardButton) {
if sender.key.keyCode == AppleKeyboardKey.KEY_SPECIAL_TOGGLE.rawValue {
return
}
if !sender.key.isModifier {
let label = UILabel(frame: .zero)
label.text = sender.titleLabel?.text
// hmm need to convert frame
let converted = sender.convert(sender.bounds, to: self)
print("sender frame: \(sender.frame), bounds: \(sender.bounds), convertedBounds = \(converted)")
var labelFrame = converted.offsetBy(dx: 0, dy: -60)
labelFrame = CGRect(x: labelFrame.origin.x, y: labelFrame.origin.y, width: labelFrame.width * 2, height: labelFrame.height * 2)
label.backgroundColor = .white
label.textColor = .black
label.frame = labelFrame
label.font = UIFont(name: "Print Char 21", size: 12)
label.textAlignment = .center
addSubview(label)
pressedKeyLabels[label.text ?? "😭"] = label
}
viewModel.keyPressed(sender.key)
}
@objc private func keyCancelled(_ sender: KeyboardButton) {
let title = sender.titleLabel?.text ?? "😭"
if let label = pressedKeyLabels[title] {
label.removeFromSuperview()
pressedKeyLabels.removeValue(forKey: title)
}
}
@objc private func keyReleased(_ sender: KeyboardButton) {
if sender.key.keyCode == AppleKeyboardKey.KEY_SPECIAL_TOGGLE.rawValue {
delegate?.toggleAlternateKeys()
return
}
let title = sender.titleLabel?.text ?? "😭"
if let label = pressedKeyLabels[title] {
label.removeFromSuperview()
pressedKeyLabels.removeValue(forKey: title)
}
let modifierState = viewModel.modifierKeyToggleStateForKey(sender.key)
sender.toggleState = modifierState
sender.isSelected = modifierState
viewModel.keyReleased(sender.key)
self.delegate?.refreshModifierStates()
}
func setupWithModel(_ model: EmulatorKeyboardViewModel) {
for row in model.keys {
let keysInRow = createKeyRow(keys: row)
keyRowsStackView.addArrangedSubview(keysInRow)
}
if let altKeys = model.alternateKeys {
for row in altKeys {
let keysInRow = createKeyRow(keys: row)
alternateKeyRowsStackView.addArrangedSubview(keysInRow)
}
}
if !model.isDraggable {
dragMeView.isHidden = true
}
}
func toggleKeysStackView() {
if viewModel.alternateKeys != nil {
keyRowsStackView.isHidden.toggle()
alternateKeyRowsStackView.isHidden.toggle()
refreshModifierStates()
}
}
func refreshModifierStates() {
modifierButtons.forEach{ button in
button.toggleState = viewModel.modifierKeyToggleStateForKey(button.key)
button.isSelected = button.toggleState
}
}
private func createKey(_ keyCoded: KeyCoded) -> UIButton {
let key = KeyboardButton(key: keyCoded)
if let imageName = keyCoded.keyImageName {
key.setImage(UIImage(systemName: imageName), for: .normal)
if let highlightedImageName = keyCoded.keyImageNameHighlighted {
key.setImage(UIImage(systemName: highlightedImageName), for: .highlighted)
key.setImage(UIImage(systemName: highlightedImageName), for: .selected)
}
} else {
key.setTitle(keyCoded.keyLabel, for: .normal)
key.titleLabel?.font = UIFont(name: "Print Char 21", size: 12)
key.setTitleColor(.white, for: .normal)
key.setTitleColor(.black, for: .highlighted)
}
key.translatesAutoresizingMaskIntoConstraints = false
key.widthAnchor.constraint(equalToConstant: (25 * CGFloat(keyCoded.keySize.rawValue))).isActive = true
key.heightAnchor.constraint(equalToConstant: 35).isActive = true
key.layer.borderWidth = 1.0
key.layer.borderColor = UIColor.white.cgColor
key.layer.cornerRadius = 6.0
key.addTarget(self, action: #selector(keyPressed(_:)), for: .touchDown)
key.addTarget(self, action: #selector(keyReleased(_:)), for: .touchUpInside)
key.addTarget(self, action: #selector(keyReleased(_:)), for: .touchUpOutside)
key.addTarget(self, action: #selector(keyCancelled(_:)), for: .touchCancel)
if keyCoded.isModifier {
modifierButtons.update(with: key)
}
return key
}
private func createKeyRow(keys: [KeyCoded]) -> UIStackView {
let subviews: [UIView] = keys.enumerated().map { index, keyCoded -> UIView in
if keyCoded is SpacerKey {
let spacer = UIView()
spacer.widthAnchor.constraint(equalToConstant: 25.0 * CGFloat(keyCoded.keySize.rawValue)).isActive = true
spacer.heightAnchor.constraint(equalToConstant: 25.0).isActive = true
return spacer
} else if let sliderKey = keyCoded as? SliderKey {
sliderKey.keyboardViewModel = self.viewModel
return sliderKey.createView()
}
return createKey(keyCoded)
}
let stack = UIStackView(arrangedSubviews: subviews)
stack.axis = .horizontal
stack.distribution = .fill
stack.spacing = 8
return stack
}
}
@objc enum KeySize: Int {
case standard = 1, wide, wider
}
// represents a key that has an underlying code that gets sent to the emulator
@objc protocol KeyCoded: AnyObject {
var keyLabel: String { get }
var keyImageName: String? { get }
var keyImageNameHighlighted: String? { get }
var keyCode: Int { get }
var keySize: KeySize { get }
var isModifier: Bool { get }
}
protocol KeyRowsDataSource {
func keyForPositionAt(_ position: KeyPosition) -> KeyCoded?
}
@objc class AppleIIKey: NSObject, KeyCoded {
let keyLabel: String
var keyImageName: String?
var keyImageNameHighlighted: String?
let keyCode: Int
let keySize: KeySize
let isModifier: Bool
override var description: String {
return String(format: "\(keyLabel) (%02X)", keyCode)
}
init(label: String, code: Int, keySize: KeySize = .standard, isModifier: Bool = false, imageName: String? = nil, imageNameHighlighted: String? = nil) {
self.keyLabel = label
self.keyCode = code
self.keySize = keySize
self.isModifier = isModifier
self.keyImageName = imageName
self.keyImageNameHighlighted = imageNameHighlighted
}
}
class SpacerKey: KeyCoded {
let keyLabel = ""
let keyCode = 0
let keySize: KeySize
let isModifier = false
let keyImageName: String? = nil
let keyImageNameHighlighted: String? = nil
init(keySize: KeySize = .standard) {
self.keySize = keySize
}
}
class SliderKey: KeyCoded {
let keyLabel = ""
let keyCode = 0
let keySize: KeySize
let isModifier = false
let keyImageName: String? = nil
let keyImageNameHighlighted: String? = nil
weak var keyboardViewModel: EmulatorKeyboardViewModel?
init(keySize: KeySize = .standard) {
self.keySize = keySize
}
func createView() -> UIView {
let slider = UISlider(frame: .zero)
slider.minimumValue = 0.1
slider.maximumValue = 1.0
slider.addTarget(self, action: #selector(adjustKeyboardAlpha(_:)), for: .valueChanged)
slider.value = 1.0
return slider
}
@objc func adjustKeyboardAlpha(_ sender: UISlider) {
keyboardViewModel?.delegate?.updateTransparency(toAlpha: CGFloat(sender.value))
}
}
struct KeyPosition {
let row: Int
let column: Int
}
@objc class EmulatorKeyboardViewModel: NSObject, KeyRowsDataSource {
var keys = [[KeyCoded]]()
var alternateKeys: [[KeyCoded]]?
var modifiers: [Int16: KeyCoded]?
var isDraggable = true
@objc weak var delegate: EmulatorKeyboardKeyPressedDelegate?
@objc weak var modifierDelegate: EmulatorKeyboardModifierPressedDelegate?
init(keys: [[KeyCoded]], alternateKeys: [[KeyCoded]]? = nil) {
self.keys = keys
self.alternateKeys = alternateKeys
}
func createView() -> EmulatorKeyboardView {
let view = EmulatorKeyboardView()
view.viewModel = self
return view
}
func keyForPositionAt(_ position: KeyPosition) -> KeyCoded? {
guard position.row < keys.count else {
return nil
}
let row = keys[position.row]
guard position.column < row.count else {
return nil
}
return row[position.column]
}
func modifierKeyToggleStateForKey(_ key: KeyCoded) -> Bool {
return key.isModifier && (modifierDelegate?.isModifierEnabled(key: key) ?? false)
}
func keyPressed(_ key: KeyCoded) {
if key.isModifier {
let isPressed = modifierDelegate?.isModifierEnabled(key: key) ?? false
modifierDelegate?.modifierPressedWithKey(key, enable: !isPressed)
return
}
delegate?.keyDown(key)
}
func keyReleased(_ key: KeyCoded) {
if key.isModifier {
return
}
delegate?.keyUp(key)
}
// KeyCoded can support a shifted key label
// view can update with shifted key labels?
// cluster can support alternate keys and view can swap them out?
}
@objc class EmulatorKeyboardController: UIViewController {
@objc lazy var leftKeyboardView: EmulatorKeyboardView = {
let view = leftKeyboardModel.createView()
view.delegate = self
return view
}()
@objc lazy var rightKeyboardView: EmulatorKeyboardView = {
let view = rightKeyboardModel.createView()
view.delegate = self
return view
}()
var keyboardConstraints = [NSLayoutConstraint]()
// Global states for all the keyboards
// uses bitwise masks for the state of shift keys, control, open-apple keys, etc
@objc var modifierState: Int16 = 0
@objc let leftKeyboardModel = EmulatorKeyboardViewModel(
keys:
[
[
AppleIIKey(label: "esc", code: AppleKeyboardKey.KEY_ESC.rawValue),
AppleIIKey(label: "tab", code: AppleKeyboardKey.KEY_TAB.rawValue, keySize: .wide),
SpacerKey(),
AppleIIKey(label: "CTRL", code: AppleKeyboardKey.KEY_CTRL.rawValue,
keySize: .standard, isModifier: true, imageName: "control")
],
[
AppleIIKey(label: "q", code: AppleKeyboardKey.KEY_Q.rawValue),
AppleIIKey(label: "w", code: AppleKeyboardKey.KEY_W.rawValue),
AppleIIKey(label: "e", code: AppleKeyboardKey.KEY_E.rawValue),
AppleIIKey(label: "r", code: AppleKeyboardKey.KEY_R.rawValue),
AppleIIKey(label: "t", code: AppleKeyboardKey.KEY_T.rawValue)
],
[
AppleIIKey(label: "a", code: AppleKeyboardKey.KEY_A.rawValue),
AppleIIKey(label: "s", code: AppleKeyboardKey.KEY_S.rawValue),
AppleIIKey(label: "d", code: AppleKeyboardKey.KEY_D.rawValue),
AppleIIKey(label: "f", code: AppleKeyboardKey.KEY_F.rawValue),
AppleIIKey(label: "g", code: AppleKeyboardKey.KEY_G.rawValue)
],
[
AppleIIKey(label: "z", code: AppleKeyboardKey.KEY_Z.rawValue),
AppleIIKey(label: "x", code: AppleKeyboardKey.KEY_X.rawValue),
AppleIIKey(label: "c", code: AppleKeyboardKey.KEY_C.rawValue),
AppleIIKey(label: "v", code: AppleKeyboardKey.KEY_V.rawValue),
AppleIIKey(label: "b", code: AppleKeyboardKey.KEY_B.rawValue)
],
[
AppleIIKey(label: "SHIFT", code: AppleKeyboardKey.KEY_SHIFT.rawValue,
keySize: .standard, isModifier: true, imageName: "shift", imageNameHighlighted: "shift.fill"),
AppleIIKey(label: "123", code: AppleKeyboardKey.KEY_SPECIAL_TOGGLE.rawValue, keySize: .standard, imageName: "textformat.123"),
AppleIIKey(label: "\(UnicodeScalar(0xe081)!)", code: AppleKeyboardKey.KEY_APPLE.rawValue,
keySize: .standard, isModifier: true),
AppleIIKey(label: "SPACE", code: AppleKeyboardKey.KEY_SPACE.rawValue, keySize: .wide)
]
],
alternateKeys:
[
[
SliderKey(keySize: .standard)
],
[
AppleIIKey(label: "1", code: AppleKeyboardKey.KEY_1.rawValue),
AppleIIKey(label: "2", code: AppleKeyboardKey.KEY_2.rawValue),
AppleIIKey(label: "3", code: AppleKeyboardKey.KEY_3.rawValue),
AppleIIKey(label: "4", code: AppleKeyboardKey.KEY_4.rawValue),
AppleIIKey(label: "5", code: AppleKeyboardKey.KEY_5.rawValue),
],
[
AppleIIKey(label: "-", code: AppleKeyboardKey.KEY_MINUS.rawValue),
AppleIIKey(label: "=", code: AppleKeyboardKey.KEY_EQUALS.rawValue),
AppleIIKey(label: "/", code: AppleKeyboardKey.KEY_FSLASH.rawValue),
AppleIIKey(label: "[", code: AppleKeyboardKey.KEY_LEFT_BRACKET.rawValue),
AppleIIKey(label: "]", code: AppleKeyboardKey.KEY_RIGHT_BRACKET.rawValue),
],
[
AppleIIKey(label: ";", code: AppleKeyboardKey.KEY_SEMICOLON.rawValue),
AppleIIKey(label: "~", code: AppleKeyboardKey.KEY_TILDE.rawValue)
],
[
AppleIIKey(label: "SHIFT", code: AppleKeyboardKey.KEY_SHIFT.rawValue,
keySize: .standard, isModifier: true, imageName: "shift", imageNameHighlighted: "shift.fill"),
AppleIIKey(label: "ABC", code: AppleKeyboardKey.KEY_SPECIAL_TOGGLE.rawValue, keySize: .standard, imageName: "textformat.abc"),
AppleIIKey(label: "\(UnicodeScalar(0xe081)!)", code: AppleKeyboardKey.KEY_APPLE.rawValue,
keySize: .standard, isModifier: true),
AppleIIKey(label: "SPACE", code: AppleKeyboardKey.KEY_SPACE.rawValue, keySize: .wide)
]
]
)
@objc let rightKeyboardModel = EmulatorKeyboardViewModel(
keys:
[
[
SpacerKey(),
SpacerKey(),
AppleIIKey(label: "\(UnicodeScalar(0xe144)!)", code: AppleKeyboardKey.KEY_SPECIAL_DEBUGGER.rawValue),
AppleIIKey(label: "RESET", code: AppleKeyboardKey.KEY_RESET.rawValue, keySize: .wide)
],
[
AppleIIKey(label: "y", code: AppleKeyboardKey.KEY_Y.rawValue),
AppleIIKey(label: "u", code: AppleKeyboardKey.KEY_U.rawValue),
AppleIIKey(label: "i", code: AppleKeyboardKey.KEY_I.rawValue),
AppleIIKey(label: "o", code: AppleKeyboardKey.KEY_O.rawValue),
AppleIIKey(label: "p", code: AppleKeyboardKey.KEY_P.rawValue)
],
[
AppleIIKey(label: "h", code: AppleKeyboardKey.KEY_H.rawValue),
AppleIIKey(label: "j", code: AppleKeyboardKey.KEY_J.rawValue),
AppleIIKey(label: "k", code: AppleKeyboardKey.KEY_K.rawValue),
AppleIIKey(label: "l", code: AppleKeyboardKey.KEY_L.rawValue),
AppleIIKey(label: "'", code: AppleKeyboardKey.KEY_SQUOTE.rawValue)
],
[
AppleIIKey(label: "n", code: AppleKeyboardKey.KEY_N.rawValue),
AppleIIKey(label: "m", code: AppleKeyboardKey.KEY_M.rawValue),
AppleIIKey(label: ",", code: AppleKeyboardKey.KEY_COMMA.rawValue),
AppleIIKey(label: ".", code: AppleKeyboardKey.KEY_PERIOD.rawValue),
AppleIIKey(label: "DELETE", code: AppleKeyboardKey.KEY_DELETE.rawValue, imageName: "delete.left", imageNameHighlighted: "delete.left.fill")
],
[
AppleIIKey(label: "\(UnicodeScalar(0xe080)!)", code: AppleKeyboardKey.KEY_OPTION.rawValue,
keySize: .standard, isModifier: true),
AppleIIKey(label: "RETURN", code: AppleKeyboardKey.KEY_RETURN.rawValue, keySize: .wide)
]
],
alternateKeys:
[
[
AppleIIKey(label: "6", code: AppleKeyboardKey.KEY_6.rawValue),
AppleIIKey(label: "7", code: AppleKeyboardKey.KEY_7.rawValue),
AppleIIKey(label: "8", code: AppleKeyboardKey.KEY_8.rawValue),
AppleIIKey(label: "9", code: AppleKeyboardKey.KEY_9.rawValue),
AppleIIKey(label: "0", code: AppleKeyboardKey.KEY_0.rawValue),
],
[
SpacerKey(),
SpacerKey(),
AppleIIKey(label: "\(UnicodeScalar(0xe08b)!)", code: AppleKeyboardKey.KEY_UP_CURSOR.rawValue),
SpacerKey(),
SpacerKey()
],
[
SpacerKey(),
AppleIIKey(label: "\(UnicodeScalar(0xe088)!)", code: AppleKeyboardKey.KEY_LEFT_CURSOR.rawValue),
AppleIIKey(label: "\(UnicodeScalar(0xe08a)!)", code: AppleKeyboardKey.KEY_DOWN_CURSOR.rawValue),
AppleIIKey(label: "\(UnicodeScalar(0xe095)!)", code: AppleKeyboardKey.KEY_RIGHT_CURSOR.rawValue),
SpacerKey()
],
[
AppleIIKey(label: "SPACE", code: AppleKeyboardKey.KEY_SPACE.rawValue, keySize: .wide),
AppleIIKey(label: "SHIFT", code: AppleKeyboardKey.KEY_SHIFT.rawValue,
keySize: .standard, isModifier: true, imageName: "shift", imageNameHighlighted: "shift.fill"),
AppleIIKey(label: "DELETE", code: AppleKeyboardKey.KEY_DELETE.rawValue, imageName: "delete.left", imageNameHighlighted: "delete.left.fill")
],
[
AppleIIKey(label: "\(UnicodeScalar(0xe080)!)", code: AppleKeyboardKey.KEY_OPTION.rawValue,
keySize: .standard, isModifier: true),
AppleIIKey(label: "RETURN", code: AppleKeyboardKey.KEY_RETURN.rawValue, keySize: .wide)
]
]
)
@objc let leftKeyboardModel2 = EmulatorKeyboardViewModel(
keys:
[
[
AppleIIKey(label: "esc", code: AppleKeyboardKey.KEY_ESC.rawValue),
AppleIIKey(label: "tab", code: AppleKeyboardKey.KEY_TAB.rawValue),
AppleIIKey(label: "CTRL", code: AppleKeyboardKey.KEY_CTRL.rawValue,
keySize: .standard, isModifier: true, imageName: "control")
],
[
AppleIIKey(label: "q", code: AppleKeyboardKey.KEY_Q.rawValue),
AppleIIKey(label: "a", code: AppleKeyboardKey.KEY_A.rawValue),
AppleIIKey(label: "z", code: AppleKeyboardKey.KEY_Z.rawValue),
],
[
AppleIIKey(label: "w", code: AppleKeyboardKey.KEY_W.rawValue),
AppleIIKey(label: "s", code: AppleKeyboardKey.KEY_S.rawValue),
AppleIIKey(label: "x", code: AppleKeyboardKey.KEY_X.rawValue),
],
[
AppleIIKey(label: "e", code: AppleKeyboardKey.KEY_E.rawValue),
AppleIIKey(label: "d", code: AppleKeyboardKey.KEY_D.rawValue),
AppleIIKey(label: "c", code: AppleKeyboardKey.KEY_C.rawValue)
],
[
AppleIIKey(label: "r", code: AppleKeyboardKey.KEY_R.rawValue),
AppleIIKey(label: "f", code: AppleKeyboardKey.KEY_F.rawValue),
AppleIIKey(label: "v", code: AppleKeyboardKey.KEY_V.rawValue),
],
[
AppleIIKey(label: "t", code: AppleKeyboardKey.KEY_T.rawValue),
AppleIIKey(label: "g", code: AppleKeyboardKey.KEY_G.rawValue),
AppleIIKey(label: "b", code: AppleKeyboardKey.KEY_B.rawValue)
],
[
AppleIIKey(label: "SHIFT", code: AppleKeyboardKey.KEY_SHIFT.rawValue,
keySize: .wide, isModifier: true, imageName: "shift", imageNameHighlighted: "shift.fill"),
AppleIIKey(label: "123", code: AppleKeyboardKey.KEY_SPECIAL_TOGGLE.rawValue, keySize: .standard, imageName: "textformat.123")
],
[
AppleIIKey(label: "SPACE", code: AppleKeyboardKey.KEY_SPACE.rawValue, keySize: .wide),
AppleIIKey(label: "", code: AppleKeyboardKey.KEY_APPLE.rawValue,
keySize: .standard, isModifier: true)
]
],
alternateKeys:
[
[
AppleIIKey(label: "esc", code: AppleKeyboardKey.KEY_ESC.rawValue),
AppleIIKey(label: "tab", code: AppleKeyboardKey.KEY_TAB.rawValue),
AppleIIKey(label: "CTRL", code: AppleKeyboardKey.KEY_CTRL.rawValue,
keySize: .standard, isModifier: true, imageName: "control")
],
[
AppleIIKey(label: "1", code: AppleKeyboardKey.KEY_1.rawValue),
AppleIIKey(label: "-", code: AppleKeyboardKey.KEY_MINUS.rawValue),
AppleIIKey(label: "]", code: AppleKeyboardKey.KEY_RIGHT_BRACKET.rawValue)
],
[
AppleIIKey(label: "2", code: AppleKeyboardKey.KEY_2.rawValue),
AppleIIKey(label: "=", code: AppleKeyboardKey.KEY_EQUALS.rawValue),
AppleIIKey(label: "~", code: AppleKeyboardKey.KEY_TILDE.rawValue)
],
[
AppleIIKey(label: "3", code: AppleKeyboardKey.KEY_3.rawValue),
AppleIIKey(label: ";", code: AppleKeyboardKey.KEY_SEMICOLON.rawValue),
],
[
AppleIIKey(label: "4", code: AppleKeyboardKey.KEY_4.rawValue),
AppleIIKey(label: "/", code: AppleKeyboardKey.KEY_FSLASH.rawValue)
],
[
AppleIIKey(label: "5", code: AppleKeyboardKey.KEY_5.rawValue),
AppleIIKey(label: "[", code: AppleKeyboardKey.KEY_LEFT_BRACKET.rawValue)
],
[
AppleIIKey(label: "SHIFT", code: AppleKeyboardKey.KEY_SHIFT.rawValue,
keySize: .wide, isModifier: true, imageName: "shift", imageNameHighlighted: "shift.fill"),
AppleIIKey(label: "ABC", code: AppleKeyboardKey.KEY_SPECIAL_TOGGLE.rawValue, keySize: .wide, imageName: "textformat.abc"),
],
[
AppleIIKey(label: "SPC", code: AppleKeyboardKey.KEY_SPACE.rawValue),
AppleIIKey(label: "OPT", code: AppleKeyboardKey.KEY_OPTION.rawValue,
keySize: .standard, isModifier: true)
]
]
)
@objc let rightKeyboardModel2 = EmulatorKeyboardViewModel(
keys:
[
[
SpacerKey(),
SpacerKey(),
AppleIIKey(label: "RESET", code: AppleKeyboardKey.KEY_RESET.rawValue)
],
[
AppleIIKey(label: "y", code: AppleKeyboardKey.KEY_Y.rawValue),
AppleIIKey(label: "h", code: AppleKeyboardKey.KEY_H.rawValue),
AppleIIKey(label: "n", code: AppleKeyboardKey.KEY_N.rawValue),
],
[
AppleIIKey(label: "u", code: AppleKeyboardKey.KEY_U.rawValue),
AppleIIKey(label: "j", code: AppleKeyboardKey.KEY_J.rawValue),
AppleIIKey(label: "m", code: AppleKeyboardKey.KEY_M.rawValue),
],
[
AppleIIKey(label: "i", code: AppleKeyboardKey.KEY_I.rawValue),
AppleIIKey(label: "k", code: AppleKeyboardKey.KEY_K.rawValue),
AppleIIKey(label: ",", code: AppleKeyboardKey.KEY_COMMA.rawValue)
],
[
AppleIIKey(label: "o", code: AppleKeyboardKey.KEY_O.rawValue),
AppleIIKey(label: "l", code: AppleKeyboardKey.KEY_L.rawValue),
AppleIIKey(label: ".", code: AppleKeyboardKey.KEY_PERIOD.rawValue),
],
[
AppleIIKey(label: "p", code: AppleKeyboardKey.KEY_P.rawValue),
AppleIIKey(label: ";", code: AppleKeyboardKey.KEY_SEMICOLON.rawValue),
AppleIIKey(label: "/", code: AppleKeyboardKey.KEY_FSLASH.rawValue)
],
[
AppleIIKey(label: "]", code: AppleKeyboardKey.KEY_RIGHT_BRACKET.rawValue),
AppleIIKey(label: "'", code: AppleKeyboardKey.KEY_SQUOTE.rawValue),
],
[
AppleIIKey(label: "RETURN", code: AppleKeyboardKey.KEY_RETURN.rawValue, keySize: .wide),
AppleIIKey(label: "DELETE", code: AppleKeyboardKey.KEY_DELETE.rawValue, imageName: "delete.left", imageNameHighlighted: "delete.left.fill")
]
],
alternateKeys:
[
[
AppleIIKey(label: "6", code: AppleKeyboardKey.KEY_6.rawValue),
SpacerKey(),
SpacerKey()
],
[
AppleIIKey(label: "7", code: AppleKeyboardKey.KEY_7.rawValue),
SpacerKey(),
SpacerKey()
],
[
AppleIIKey(label: "8", code: AppleKeyboardKey.KEY_8.rawValue),
SpacerKey(),
SpacerKey()
],
[
AppleIIKey(label: "9", code: AppleKeyboardKey.KEY_9.rawValue),
SpacerKey(),
SpacerKey()
],
[
AppleIIKey(label: "0", code: AppleKeyboardKey.KEY_0.rawValue),
AppleIIKey(label: "", code: AppleKeyboardKey.KEY_UP_CURSOR.rawValue),
SpacerKey()
],
[
AppleIIKey(label: "", code: AppleKeyboardKey.KEY_LEFT_CURSOR.rawValue),
AppleIIKey(label: "", code: AppleKeyboardKey.KEY_DOWN_CURSOR.rawValue),
AppleIIKey(label: "", code: AppleKeyboardKey.KEY_RIGHT_CURSOR.rawValue)
],
[
AppleIIKey(label: "SHIFT", code: AppleKeyboardKey.KEY_SHIFT.rawValue,
keySize: .standard, isModifier: true, imageName: "shift", imageNameHighlighted: "shift.fill"),
AppleIIKey(label: "DELETE", code: AppleKeyboardKey.KEY_DELETE.rawValue, imageName: "delete.left", imageNameHighlighted: "delete.left.fill")
],
[
AppleIIKey(label: "RETURN", code: AppleKeyboardKey.KEY_RETURN.rawValue, keySize: .standard)
]
]
)
init() {
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
setupView()
// setupViewFrames()
// setupKeyModels()
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(draggedView(_:)))
leftKeyboardView.dragMeView.isUserInteractionEnabled = true
leftKeyboardView.dragMeView.addGestureRecognizer(panGesture)
let panGestureRightKeyboard = UIPanGestureRecognizer(target: self, action: #selector(draggedView(_:)))
rightKeyboardView.dragMeView.isUserInteractionEnabled = true
rightKeyboardView.dragMeView.addGestureRecognizer(panGestureRightKeyboard)
}
func setupView() {
NSLayoutConstraint.deactivate(keyboardConstraints)
keyboardConstraints.removeAll()
leftKeyboardView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(leftKeyboardView)
leftKeyboardView.heightAnchor.constraint(equalToConstant: 270).isActive = true
leftKeyboardView.widthAnchor.constraint(equalToConstant: 180).isActive = true
keyboardConstraints.append(contentsOf: [
leftKeyboardView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
leftKeyboardView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
rightKeyboardView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(rightKeyboardView)
keyboardConstraints.append(contentsOf: [
rightKeyboardView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
rightKeyboardView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
rightKeyboardView.heightAnchor.constraint(equalToConstant: 270).isActive = true
rightKeyboardView.widthAnchor.constraint(equalToConstant: 180).isActive = true
NSLayoutConstraint.activate(keyboardConstraints)
}
func setupViewFrames() {
// initial placement on the bottom corners
// since we don't know the frame of this view yet until layout time,
// assume it's taking the full screen
let screenFrame = UIScreen.main.bounds
let keyboardHeight: CGFloat = 250.0
let keyboardWidth: CGFloat = 180.0
let bottomLeftFrame = CGRect(
x: 0,
y: screenFrame.size.height - 40 - keyboardHeight - 20,
width: keyboardWidth, height: keyboardHeight)
let bottomRightFrame = CGRect(
x: screenFrame.size.width - 20 - keyboardWidth,
y:screenFrame.size.height - 40 - keyboardHeight - 20,
width: keyboardWidth, height: keyboardHeight
)
view.addSubview(leftKeyboardView)
view.addSubview(rightKeyboardView)
leftKeyboardView.frame = bottomLeftFrame
rightKeyboardView.frame = bottomRightFrame
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
// get relative positions of frames to size
// for v in [leftKeyboardView, rightKeyboardView] {
// let xPercent = v.frame.origin.x / view.frame.size.width
// let yPercent = v.frame.origin.y / view.frame.size.height
// var newX = size.width * xPercent
// var newY = size.height * yPercent
// // mmm need to check if the views fit within the frame and adjust
// if newX + v.bounds.size.width > size.width {
// newX = size.width - v.bounds.size.width
// } else if newX < 0 {
// newX = 0
// }
// if newY + v.bounds.size.height > size.height {
// newY = size.height - v.bounds.size.height
// }
// let newFrame = CGRect(x: newX, y: newY, width: v.bounds.size.width, height: v.bounds.size.height)
// v.frame = newFrame
// }
}
func setupKeyModels() {
leftKeyboardView.setupWithModel(leftKeyboardModel)
rightKeyboardView.setupWithModel(rightKeyboardModel)
}
@objc func draggedView(_ sender:UIPanGestureRecognizer){
guard let keyboardView = sender.view?.superview else {
return
}
// NSLayoutConstraint.deactivate(keyboardConstraints)
// self.view.bringSubviewToFront(keyboardView)
let translation = sender.translation(in: self.view)
keyboardView.center = CGPoint(x: keyboardView.center.x + translation.x, y: keyboardView.center.y + translation.y)
sender.setTranslation(CGPoint.zero, in: self.view)
}
}
extension EmulatorKeyboardController: EmulatorKeyboardViewDelegate {
func toggleAlternateKeys() {
for keyboard in [leftKeyboardView, rightKeyboardView] {
keyboard.toggleKeysStackView()
}
}
func refreshModifierStates() {
for keyboard in [leftKeyboardView, rightKeyboardView] {
keyboard.refreshModifierStates()
}
}
func updateTransparency(toAlpha alpha: Float) {
for keyboard in [leftKeyboardView, rightKeyboardView] {
keyboard.alpha = CGFloat(alpha)
}
}
}

View File

@ -0,0 +1,22 @@
//
// GameControllerKeyRemapController.h
// activegs
//
// Created by Yoshi Sugawara on 4/8/16.
//
//
#import <UIKit/UIKit.h>
#import "KeyMapper.h"
@interface GameControllerKeyRemapController : UIViewController
@property (nonatomic, strong) IBOutlet UIView *keyboardContainerView;
@property (nonatomic, strong) IBOutlet UIButton *saveButton;
@property (nonatomic, strong) IBOutlet UIButton *cancelButton;
@property (nonatomic, strong) IBOutlet UIButton *defaultsButton;
@property (nonatomic, strong) KeyMapper *keyMapper;
@property(nonatomic, copy) void (^onDismissal)();
@end

View File

@ -0,0 +1,503 @@
//
// GameControllerKeyRemapController.m
// activegs
//
// Created by Yoshi Sugawara on 4/8/16.
//
//
#import <GameController/GameController.h>
#import "GameControllerKeyRemapController.h"
#import "KeyCapView.h"
#import "KeyMapper.h"
#import "MfiGameControllerHandler.h"
const CGFloat NUMBER_OF_KEYS_IN_ROW = 15.0f;
const CGFloat KEYCAP_WIDTH_PCT = 1.0f / NUMBER_OF_KEYS_IN_ROW;
const CGFloat KEYCAP_HORIZONTAL_PADDING = 2.0f;
const CGFloat KEYCAP_VERTICAL_PADDING = 2.0f;
const CGFloat KEYCAP_HEIGHT = 40.0f;
// Using a C struct here for really just convenience of typing the definitions out
// This gets converted into an obj-c object later
struct KeyCap {
CGFloat widthMultiplier;
const char* key1;
int code1;
const char* key2;
};
struct KeyCap keyCapDefinitions[] = {
{ 1.2,"caps",KEY_CAPS,0 },
{ 1.5,"opt",KEY_APPLE,0 },
{ 1.0,"",KEY_OPTION,0 },
{ 1.0,"`",KEY_TILDE,0 },
{ 6.3," ",KEY_SPACE,0 },
{ 1.0,"←",KEY_LEFT_CURSOR,0 },
{ 1.0,"→",KEY_RIGHT_CURSOR,0 },
{ 1.0,"↑",KEY_UP_CURSOR,0 },
{ 1.0,"↓",KEY_DOWN_CURSOR,0 },
{ -1,0,0,0 },
{ 2.5,"shift",KEY_SHIFT,0 },
{ 1.0,"Z",KEY_Z,0 },
{ 1.0,"X",KEY_X,0 },
{ 1.0,"C",KEY_C,0 },
{ 1.0,"V",KEY_V,0 },
{ 1.0,"B",KEY_B,0 },
{ 1.0,"N",KEY_N,0 },
{ 1.0,"M",KEY_M,0 },
{ 1.0,",",KEY_COMMA,"<" },
{ 1.0,".",KEY_PERIOD,">" },
{ 1.0,"/",KEY_FSLASH,"?" },
{ 2.5,"shift",KEY_SHIFT,0 },
{ -1,0,0,0 },
{ 2.0,"control",KEY_CTRL,0 },
{ 1.0,"A",KEY_A,0 },
{ 1.0,"S",KEY_S,0 },
{ 1.0,"D",KEY_D,0 },
{ 1.0,"F",KEY_F,0 },
{ 1.0,"G",KEY_G,0 },
{ 1.0,"H",KEY_H,0 },
{ 1.0,"J",KEY_J,0 },
{ 1.0,"K",KEY_K,0 },
{ 1.0,"L",KEY_L,0 },
{ 1.0,";",KEY_SEMICOLON,":" },
{ 1.0,"'",KEY_SQUOTE,"\""},
{ 2.0,"return",KEY_RETURN,0 },
{ -1,0,0,0 },
{ 2.0,"tab",KEY_TAB,0 },
{ 1.0,"Q",KEY_Q,0 },
{ 1.0,"W",KEY_W,0 },
{ 1.0,"E",KEY_E,0 },
{ 1.0,"R",KEY_R,0 },
{ 1.0,"T",KEY_T,0 },
{ 1.0,"Y",KEY_Y,0 },
{ 1.0,"U",KEY_U,0 },
{ 1.0,"I",KEY_I,0 },
{ 1.0,"O",KEY_O,0 },
{ 1.0,"P",KEY_P,0 },
{ 1.5,"[",KEY_LEFT_BRACKET,"{" },
{ 1.5,"]",KEY_RIGHT_BRACKET,"}" },
{ -1,0,0,0 },
{ 1.0,"esc",KEY_ESC,0 },
{ 1.0,"1",KEY_1,"!" },
{ 1.0,"2",KEY_2,"@" },
{ 1.0,"3",KEY_3,"#" },
{ 1.0,"4",KEY_4,"$" },
{ 1.0,"5",KEY_5,"%" },
{ 1.0,"6",KEY_6,"^" },
{ 1.0,"7",KEY_7,"&" },
{ 1.0,"8",KEY_8,"*" },
{ 1.0,"9",KEY_9,"(" },
{ 1.0,"0",KEY_0,")" },
{ 1.0,"-",KEY_MINUS,"_" },
{ 1.0,"=",KEY_EQUALS,"+" },
{ 2.0,"delete",KEY_DELETE,0 },
{ 0,0,0,0 }
};
@interface GameControllerKeyRemapController () <UIAlertViewDelegate,UITextFieldDelegate>
@property (nonatomic, strong) NSMutableArray *keyCapViews;
@property (nonatomic, strong) UIAlertView *alertView;
@property (nonatomic, strong) KeyMapper *keyMapperWorkingCopy;
@property (nonatomic, strong) MfiGameControllerHandler *controllerHandler;
@property (nonatomic, strong) UITextField *textFieldForICadeInput;
@property (nonatomic, strong) NSNumber *currentlyMappingKey;
@end
@implementation GameControllerKeyRemapController
- (void)viewDidLoad {
[super viewDidLoad];
self.controllerHandler = [[MfiGameControllerHandler alloc] init];
[self.controllerHandler discoverController:^(GCController *gameController) {
} disconnectedCallback:^{
}];
self.keyCapViews = [NSMutableArray array];
self.keyMapperWorkingCopy = [self.keyMapper copy];
self.saveButton.layer.borderWidth = 1.0f;
self.saveButton.layer.borderColor = [self.view.tintColor CGColor];
self.cancelButton.layer.borderWidth = 1.0f;
self.cancelButton.layer.borderColor = [[UIColor redColor] CGColor];
self.defaultsButton.layer.borderWidth = 1.0f;
self.defaultsButton.layer.borderColor = [self.view.tintColor CGColor];
// for detecting icade input
self.textFieldForICadeInput = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
self.textFieldForICadeInput.delegate = self;
self.textFieldForICadeInput.autocapitalizationType= UITextAutocorrectionTypeNo;
self.currentlyMappingKey = nil;
[self constructKeyboard];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// convert the above c struct array into an objective c object to make it easier to deal with (for me, personally)
-(NSArray*) objc_keyCapsDefinitions {
NSMutableArray *keyDefs = [NSMutableArray array];
NSMutableArray *keyDefsRow = [NSMutableArray array];
int i = 0;
while (keyCapDefinitions[i].widthMultiplier) {
struct KeyCap keyCap = keyCapDefinitions[i];
if ( keyCap.widthMultiplier == -1.0 ) {
[keyDefs addObject:[keyDefsRow copy]];
[keyDefsRow removeAllObjects];
i++;
continue;
}
[keyDefsRow addObject:@[ [NSNumber numberWithFloat:keyCap.widthMultiplier],
[NSString stringWithUTF8String:keyCap.key1],
[NSNumber numberWithInt:keyCap.code1],
keyCap.key2 != 0 ? [NSString stringWithUTF8String:keyCap.key2] : @""
]];
i++;
}
[keyDefs addObject:keyDefsRow];
return [keyDefs copy];
}
// Construct the keyboard key views using auto layout constraints entirely
// It gets constructed from the bottom up (pinned to the bottom)
-(void) constructKeyboard {
NSArray *keyDefinitions = [self objc_keyCapsDefinitions];
UIView *keyboardContainer = self.keyboardContainerView;
UIView *lastVerticalView = nil;
UIView *lastHorizontalView = nil;
NSUInteger keyboardRow = 0;
for (NSArray *keyDefsRow in keyDefinitions) {
KeyCapView *keyCapView = nil;
NSUInteger keyIndex = 0;
for (NSArray *keyDef in keyDefsRow) {
keyCapView = [KeyCapView createViewWithKeyDef:keyDef];
keyCapView.translatesAutoresizingMaskIntoConstraints = NO;
keyCapView.layer.borderWidth = 1.0f;
keyCapView.layer.borderColor = [[UIColor blackColor] CGColor];
[keyCapView setupWithKeyMapper:self.keyMapperWorkingCopy];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onKeyTap:)];
[keyCapView addGestureRecognizer:tap];
[self.keyCapViews addObject:keyCapView];
CGFloat widthMultiplier = [[keyDef objectAtIndex:KeyCapIndexWidthMultiplier] floatValue] * KEYCAP_WIDTH_PCT;
NSDictionary *metrics = @{@"height" : @(KEYCAP_HEIGHT), @"padding" : @(KEYCAP_HORIZONTAL_PADDING)};
[keyboardContainer addSubview:keyCapView];
// vertical
if ( keyboardRow == 0 ) {
NSDictionary *bindings = NSDictionaryOfVariableBindings(keyCapView);
// pin to super view bottom
[keyboardContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[keyCapView(height)]-0@750-|" options:0 metrics:metrics views:bindings]];
} else {
NSDictionary *bindings = NSDictionaryOfVariableBindings(keyCapView,lastVerticalView);
// pin bottom to last vertical view
[keyboardContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[keyCapView(height)]-4@750-[lastVerticalView]" options:0 metrics:metrics views:bindings]];
}
// horizontal
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:keyCapView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:keyboardContainer attribute:NSLayoutAttributeWidth multiplier:widthMultiplier constant:KEYCAP_HORIZONTAL_PADDING * -1.0];
if ( lastHorizontalView == nil ) {
NSDictionary *bindings = NSDictionaryOfVariableBindings(keyCapView);
[keyboardContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-padding@750-[keyCapView]" options:0 metrics:metrics views:bindings]];
} else {
NSDictionary *bindings = NSDictionaryOfVariableBindings(keyCapView,lastHorizontalView);
if ( keyIndex == (int)NUMBER_OF_KEYS_IN_ROW-1 ) {
// last key in row
[keyboardContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[lastHorizontalView]-padding@750-[keyCapView]-padding@750-|" options:0 metrics:metrics views:bindings]];
} else {
[keyboardContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[lastHorizontalView]-padding@750-[keyCapView]" options:0 metrics:metrics views:bindings]];
}
}
if ( keyIndex != (int)NUMBER_OF_KEYS_IN_ROW-1 ) {
[keyboardContainer addConstraint:widthConstraint];
}
keyIndex++;
lastHorizontalView = keyCapView;
}
lastVerticalView = keyCapView;
lastHorizontalView = nil;
keyboardRow++;
}
}
- (void) refreshAllKeyCapViews {
for (KeyCapView *view in self.keyCapViews) {
[view setupWithKeyMapper:self.keyMapperWorkingCopy];
}
}
- (void) onKeyTap:(UITapGestureRecognizer*)sender {
KeyCapView *view = (KeyCapView*) sender.view;
self.alertView = [[UIAlertView alloc] initWithTitle:@"Remap Key" message:[NSString stringWithFormat:@"Press a button to map the [%@] key",[view.keyDef objectAtIndex:KeyCapIndexKey]] delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Unbind",nil];
[self.alertView show];
self.alertView.tag = [[view.keyDef objectAtIndex:KeyCapIndexCode] integerValue];
[self startRemappingControlsForMfiControllerForKey:[view.keyDef objectAtIndex:KeyCapIndexCode]];
self.alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
[self.alertView textFieldAtIndex:0].delegate = self;
[self.alertView textFieldAtIndex:0].autocapitalizationType = UITextAutocorrectionTypeNo;
// start icade detection
self.currentlyMappingKey = [view.keyDef objectAtIndex:KeyCapIndexCode];
}
- (void) startRemappingControlsForMfiControllerForKey:(NSNumber*)keyCode {
AppleKeyboardKey keyboardKey = [keyCode intValue];
if ( [[GCController controllers] count] == 0 ) {
NSLog(@"Could not find any mfi controllers!");
return;
}
GCController *controller = [[GCController controllers] firstObject];
if ( controller.extendedGamepad ) {
controller.extendedGamepad.valueChangedHandler = ^(GCExtendedGamepad *gamepad, GCControllerElement *element) {
if ( gamepad.buttonA.pressed ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_BUTTON_A];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.buttonB.pressed ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_BUTTON_B];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.buttonX.pressed ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_BUTTON_X];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.buttonY.pressed ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_BUTTON_Y];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.leftShoulder.pressed ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_BUTTON_LS];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.rightShoulder.pressed ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_BUTTON_RS];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.dpad.xAxis.value > 0.0f ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_DPAD_RIGHT];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.dpad.xAxis.value < 0.0f ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_DPAD_LEFT];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.dpad.yAxis.value > 0.0f ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_DPAD_UP];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.dpad.yAxis.value < 0.0f ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_DPAD_DOWN];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.rightTrigger.pressed ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_BUTTON_RT];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.leftTrigger.pressed ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_BUTTON_LT];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
};
} else {
controller.gamepad.valueChangedHandler = ^(GCGamepad *gamepad, GCControllerElement *element) {
if ( gamepad.buttonA.pressed ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_BUTTON_A];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.buttonB.pressed ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_BUTTON_B];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.buttonX.pressed ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_BUTTON_X];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.buttonY.pressed ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_BUTTON_Y];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];;
return;
}
if ( gamepad.leftShoulder.pressed ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_BUTTON_LS];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.rightShoulder.pressed ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_BUTTON_RS];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.dpad.xAxis.value > 0.0f ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_DPAD_RIGHT];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.dpad.xAxis.value < 0.0f ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_DPAD_LEFT];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.dpad.yAxis.value > 0.0f ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_DPAD_UP];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
if ( gamepad.dpad.yAxis.value < 0.0f ) {
[self.keyMapperWorkingCopy mapKey:keyboardKey ToControl:MFI_DPAD_DOWN];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
return;
}
};
}
}
-(void) stopRemappingControls {
if ( [[GCController controllers] count] == 0 ) {
return;
}
GCController *controller = [[GCController controllers] firstObject];
if ( controller.extendedGamepad ) {
controller.extendedGamepad.valueChangedHandler = nil;
} else {
controller.gamepad.valueChangedHandler = nil;
}
self.currentlyMappingKey = nil;
}
-(IBAction)saveButtonTapped:(id)sender {
self.keyMapper = [self.keyMapperWorkingCopy copy];
[self.keyMapper saveKeyMapping];
self.keyMapperWorkingCopy = nil;
[self.presentingViewController dismissViewControllerAnimated:YES completion:^{
self.onDismissal();
}];
}
-(IBAction)cancelButtonTapped:(id)sender {
self.keyMapperWorkingCopy = nil;
[self.presentingViewController dismissViewControllerAnimated:YES completion:^{
self.onDismissal();
}];
}
-(IBAction) defaultsButtonTapped:(id)sender {
[self.keyMapperWorkingCopy resetToDefaults];
[self refreshAllKeyCapViews];
}
#
# pragma mark - UIAlertViewDelegate
#
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
[self stopRemappingControls];
if ( buttonIndex == 1 ) {
AppleKeyboardKey mappedKey = alertView.tag;
[self.keyMapperWorkingCopy unmapKey:mappedKey];
}
}
- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex {
[self stopRemappingControls];
[self refreshAllKeyCapViews];
}
#
# pragma mark - UITextFieldDelegate
#
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if ( self.currentlyMappingKey == nil ) {
return NO;
}
const char* s = [string UTF8String];
char c;
int i=0;
while( (c = s[i++]) != 0)
{
switch(c) {
case 'e': // up released
[self.keyMapperWorkingCopy mapKey:self.currentlyMappingKey.integerValue ToControl:ICADE_DPAD_UP];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
break;
case 'z': // down released
[self.keyMapperWorkingCopy mapKey:self.currentlyMappingKey.integerValue ToControl:ICADE_DPAD_DOWN];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
break;
case 'q': // left released
[self.keyMapperWorkingCopy mapKey:self.currentlyMappingKey.integerValue ToControl:ICADE_DPAD_LEFT];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
break;
case 'c': // right released
[self.keyMapperWorkingCopy mapKey:self.currentlyMappingKey.integerValue ToControl:ICADE_DPAD_RIGHT];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
break;
case 't': // button 1 released
[self.keyMapperWorkingCopy mapKey:self.currentlyMappingKey.integerValue ToControl:ICADE_BUTTON_1];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
break;
case 'r': // button 2 released
[self.keyMapperWorkingCopy mapKey:self.currentlyMappingKey.integerValue ToControl:ICADE_BUTTON_2];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
break;
case 'f': // button 3 released
[self.keyMapperWorkingCopy mapKey:self.currentlyMappingKey.integerValue ToControl:ICADE_BUTTON_3];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
break;
case 'n': // button 4 released
[self.keyMapperWorkingCopy mapKey:self.currentlyMappingKey.integerValue ToControl:ICADE_BUTTON_4];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
break;
case 'm': // button 5 released
[self.keyMapperWorkingCopy mapKey:self.currentlyMappingKey.integerValue ToControl:ICADE_BUTTON_5];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
break;
case 'p': // button 6 released
[self.keyMapperWorkingCopy mapKey:self.currentlyMappingKey.integerValue ToControl:ICADE_BUTTON_6];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
break;
case 'g': // button 7 released
[self.keyMapperWorkingCopy mapKey:self.currentlyMappingKey.integerValue ToControl:ICADE_BUTTON_7];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
break;
case 'v': // button 8 released
[self.keyMapperWorkingCopy mapKey:self.currentlyMappingKey.integerValue ToControl:ICADE_BUTTON_8];
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
break;
default:
break;
}
}
return NO;
}
@end

View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10116" systemVersion="15A284" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="GameControllerKeyRemapController">
<connections>
<outlet property="cancelButton" destination="zAx-JO-gDf" id="i1M-NV-0UN"/>
<outlet property="defaultsButton" destination="Ih9-iG-ECT" id="Ho3-g5-rOQ"/>
<outlet property="keyboardContainerView" destination="PbL-95-ilz" id="UPI-70-2J7"/>
<outlet property="saveButton" destination="Ihv-aC-sb7" id="Byt-Gy-MVK"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="PbL-95-ilz" userLabel="Keyboard Container View">
<rect key="frame" x="0.0" y="380" width="600" height="220"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="height" constant="220" id="QNq-rB-Zxd"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ihv-aC-sb7">
<rect key="frame" x="88.5" y="158" width="107" height="44"/>
<constraints>
<constraint firstAttribute="width" constant="107" id="82d-Qy-Xfg"/>
<constraint firstAttribute="height" constant="44" id="bOc-8m-OXA"/>
</constraints>
<state key="normal" title="Save"/>
<connections>
<action selector="saveButtonTapped:" destination="-1" eventType="touchUpInside" id="dbc-hJ-1z4"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zAx-JO-gDf">
<rect key="frame" x="404.5" y="158" width="107" height="44"/>
<state key="normal" title="Cancel">
<color key="titleColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
</state>
<connections>
<action selector="cancelButtonTapped:" destination="-1" eventType="touchUpInside" id="byq-hr-jDY"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Remap Keys to Gamepad Buttons" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="x2H-qm-EGT">
<rect key="frame" x="172" y="64" width="256" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ih9-iG-ECT">
<rect key="frame" x="247" y="158" width="107" height="44"/>
<constraints>
<constraint firstAttribute="width" constant="107" id="8aa-Yx-81a"/>
<constraint firstAttribute="height" constant="44" id="qBN-1t-J0B"/>
</constraints>
<state key="normal" title="Defaults"/>
<variation key="default">
<mask key="constraints">
<exclude reference="8aa-Yx-81a"/>
<exclude reference="qBN-1t-J0B"/>
</mask>
</variation>
<connections>
<action selector="defaultsButtonTapped:" destination="-1" eventType="touchUpInside" id="reT-vk-ZW4"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="x2H-qm-EGT" firstAttribute="centerY" secondItem="i5M-Pr-FkT" secondAttribute="centerY" multiplier="0.25" id="3zs-qM-hjM"/>
<constraint firstItem="zAx-JO-gDf" firstAttribute="top" secondItem="Ihv-aC-sb7" secondAttribute="top" id="6TO-tV-bng"/>
<constraint firstItem="PbL-95-ilz" firstAttribute="height" secondItem="i5M-Pr-FkT" secondAttribute="height" multiplier="0.4" id="7Tq-sc-r5F"/>
<constraint firstItem="PbL-95-ilz" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="ALZ-jN-EW8"/>
<constraint firstItem="zAx-JO-gDf" firstAttribute="height" secondItem="Ihv-aC-sb7" secondAttribute="height" id="HFd-QQ-Vpx"/>
<constraint firstItem="zAx-JO-gDf" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" multiplier="1.5" constant="8" id="Kdj-w0-y90"/>
<constraint firstItem="Ih9-iG-ECT" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="Mgp-p2-fmB"/>
<constraint firstItem="Ih9-iG-ECT" firstAttribute="width" secondItem="Ihv-aC-sb7" secondAttribute="width" id="R6y-RO-5t1"/>
<constraint firstItem="Ih9-iG-ECT" firstAttribute="top" secondItem="Ihv-aC-sb7" secondAttribute="top" id="XbU-xP-HYw"/>
<constraint firstItem="x2H-qm-EGT" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="ZTO-dh-bwz"/>
<constraint firstItem="zAx-JO-gDf" firstAttribute="centerX" secondItem="Ihv-aC-sb7" secondAttribute="centerX" multiplier="2" id="hJc-6p-crb"/>
<constraint firstAttribute="bottom" secondItem="PbL-95-ilz" secondAttribute="bottom" id="kCc-QA-uYA"/>
<constraint firstItem="zAx-JO-gDf" firstAttribute="width" secondItem="Ihv-aC-sb7" secondAttribute="width" id="mPI-1j-gTO"/>
<constraint firstItem="Ihv-aC-sb7" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" multiplier="0.5" constant="-8" id="niB-eU-bnx"/>
<constraint firstItem="Ihv-aC-sb7" firstAttribute="centerY" secondItem="i5M-Pr-FkT" secondAttribute="centerY" multiplier="0.6" id="vLe-Gk-22l"/>
<constraint firstAttribute="trailing" secondItem="PbL-95-ilz" secondAttribute="trailing" id="zbm-Dr-7Jd"/>
<constraint firstItem="Ih9-iG-ECT" firstAttribute="height" secondItem="Ihv-aC-sb7" secondAttribute="height" id="zd1-zF-ZZI"/>
</constraints>
<variation key="default">
<mask key="constraints">
<exclude reference="7Tq-sc-r5F"/>
<exclude reference="hJc-6p-crb"/>
</mask>
</variation>
</view>
</objects>
</document>

View File

@ -22,6 +22,8 @@
#include "../kegs/Src/SaveState.h"
#include "../Common/ActiveDownload.h"
#import "MfiGameControllerHandler.h"
#import "GameControllerKeyRemapController.h"
#import "ActiveGS-Swift.h"
#ifdef ACTIVEGS_CUSTOMKEYS
#include "UICustomKey.h"
@ -281,6 +283,7 @@ int isHardwareKeyboard()
UISegmentedControl *saveStateSegmentedControl;
}
@property (nonatomic,strong) MfiGameControllerHandler *mfiControllerHandler;
@property (nonatomic,strong) KeyMapper *keyMapper;
@end
@implementation KBDController
@ -333,7 +336,6 @@ int isHardwareKeyboard()
extern int findCode(const char* _s);
- (void)loadView
{
@ -455,7 +457,7 @@ extern int findCode(const char* _s);
self.debugIndicator.hidden = TRUE;
self.debugIndicator.backgroundColor = [UIColor lightGrayColor];
self.debugIndicator.font = [UIFont systemFontOfSize:(CGFloat)12.0];
self.debugIndicator.lineBreakMode=UILineBreakModeClip;
self.debugIndicator.lineBreakMode=NSLineBreakByClipping;
[self.interfaceView addSubview:self.debugIndicator];
[self showDebug:FALSE];
@ -568,6 +570,9 @@ extern int findCode(const char* _s);
[self setInputMode:INPUTMODE_ACCESS+INPUTMODE_HIDDEN];
[self setMenuBarVisibility:TRUE]; // So First time users are not lost!
self.keyMapper = [[KeyMapper alloc] init];
[self.keyMapper loadFromDefaults];
self.mfiControllerHandler = [[MfiGameControllerHandler alloc] init];
__weak typeof(self) weakSelf = self;
[self.mfiControllerHandler discoverController:^(GCController *gameController) {
@ -578,8 +583,8 @@ extern int findCode(const char* _s);
[pManager setNotificationText:@"mFi Controller Disconnected"];
}];
}
}
- (NSArray*)keyCommands
{
if (lastArrowKey != 0)
@ -645,8 +650,15 @@ extern int findCode(const char* _s);
joyX = xvalue;
joyY = yvalue * -1.0;
};
GCControllerButtonInput *buttonX = controller.extendedGamepad ? controller.extendedGamepad.buttonX : controller.gamepad.buttonX;
GCControllerButtonInput *buttonA = controller.extendedGamepad ? controller.extendedGamepad.buttonA : controller.gamepad.buttonA;
GCControllerButtonInput *buttonY = controller.extendedGamepad ? controller.extendedGamepad.buttonY : controller.gamepad.buttonY;
GCControllerButtonInput *buttonB = controller.extendedGamepad ? controller.extendedGamepad.buttonB : controller.gamepad.buttonB;
GCControllerButtonInput *buttonRS = controller.extendedGamepad ? controller.extendedGamepad.rightShoulder : controller.gamepad.rightShoulder;
GCControllerButtonInput *buttonLS = controller.extendedGamepad ? controller.extendedGamepad.leftShoulder : controller.gamepad.leftShoulder;
GCControllerButtonInput *buttonRT = controller.extendedGamepad ? controller.extendedGamepad.rightTrigger : nil;
GCControllerButtonInput *buttonLT = controller.extendedGamepad ? controller.extendedGamepad.leftTrigger : nil;
GCControllerDirectionPad *dpad = controller.extendedGamepad ? controller.extendedGamepad.dpad : controller.gamepad.dpad;
buttonX.valueChangedHandler = appleJoyButton0Handler;
@ -656,6 +668,132 @@ extern int findCode(const char* _s);
if ( controller.extendedGamepad ) {
controller.extendedGamepad.leftThumbstick.valueChangedHandler = appleJoystickhHandler;
}
//
// mapped keys
AppleKeyboardKey mappedKey = [self.keyMapper getMappedKeyForControl:MFI_BUTTON_X];
if ( mappedKey != NSNotFound ) {
buttonX.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
if ( pressed ) {
add_event_key((int)mappedKey, 0);
} else {
add_event_key((int)mappedKey, 1);
}
};
}
mappedKey = [self.keyMapper getMappedKeyForControl:MFI_BUTTON_Y];
if ( mappedKey != NSNotFound ) {
buttonY.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
if ( pressed ) {
add_event_key((int)mappedKey, 0);
} else {
add_event_key((int)mappedKey, 1);
}
};
}
mappedKey = [self.keyMapper getMappedKeyForControl:MFI_BUTTON_A];
if ( mappedKey != NSNotFound ) {
buttonA.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
if ( pressed ) {
add_event_key((int)mappedKey, 0);
} else {
add_event_key((int)mappedKey, 1);
}
};
}
mappedKey = [self.keyMapper getMappedKeyForControl:MFI_BUTTON_B];
if ( mappedKey != NSNotFound ) {
buttonB.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
if ( pressed ) {
add_event_key((int)mappedKey, 0);
} else {
add_event_key((int)mappedKey, 1);
}
};
}
mappedKey = [self.keyMapper getMappedKeyForControl:MFI_BUTTON_LS];
if ( mappedKey != NSNotFound ) {
buttonLS.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
if ( pressed ) {
add_event_key((int)mappedKey, 0);
} else {
add_event_key((int)mappedKey, 1);
}
};
}
mappedKey = [self.keyMapper getMappedKeyForControl:MFI_BUTTON_RS];
if ( mappedKey != NSNotFound ) {
buttonRS.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
if ( pressed ) {
add_event_key((int)mappedKey, 0);
} else {
add_event_key((int)mappedKey, 1);
}
};
}
mappedKey = [self.keyMapper getMappedKeyForControl:MFI_BUTTON_LT];
if ( mappedKey != NSNotFound && buttonLT != nil ) {
buttonLT.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
if ( pressed ) {
add_event_key((int)mappedKey, 0);
} else {
add_event_key((int)mappedKey, 1);
}
};
}
mappedKey = [self.keyMapper getMappedKeyForControl:MFI_BUTTON_RT];
if ( mappedKey != NSNotFound && buttonLT != nil ) {
buttonRT.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) {
if ( pressed ) {
add_event_key((int)mappedKey, 0);
} else {
add_event_key((int)mappedKey, 1);
}
};
}
AppleKeyboardKey mappedKeyDpadUp = [self.keyMapper getMappedKeyForControl:MFI_DPAD_UP];
AppleKeyboardKey mappedKeyDpadDown = [self.keyMapper getMappedKeyForControl:MFI_DPAD_DOWN];
AppleKeyboardKey mappedKeyDpadLeft = [self.keyMapper getMappedKeyForControl:MFI_DPAD_LEFT];
AppleKeyboardKey mappedKeyDpadRight = [self.keyMapper getMappedKeyForControl:MFI_DPAD_RIGHT];
if ( mappedKeyDpadUp != NSNotFound || mappedKeyDpadDown != NSNotFound || mappedKeyDpadLeft != NSNotFound || mappedKeyDpadRight != NSNotFound ) {
dpad.valueChangedHandler = ^(GCControllerDirectionPad *, float xvalue, float yvalue) {
if ( mappedKeyDpadUp != NSNotFound && yvalue > 0.0 ) {
add_event_key((int)mappedKeyDpadUp, 0);
} else if ( mappedKeyDpadUp != NSNotFound && yvalue <= 0.0 ) {
add_event_key((int)mappedKeyDpadUp, 1);
}
if ( mappedKeyDpadDown != NSNotFound && yvalue < 0.0 ) {
add_event_key((int)mappedKeyDpadDown, 0);
} else if ( mappedKeyDpadDown != NSNotFound && yvalue >= 0.0 ) {
add_event_key((int)mappedKeyDpadDown, 1);
}
if ( mappedKeyDpadRight != NSNotFound && xvalue > 0.0 ) {
add_event_key((int)mappedKeyDpadRight, 0);
} else if ( mappedKeyDpadRight != NSNotFound && xvalue <= 0.0 ) {
add_event_key((int)mappedKeyDpadRight, 1);
}
if ( mappedKeyDpadLeft != NSNotFound && xvalue < 0.0 ) {
add_event_key((int)mappedKeyDpadLeft, 0);
} else if ( mappedKeyDpadLeft != NSNotFound && xvalue >= 0.0 ) {
add_event_key((int)mappedKeyDpadLeft, 1);
}
// pass the joystick input through
joyX = xvalue;
joyY = yvalue * -1.0;
};
}
}
int hardwarekeyboard= 0;
@ -1012,6 +1150,25 @@ extern int x_frame_rate ;
[pManager setNotificationText:[NSString stringWithFormat:@"Loaded State #%@",segIndex]];
}
-(void) remapControlsButtonPressed:(id)sender {
r_sim65816.pause();
GameControllerKeyRemapController *remapController = [[GameControllerKeyRemapController alloc] initWithNibName:@"GameControllerKeyRemapController" bundle:nil];
remapController.keyMapper = self.keyMapper;
remapController.onDismissal = ^{
[self.keyMapper loadFromDefaults];
[self setupMfiController:[[GCController controllers] firstObject]];
r_sim65816.resume();
};
[self presentViewController:remapController animated:YES completion:nil];
}
-(void) memoryDebuggerButtonPressed:(id)sender {
r_sim65816.pause();
DebugMemoryViewController *controller = [pManager getEmulatorView].debugMemoryViewController;
controller.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:controller animated:YES completion:nil];
}
//
-(void)addRuntimeControls
{
@ -1111,6 +1268,42 @@ extern int x_frame_rate ;
[self.runtimeControlsOptions addSubview:loadStateButton];
l+=LINEHEIGHT;
l += 2.0;
UILabel* remapControlsLabel = [[UILabel alloc] initWithFrame:CGRectMake(OPTIONMARGIN,l,OPTIONWIDTH,LINEHEIGHT)];
remapControlsLabel.text = @"Key Bindings";
remapControlsLabel.textAlignment = NSTextAlignmentCenter;
remapControlsLabel.font = [UIFont systemFontOfSize:12*res];
remapControlsLabel.backgroundColor = [UIColor clearColor];
[self.runtimeControlsOptions addSubview:remapControlsLabel];
l += LINEHEIGHT;
l += 2.0;
UIButton *remapControlsButton = [UIButton buttonWithType:UIButtonTypeCustom];
remapControlsButton.frame = CGRectMake(OPTIONMARGIN,l,OPTIONWIDTH,LINEHEIGHT);
[remapControlsButton setTitle:@"Remap Controls" forState:UIControlStateNormal];
remapControlsButton.titleLabel.font = [UIFont systemFontOfSize:12*res];
[remapControlsButton setTitleColor:self.view.tintColor forState:UIControlStateNormal];
remapControlsButton.backgroundColor = [UIColor clearColor];
remapControlsButton.layer.borderWidth = 1.0f;
remapControlsButton.layer.borderColor = [self.view.tintColor CGColor];
[remapControlsButton addTarget:self action:@selector(remapControlsButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self.runtimeControlsOptions addSubview:remapControlsButton];
l += LINEHEIGHT;
l += 2.0;
UIButton *memoryDebuggerButton = [UIButton buttonWithType:UIButtonTypeCustom];
memoryDebuggerButton.frame = CGRectMake(OPTIONMARGIN,l,OPTIONWIDTH,LINEHEIGHT);
[memoryDebuggerButton setTitle:@"Memory Debugger" forState:UIControlStateNormal];
memoryDebuggerButton.titleLabel.font = [UIFont systemFontOfSize:12*res];
memoryDebuggerButton.backgroundColor = [UIColor clearColor];
memoryDebuggerButton.layer.borderWidth = 1.0f;
memoryDebuggerButton.layer.borderColor = [self.view.tintColor CGColor];
[memoryDebuggerButton addTarget:self action:@selector(memoryDebuggerButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self.runtimeControlsOptions addSubview:memoryDebuggerButton];
l += LINEHEIGHT;
nbs++;
float w = OPTIONWIDTH+OPTIONMARGIN*2;
@ -2087,7 +2280,7 @@ int x_adb_get_keypad_y()
else
if (!bForceOnScreenKeyboard)
{
AppleKeyboardKey mappedKey = NSNotFound;
char c;
int i=0;
while( (c = s[i++]) != 0)
@ -2096,44 +2289,165 @@ int x_adb_get_keypad_y()
{
case 'w': // up
keypad_y = -32767;
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_DPAD_UP];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 0);
}
break;
case 'e': // !verti
case 'z':
case 'e': // !verti : up released
keypad_y = 0;
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_DPAD_UP];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 1);
}
break;
case 'z': // down released
keypad_y = 0;
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_DPAD_DOWN];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 1);
}
break;
case 'x': // down
keypad_y = 32767;
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_DPAD_DOWN];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 0);
}
break;
case 'a': // left
keypad_x = -32767;
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_DPAD_LEFT];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 0);
}
break;
case 'q': // !hori
case 'c':
case 'q': // left released
keypad_x = 0;
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_DPAD_LEFT];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 1);
}
case 'c': // right released
keypad_x = 0;
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_DPAD_RIGHT];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 1);
}
break;
case 'd': // right
keypad_x = 32767;
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_DPAD_RIGHT];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 0);
}
break;
case 'y': // button 1 pressed
add_event_key(0x37, 0);
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_1];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 0);
}
break;
case 't': // button 1 depressed
add_event_key(0x37, 1);
// add_event_key(0x37, 1);
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_1];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 1);
}
break;
case 'h': // button 2 pressed
add_event_key(0x3a, 0);
// add_event_key(0x3a, 0);
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_2];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 0);
}
break;
case 'r': // button 2 depressed
add_event_key(0x3a, 1);
// add_event_key(0x3a, 1);
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_2];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 1);
}
break;
case 'g': //à faire sur un keydepressed
// display keyboard
printf("*** forcing on-screeen keyboard");
[self OnScreenKeyboard:TRUE];
case 'u': // button 3 pressed
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_3];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 0);
}
break;
case 'f': // button 3 released
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_3];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 1);
}
break;
case 'j': // button 4 pressed
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_4];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 0);
}
break;
case 'n': // button 4 released
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_4];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 1);
}
break;
case 'i': // button 5 pressed
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_5];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 0);
}
break;
case 'm': // button 5 released
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_5];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 1);
}
break;
case 'k': // button 6 pressed
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_5];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 0);
}
break;
case 'p': // button 6 released
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_5];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 1);
}
break;
case 'o':
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_6];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 0);
}
break;
case 'g': //à faire sur un keydepressed : coin
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_6];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 1);
} else {
// display keyboard
printf("*** forcing on-screeen keyboard");
[self OnScreenKeyboard:TRUE];
}
break;
case 'v': //à faire sur un keydepressed
// toggle la menu bar
[self setMenuBarVisibility:!bMenuBarVisibility];
case 'l':
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_7];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 0);
}
break;
case 'v': //à faire sur un keydepressed : start
mappedKey = [self.keyMapper getMappedKeyForControl:ICADE_BUTTON_7];
if ( mappedKey != NSNotFound ) {
add_event_key((int)mappedKey, 1);
} else {
// toggle la menu bar
[self setMenuBarVisibility:!bMenuBarVisibility];
}
break;
default:
break;

View File

@ -0,0 +1,22 @@
//
// KeyCapView.h
// activegs
//
// Created by Yoshi Sugawara on 4/9/16.
//
//
#import <UIKit/UIKit.h>
#import "KeyMapper.h"
@interface KeyCapView : UIView
@property (nonatomic, strong) IBOutlet UILabel *keyLabel;
@property (nonatomic, strong) IBOutlet UILabel *keyLabelAlt;
@property (nonatomic, strong) IBOutlet UILabel *mappedButtonLabel;
@property (nonatomic, strong) NSArray *keyDef;
+ (instancetype)createViewWithKeyDef:(NSArray*)keyDef;
- (void)setupWithKeyMapper:(KeyMapper*)keyMapper;
@end

View File

@ -0,0 +1,48 @@
//
// KeyCapView.m
// activegs
//
// Created by Yoshi Sugawara on 4/9/16.
//
//
#import "KeyCapView.h"
@implementation KeyCapView
+ (instancetype)createViewWithKeyDef:(NSArray*)keyDef
{
KeyCapView *keyCapView = [[[UINib nibWithNibName:@"KeyCapView" bundle:nil] instantiateWithOwner:nil options:nil] lastObject];
if ([keyCapView isKindOfClass:[KeyCapView class]]) {
keyCapView.keyDef = keyDef;
return keyCapView;
} else {
return nil;
}
}
- (void)setupWithKeyMapper:(KeyMapper*)keyMapper {
if ( ![[self.keyDef objectAtIndex:KeyCapIndexShiftedKey] isEqualToString:@""] ) {
self.keyLabel.text = [self.keyDef objectAtIndex:KeyCapIndexShiftedKey];
self.keyLabelAlt.text = [self.keyDef objectAtIndex:KeyCapIndexKey];
} else {
self.keyLabel.text = [self.keyDef objectAtIndex:KeyCapIndexKey];
self.keyLabelAlt.text = @"";
}
self.mappedButtonLabel.text = @"";
NSArray *mappedButtons = [keyMapper getControlsForMappedKey:[[self.keyDef objectAtIndex:KeyCapIndexCode] integerValue]];
if ( mappedButtons.count > 0 ) {
NSMutableString *displayText = [NSMutableString string];
int index = 0;
for (NSNumber *button in mappedButtons) {
if ( index++ > 0 ) {
[displayText appendString:@","];
}
[displayText appendString:[NSString stringWithFormat:@"%@",[KeyMapper controlToDisplayName:button.integerValue]]];
}
self.mappedButtonLabel.text = displayText;
}
}
@end

123
Common.iphone/KeyMapper.h Normal file
View File

@ -0,0 +1,123 @@
//
// KeyMapper.h
// activegs
//
// Created by Yoshi Sugawara on 4/9/16.
//
//
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, AppleKeyboardKey) {
KEY_CAPS = 0x39,
KEY_OPTION = 0x3A,
KEY_APPLE = 0x37,
KEY_TILDE = 0x12,
KEY_SPACE = 0x31,
KEY_RIGHT_CURSOR = 0x3C,
KEY_LEFT_CURSOR = 0x3B,
KEY_UP_CURSOR = 0x3E,
KEY_DOWN_CURSOR = 0x3D,
KEY_SHIFT = 0x38,
KEY_Z = 0x06,
KEY_X = 0x07,
KEY_C = 0x08,
KEY_V = 0x09,
KEY_B = 0x0B,
KEY_N = 0x2D,
KEY_M = 0x2E,
KEY_COMMA = 0x2B,
KEY_PERIOD = 0x2F,
KEY_FSLASH = 0x2C,
KEY_CTRL = 0x36,
KEY_A = 0x00,
KEY_S = 0x01,
KEY_D = 0x02,
KEY_F = 0x03,
KEY_G = 0x05,
KEY_H = 0x04,
KEY_J = 0x26,
KEY_K = 0x28,
KEY_L = 0x25,
KEY_SEMICOLON = 0x29,
KEY_SQUOTE = 0x27,
KEY_RETURN = 0x24,
KEY_TAB = 0x30,
KEY_Q = 0x0C,
KEY_W = 0x0D,
KEY_E = 0x0E,
KEY_R = 0x0F,
KEY_T = 0x11,
KEY_Y = 0x10,
KEY_U = 0x20,
KEY_I = 0x22,
KEY_O = 0x1F,
KEY_P = 0x23,
KEY_LEFT_BRACKET = 0x21,
KEY_RIGHT_BRACKET = 0x1E,
KEY_ESC = 0x35,
KEY_1 = 0x12,
KEY_2 = 0x13,
KEY_3 = 0x14,
KEY_4 = 0x15,
KEY_5 = 0x17,
KEY_6 = 0x16,
KEY_7 = 0x1A,
KEY_8 = 0x1C,
KEY_9 = 0x19,
KEY_0 = 0x1D,
KEY_MINUS = 0x1B,
KEY_EQUALS = 0x18,
KEY_DELETE = 0x33,
KEY_RESET = 0x7F,
KEY_SPECIAL_TOGGLE = 0x50,
KEY_SPECIAL_SPACER = 0x51,
KEY_SPECIAL_DEBUGGER = 0x52
};
typedef NS_ENUM(NSInteger, KeyMapMappableButton) {
MFI_BUTTON_X,
MFI_BUTTON_A,
MFI_BUTTON_B,
MFI_BUTTON_Y,
MFI_BUTTON_LT,
MFI_BUTTON_RT,
MFI_BUTTON_LS,
MFI_BUTTON_RS,
MFI_DPAD_UP,
MFI_DPAD_DOWN,
MFI_DPAD_LEFT,
MFI_DPAD_RIGHT,
ICADE_BUTTON_1,
ICADE_BUTTON_2,
ICADE_BUTTON_3,
ICADE_BUTTON_4,
ICADE_BUTTON_5,
ICADE_BUTTON_6,
ICADE_BUTTON_7,
ICADE_BUTTON_8,
ICADE_DPAD_UP,
ICADE_DPAD_DOWN,
ICADE_DPAD_LEFT,
ICADE_DPAD_RIGHT
};
typedef NS_ENUM(NSInteger, KeyCapIndex) {
KeyCapIndexWidthMultiplier = 0,
KeyCapIndexKey = 1,
KeyCapIndexCode = 2,
KeyCapIndexShiftedKey = 3
};
@interface KeyMapper : NSObject<NSCopying>
-(void)loadFromDefaults;
-(void) resetToDefaults;
-(void) saveKeyMapping;
-(void) mapKey:(AppleKeyboardKey)keyboardKey ToControl:(KeyMapMappableButton)button;
-(void) unmapKey:(AppleKeyboardKey)keyboardKey;
-(AppleKeyboardKey) getMappedKeyForControl:(KeyMapMappableButton)button;
+(NSString*) controlToDisplayName:(KeyMapMappableButton)button;
-(NSArray*) getControlsForMappedKey:(AppleKeyboardKey) keyboardKey;
@end

164
Common.iphone/KeyMapper.m Normal file
View File

@ -0,0 +1,164 @@
//
// KeyMapper.m
// activegs
//
// Created by Yoshi Sugawara on 4/9/16.
//
//
#import "KeyMapper.h"
@interface KeyMapper()
@property (nonatomic, strong) NSMutableDictionary *keyMapping;
@end
@implementation KeyMapper
-(void)loadFromDefaults {
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"keyMapping"];
if ( data == nil || ![data isKindOfClass:[NSData class]] ) {
self.keyMapping = [self defaultMapping];
} else {
NSDictionary *fetchedDict = [NSKeyedUnarchiver unarchiveObjectWithData:data];
self.keyMapping = [fetchedDict mutableCopy];
}
}
- (id)copyWithZone:(NSZone *)zone {
KeyMapper *copy = [[[self class] alloc] init];
copy.keyMapping = [self.keyMapping mutableCopy];
return copy;
}
-(NSMutableDictionary*) defaultMapping {
return [@{ [NSNumber numberWithInteger:MFI_BUTTON_X] : [NSNumber numberWithInteger:KEY_OPTION],
[NSNumber numberWithInteger:MFI_BUTTON_A] : [NSNumber numberWithInteger:KEY_APPLE],
[NSNumber numberWithInteger:ICADE_BUTTON_1] : [NSNumber numberWithInteger:KEY_OPTION],
[NSNumber numberWithInteger:ICADE_BUTTON_2] : [NSNumber numberWithInteger:KEY_APPLE]
} mutableCopy];
}
-(void) resetToDefaults {
self.keyMapping = [self defaultMapping];
}
-(void) saveKeyMapping {
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:self.keyMapping] forKey:@"keyMapping"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
-(void) mapKey:(AppleKeyboardKey)keyboardKey ToControl:(KeyMapMappableButton)button {
NSNumber *buttonKey = [NSNumber numberWithInteger:button];
[self.keyMapping setObject:[NSNumber numberWithInteger:keyboardKey] forKey:buttonKey];
}
-(void) unmapKey:(AppleKeyboardKey)keyboardKey {
NSArray *mappedButtons = [self getControlsForMappedKey:keyboardKey];
for (NSNumber *button in mappedButtons) {
[self.keyMapping removeObjectForKey:button];
}
}
-(AppleKeyboardKey) getMappedKeyForControl:(KeyMapMappableButton)button {
NSNumber *buttonKey = [NSNumber numberWithInteger:button];
NSNumber *mappedKey = [self.keyMapping objectForKey:buttonKey];
if ( mappedKey != nil ) {
return [mappedKey intValue];
} else {
return NSNotFound;
}
}
-(NSArray*) getControlsForMappedKey:(AppleKeyboardKey) keyboardKey {
NSMutableArray *foundControls = [NSMutableArray array];
for (NSNumber *buttonKey in self.keyMapping) {
NSNumber *mappedKey = [self.keyMapping objectForKey:buttonKey];
if ( mappedKey != nil && [mappedKey integerValue] == keyboardKey ) {
[foundControls addObject:buttonKey];
}
}
return foundControls;
}
+(NSString*) controlToDisplayName:(KeyMapMappableButton)button {
switch (button) {
case MFI_BUTTON_A:
return @"A";
break;
case MFI_BUTTON_B:
return @"B";
break;
case MFI_BUTTON_X:
return @"X";
break;
case MFI_BUTTON_Y:
return @"Y";
break;
case MFI_BUTTON_LS:
return @"LS";
break;
case MFI_BUTTON_LT:
return @"LT";
break;
case MFI_BUTTON_RS:
return @"RS";
break;
case MFI_BUTTON_RT:
return @"RT";
break;
case MFI_DPAD_UP:
return @"⬆️";
break;
case MFI_DPAD_DOWN:
return @"⬇️";
break;
case MFI_DPAD_LEFT:
return @"⬅️";
break;
case MFI_DPAD_RIGHT:
return @"➡️";
break;
case ICADE_BUTTON_1:
return @"i1";
break;
case ICADE_BUTTON_2:
return @"i2";
break;
case ICADE_BUTTON_3:
return @"i3";
break;
case ICADE_BUTTON_4:
return @"i4";
break;
case ICADE_BUTTON_5:
return @"i5";
break;
case ICADE_BUTTON_6:
return @"i6";
break;
case ICADE_BUTTON_7:
return @"i7";
break;
case ICADE_BUTTON_8:
return @"i8";
break;
case ICADE_DPAD_UP:
return @"i⬆";
break;
case ICADE_DPAD_DOWN:
return @"i⬇";
break;
case ICADE_DPAD_LEFT:
return @"i⬅";
break;
case ICADE_DPAD_RIGHT:
return @"i➡";
break;
default:
return @"?";
break;
}
}
@end

View File

@ -0,0 +1,37 @@
//
// PreviewUI.swift
// activegs
//
// Created by Yoshi Sugawara on 1/9/21.
//
import SwiftUI
struct ContentView: View {
var body: some View {
//Text("Hello, World!")
IntegratedController()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
Group {
ContentView().previewLayout(.fixed(width: 568, height: 320))
}
}
}
struct IntegratedController: UIViewControllerRepresentable {
func makeUIViewController(context: UIViewControllerRepresentableContext<IntegratedController>) -> EmulatorKeyboardController {
let controller = EmulatorKeyboardController()
controller.view.backgroundColor = .black
return controller
}
func updateUIViewController(_ uiViewController: EmulatorKeyboardController, context: UIViewControllerRepresentableContext<IntegratedController>) {
}
}

View File

@ -156,6 +156,8 @@ extern enum machineSpecsEnum machineSpecs;
-(void)setNotificationText:(NSString*) _text;
-(void)updateNotificationView:(CGRect) newRect;
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation;
- (void) showKeyRemapController;
@property(nonatomic,strong,getter=getEmulatorView) activegsEmulatorController* emulatorController;
@property(nonatomic,strong,getter=getBrowserView) ACTIVEGS_LAUNCHVIEWCONTROLLER* viewController;
@property(nonatomic,strong,getter=getInfoView) infoViewController* infoController;

View File

@ -13,6 +13,7 @@
#import <AudioToolbox/AudioToolbox.h>
#include "asynccommand.h"
#import <sys/utsname.h>
#import "GameControllerKeyRemapController.h"
// Application Singleton
activegsAppDelegate* pManager = nil;
@ -369,6 +370,16 @@ void x_init_persistent_path(MyString& hp)
[[pManager getBrowserView] updateView ];
// fonts!
for (NSString *family in [UIFont familyNames]) {
NSArray *fontNames = [UIFont fontNamesForFamilyName:family];
NSLog(@"Family: %@", family);
for (NSString *name in fontNames) {
NSLog(@"Font name: %@",name);
}
NSLog(@"");
}
[self.window makeKeyAndVisible];
#ifdef HANDLE_URL
@ -615,6 +626,10 @@ void x_init_persistent_path(MyString& hp)
}
- (void) showKeyRemapController {
GameControllerKeyRemapController *remapController = [[GameControllerKeyRemapController alloc] initWithNibName:@"GameControllerKeyRemapController" bundle:nil];
[self.viewController presentViewController:remapController animated:YES completion:nil];
}
- (void) screenDidConnect:(NSNotification *)notification
{

View File

@ -9,6 +9,8 @@
#import "../kegs/iOS/emulatorView.h"
#import "KBDController.h"
#import "ActiveGS-Swift.h"
enum gestureModes
{
@ -58,7 +60,7 @@ enum attachMode
ATTACH_SECONDARY
};
@interface activegsEmulatorController : UIVIEWCONTROLLERROOT
@interface activegsEmulatorController : UIVIEWCONTROLLERROOT<EmulatorKeyboardKeyPressedDelegate, EmulatorKeyboardModifierPressedDelegate>
{
@public
int attachedTo;
@ -74,7 +76,9 @@ enum attachMode
@property (nonatomic, strong) customView* contentView;
@property (nonatomic, strong) zoomEmulatorView* zv;
@property (nonatomic, strong) KBDController* kbdc ;
@property (nonatomic, strong) NSString* trackerName ;
@property (nonatomic, strong) EmulatorKeyboardController *emuKeyboardController;
@property (nonatomic, strong) DebugMemoryViewController *debugMemoryViewController;
@property (nonatomic, strong) NSString* trackerName;
@end

View File

@ -7,6 +7,11 @@
#import "activegsAppDelegate.h"
#include "../kegs/Src/protos_macdriver.h"
#include "../kegs/Src/sim65816.h"
#include "../kegs/Src/async_event.h"
#import "KeyMapper.h"
#import "ActiveGS-Swift.h"
#define TIME_BEFORE_REENABLING_GESTURES 1.0
#define TIME_BEFORE_DISABLING_GESTURES 0.5
@ -87,8 +92,21 @@ int x_lock_zoom = 0;
return curHit;
}
}
EmulatorKeyboardView *leftKeyboard = [pManager getEmulatorView].emuKeyboardController.leftKeyboardView;
p = [self convertPoint:_point toView:leftKeyboard];
curHit = [leftKeyboard hitTest:p withEvent:event];
if ([curHit isDescendantOfView:leftKeyboard]) {
return curHit;
}
EmulatorKeyboardView *rightKeyboard = [pManager getEmulatorView].emuKeyboardController.rightKeyboardView;
p = [self convertPoint:_point toView:rightKeyboard];
curHit = [rightKeyboard hitTest:p withEvent:event];
if ([curHit isDescendantOfView:rightKeyboard]) {
return curHit;
}
// renvoie les évenements à l'emulator
return [pManager getEmulatorView].zv;
}
@ -133,8 +151,6 @@ int x_lock_zoom = 0;
return self;
}
-(void)invalidateTimers
{
@ -413,7 +429,7 @@ int x_lock_zoom = 0;
attachedTo = ATTACH_NONE;
CGRect apprect = [[UIScreen mainScreen] applicationFrame];
CGRect apprect = [[UIScreen mainScreen] bounds];
printf("mainScreen apprect %d x %d\n",(int)apprect.size.width,(int)apprect.size.height);
self.contentView = [[customView alloc] initWithFrame:apprect];
@ -428,11 +444,19 @@ int x_lock_zoom = 0;
[self.zv setUserInteractionEnabled:TRUE];
self.kbdc = [KBDController alloc];
self.kbdc = [[KBDController alloc] initWithNibName:nil bundle:nil];
[self.contentView addSubview:self.kbdc.view];
self.emuKeyboardController = [[EmulatorKeyboardController alloc] init];
self.emuKeyboardController.leftKeyboardModel.delegate = self;
self.emuKeyboardController.leftKeyboardModel.modifierDelegate = self;
self.emuKeyboardController.rightKeyboardModel.delegate = self;
self.emuKeyboardController.rightKeyboardModel.modifierDelegate = self;
self.debugMemoryViewController = [[DebugMemoryViewController alloc] init];
self.debugMemoryViewController.modalPresentationStyle = UIModalPresentationFullScreen;
self.view = self.contentView;
[self.zv disableZoom];
}
@ -564,7 +588,7 @@ int x_lock_zoom = 0;
// l'interface est repositionnées mais non animée
CGRect uirectrotate = [[UIScreen mainScreen] applicationFrame];
CGRect uirectrotate = [[UIScreen mainScreen] bounds];
[self.kbdc updateView:uirectrotate];
[pManager updateNotificationView:uirectrotate];
@ -609,6 +633,18 @@ int x_lock_zoom = 0;
// Release any cached data, images, etc that aren't in use.
}
-(void)viewDidLoad {
[super viewDidLoad];
[self addChildViewController:self.emuKeyboardController];
self.emuKeyboardController.view.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.emuKeyboardController.view];
[[self.emuKeyboardController.view.topAnchor constraintEqualToAnchor:self.view.topAnchor] setActive:YES];
[[self.emuKeyboardController.view.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor] setActive:YES];
[[self.emuKeyboardController.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor] setActive:YES];
[[self.emuKeyboardController.view.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor] setActive:YES];
[self.emuKeyboardController didMoveToParentViewController:self];
[self.view bringSubviewToFront:self.emuKeyboardController.view];
}
-(void)viewWillAppear:(BOOL)animated
{
@ -681,4 +717,78 @@ int x_lock_zoom = 0;
self.zv.crt.hidden = (vfx==VIDEOFX_CRT?0:1);
}
#pragma mark - EmulatorKeyboardKeyPressedDelegate
-(void)keyDown:(id<KeyCoded>)key {
NSLog(@"key down: %li modifier: %i",(long)key.keyCode, self.emuKeyboardController.modifierState);
if (self.emuKeyboardController.modifierState & shiftKey) {
add_event_modifier(shiftKey);
}
add_event_key((int)key.keyCode, 0);
}
-(void)keyUp:(id<KeyCoded>)key {
if (key.keyCode == KEY_SPECIAL_DEBUGGER) {
[self presentViewController:self.debugMemoryViewController animated:true completion:nil];
return;
}
if (self.emuKeyboardController.modifierState & shiftKey) {
add_event_modifier(0);
}
add_event_key((int)key.keyCode, 1);
}
-(void)updateTransparencyToAlpha:(CGFloat)alpha {
self.emuKeyboardController.view.alpha = alpha;
}
#pragma mark - EmulatorKeyboardModifierPressedDelegate
-(void)modifierPressedWithKey:(id<KeyCoded>)key enable:(BOOL)enable {
int modifierKey;
if (key.keyCode == KEY_SHIFT) {
modifierKey = shiftKey;
} else if (key.keyCode == KEY_CTRL) {
modifierKey = controlKey;
} else if (key.keyCode == KEY_APPLE) {
modifierKey = cmdKey;
} else if (key.keyCode == KEY_OPTION) {
modifierKey = optionKey;
}
if (enable) {
self.emuKeyboardController.modifierState |= modifierKey;
[self keyDown:key];
} else {
[self keyUp:key];
self.emuKeyboardController.modifierState &= ~modifierKey;
}
}
-(BOOL)isModifierEnabledWithKey:(id<KeyCoded>)key {
BOOL enabled;
switch (key.keyCode) {
case KEY_SHIFT:
NSLog(@"shift modifier = %i",self.emuKeyboardController.modifierState);
enabled = self.emuKeyboardController.modifierState & shiftKey;
NSLog(@"shift modifier enabled? %@",enabled ? @"YES" : @"NO");
return enabled;
case KEY_CTRL:
NSLog(@"ctrl modifier = %i",self.emuKeyboardController.modifierState);
enabled = self.emuKeyboardController.modifierState & controlKey;
NSLog(@"ctrl modifier enabled? %@",enabled ? @"YES" : @"NO");
return enabled;
case KEY_APPLE:
NSLog(@"open-apple modifier = %i",self.emuKeyboardController.modifierState);
enabled = self.emuKeyboardController.modifierState & cmdKey;
NSLog(@"open-apple modifier enabled? %@",enabled ? @"YES" : @"NO");
return enabled;
case KEY_OPTION:
NSLog(@"closed-apple modifier = %i",self.emuKeyboardController.modifierState);
enabled = self.emuKeyboardController.modifierState & optionKey;
NSLog(@"closed-apple modifier enabled? %@",enabled ? @"YES" : @"NO");
return enabled;
default:
break;
}
return NO;
}
@end

View File

@ -226,17 +226,26 @@ static UIImage* defaultImageII = nil;
MyString slotstr;
slotstr.Format("%d",slot);
// Some games like Immortal expect 1 disk drive :(
// check if name contains "_1dd_"
BOOL isIIGSMultiMoreThanTwoDisks = slot != 6 && diskImages.count > 2;
NSRange rangeContaining1dd = [firstImage.name rangeOfString:@"_1dd_"];
if ( rangeContaining1dd.location != NSNotFound ) {
isIIGSMultiMoreThanTwoDisks = YES;
}
[diskImages enumerateObjectsUsingBlock:^(DiskImageInfo *diskImage, NSUInteger idx, BOOL * _Nonnull stop) {
unsigned long diskIndex = idx + 1;
if ( slot == 6 || isIIGSMultiMoreThanTwoDisks ) {
int slotNumber = (int) diskImage.slotNumber;
if ( slotNumber == 6 || isIIGSMultiMoreThanTwoDisks ) {
// for Apple II disks, assume 1 disk drive
// for Apple IIGS that have more than 2 disks, use 1 drive
diskIndex = 1;
}
tempXML += "<image slot=\"";
tempXML += slotstr;
MyString slotNumberStr;
slotNumberStr.Format("%d",slotNumber);
tempXML += slotNumberStr;
tempXML += [[NSString stringWithFormat:@"\" disk=\"%lu\">",diskIndex] UTF8String];
tempXML += [diskImage.name UTF8String];
tempXML += "</image>";
@ -247,7 +256,8 @@ static UIImage* defaultImageII = nil;
tempXML += "</config>";
};
for (NSString *s in fileList)
NSArray *sortedFileList = [fileList sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
for (NSString *s in sortedFileList)
{
const char* fn = [s UTF8String];
const char* ext = getext(fn);
@ -259,7 +269,8 @@ static UIImage* defaultImageII = nil;
&& strcasecmp(ext,"po")
&& strcasecmp(ext,"do")
&& strcasecmp(ext,"nib")
&& strcasecmp(ext,"bin"))
&& strcasecmp(ext,"bin")
&& strcasecmp(ext, "hdv"))
continue;
// si le fichier est dans la liste des blacklistée : ignore
@ -572,7 +583,26 @@ static NSInteger compareImagesUsingSelector(id p1, id p2, void *context)
{
NSLog(@"activeGSList viewWillAppear %@",self);
// Move files from Documents/Inbox to Documents (Items arriving through iOS "Open In"
NSLog(@"Moving files from Documents/Inbox to Documents so they're visible");
//Turn every file inside the directory into an array
// Note to self: remember to actually put files in the Documents folder. Use the code in the apparopriately marked file
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//strings to actually get the directories
NSString *appFolderPath = [path objectAtIndex:0];
NSString *inboxAppFolderPath = [appFolderPath stringByAppendingString:@"/Inbox"]; //add ".plist" to the end of the recipe name
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSArray *inboxContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[NSString stringWithFormat:inboxAppFolderPath, documentsDirectory] error:nil];
//move all the files over
for (int i = 0; i != [inboxContents count]; i++) {
NSString *oldPath = [NSString stringWithFormat:@"%@/%@", inboxAppFolderPath, [inboxContents objectAtIndex:i]];
NSString *newPath = [NSString stringWithFormat:@"%@/%@", appFolderPath, [inboxContents objectAtIndex:i]];
[[NSFileManager defaultManager] moveItemAtPath:oldPath toPath:newPath error:nil];
}
if (self.sourceName)
{
#ifndef ACTIVEGS_BACKGROUNDIMAGE
@ -608,6 +638,8 @@ static NSInteger compareImagesUsingSelector(id p1, id p2, void *context)
[self reloadData:NO];
UILayoutGuide *lg = self.view.safeAreaLayoutGuide;
NSLog(@"safe area layout guide: %@",NSStringFromCGRect(lg.layoutFrame));
}

BIN
Common.res/PrintChar21.ttf Normal file

Binary file not shown.

View File

@ -55,7 +55,7 @@ int messageLineVBL=0;
void x_async_refresh(CGContextRef myContext,CGRect myBoundingBox)
void x_async_refresh(CGContextRef myContext,CGRect myBoundingBox, CGImageRef *imageRef)
{
#ifdef ENABLEQD
@ -92,10 +92,17 @@ void x_async_refresh(CGContextRef myContext,CGRect myBoundingBox)
CGImageRef myImage = CGBitmapContextCreateImage((CGContextRef)g_kimage_offscreen.dev_handle);
CGContextDrawImage(myContext, myBoundingBox, myImage);// 6
*imageRef = CGBitmapContextCreateImage((CGContextRef)g_kimage_offscreen.dev_handle);
// Yoshi debugging: iOS 15 issue
// CGContextDrawImage draws a blank if the target rect width values in 233 ... 235
// Raw image size of screen is 704x221.
// Rect size here is 234.6667 x 77 for 3x retina size display (iPhone)
// Calling CGContextDrawImage using this rect results in a blank image
// width of 234.0 and 235.0 does not work
// adding 3 to the width here renders the image
CGRect newRect = CGRectMake(myBoundingBox.origin.x, myBoundingBox.origin.y, myBoundingBox.size.width + 3.0, myBoundingBox.size.height);
CGContextDrawImage(myContext, newRect, myImage);// 6
#ifndef VIDEO_SINGLEVLINE
if (r_sim65816.get_video_fx() == VIDEOFX_CRT)

View File

@ -1,9 +1,9 @@
/*
ActiveGS, Copyright 2004-2016 Olivier Goguel, https://github.com/ogoguel/ActiveGS
Based on Kegs, Copyright 2004 Kent Dickey, https://kegs.sourceforge.net
This code is covered by the GNU GPL licence
*/
/*
ActiveGS, Copyright 2004-2016 Olivier Goguel, https://github.com/ogoguel/ActiveGS
Based on Kegs, Copyright 2004 Kent Dickey, https://kegs.sourceforge.net
This code is covered by the GNU GPL licence
*/
#include "adb.h"
#include "moremem.h"
#include "paddles.h"
@ -1270,16 +1270,17 @@ update_mouse(int x, int y, int button_states, int buttons_valid)
mouse_compress_fifo(dcycs);
#if 0
//#if 0
printf("Update Mouse called with buttons:%d (state:%d) x,y:%d,%d, fifo:%d,%d, "
" a2: %d,%d\n", buttons_valid,button_states, x, y,
g_adb.g_mouse_fifo[0].x, g_mouse_fifo[0].y,
g_adb.g_mouse_fifo[0].x, g_adb.g_mouse_fifo[0].y,
g_adb.g_mouse_a2_x, g_adb.g_mouse_a2_y);
#endif
//#endif
if((buttons_valid == -1) &&(g_adb.g_warp_pointer==WARP_POINTER)) {
/* Warping the pointer causes it to jump here...this is not */
/* real motion, just update info and get out */
printf("yoshi debug doing warp pointer logic!\n");
g_adb.g_mouse_a2_x += (x - g_adb.g_mouse_fifo[0].x);
g_adb.g_mouse_a2_y += (y - g_adb.g_mouse_fifo[0].y);
g_adb.g_mouse_fifo[0].x = x;
@ -1287,11 +1288,11 @@ update_mouse(int x, int y, int button_states, int buttons_valid)
return 0;
}
#if 0
//#if 0
printf("...real move, warp: %d, %d, new x: %d, %d, a2:%d,%d\n",
g_adb.g_mouse_warp_x, g_adb.g_mouse_warp_y, g_adb.g_mouse_fifo[0].x,
g_adb.g_mouse_fifo[0].y, g_adb.g_mouse_a2_x, g_adb.g_mouse_a2_y);
#endif
//#endif
mouse_moved = (g_adb.g_mouse_fifo[0].x != x) || (g_adb.g_mouse_fifo[0].y != y);

View File

@ -9,7 +9,7 @@
#import <UIKit/UIKit.h>
#include <QuartzCore/CADisplayLink.h>
extern void x_async_refresh(CGContextRef myContext,CGRect r);
extern void x_async_refresh(CGContextRef myContext,CGRect r, CGImageRef *imageRef);
extern void add_event_key(int,int);
extern void add_event_mouse(int _x,int _y, int _state, int _button);
extern void add_event_modifier(unsigned int state) ;

View File

@ -86,8 +86,19 @@ void x_invalidrect()
{
CGContextRef g = UIGraphicsGetCurrentContext();
x_async_refresh(g,rect);
CGImageRef imageRef;
x_async_refresh(g,rect,&imageRef);
// // yoshi test...
// CGImageRef imgRef = CGBitmapContextCreateImage(g);
// UIImage *image = [UIImage imageWithCGImage:imgRef];
// CGImageRelease(imgRef);
// NSLog(@"yoshi buffer image = %@",image);
// if ( imageRef != nil ) {
// UIImage *image = [[UIImage alloc] initWithCGImage:imageRef];
// NSLog(@"yoshi debug: image = %@",image.description);
// CGContextDrawImage(g, CGRectMake(0, 0, 275, 77), imageRef);
// }
}

View File

@ -133,7 +133,7 @@ float refScaleLandscape;
self->viewSize = frame.size;
self->dpiRatio = ratio;
CGRect r = CGRectMake(0.0,0.0,X_A2_WINDOW_WIDTH/self->dpiRatio ,X_A2_WINDOW_HEIGHT/self->dpiRatio );
CGRect r = CGRectMake(0.0,0.0, X_A2_WINDOW_WIDTH/self->dpiRatio, X_A2_WINDOW_HEIGHT/self->dpiRatio );
self.contentSize = CGSizeMake(r.size.width,r.size.height);
[self.ew setFrame:r];
@ -552,6 +552,7 @@ float refScaleLandscape;
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
#ifdef ACTIVEGS
if ([[pManager getEmulatorView].kbdc myTouchesBegan:touches])
{
@ -626,7 +627,7 @@ float refScaleLandscape;
self.useTouch = touch;
lastMousePos = [self rotateTouch:touch];
NSLog(@"last mouse pos = %f , %f",lastMousePos.x, lastMousePos.y);
add_event_mouse(lastMousePos.x,lastMousePos.y,0,-1);
if (self.secondTouch)
@ -672,6 +673,7 @@ float refScaleLandscape;
{
debug_printf("touchesEnded : %d",[touches count]);
[super touchesEnded:touches withEvent:event];
#ifdef ACTIVEGS
if (! [[pManager getEmulatorView].kbdc myTouchesEnded:touches])
@ -750,7 +752,7 @@ float refScaleLandscape;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
// on est ici car lez zoom a démarré => théoriquement, il ne doit y avoir aucun useTouch, secondTouch, ou mouseDown
if ([touches containsObject:self.useTouch])
@ -800,6 +802,7 @@ float refScaleLandscape;
{
lastMousePos = [self rotateTouch:self.useTouch];
NSLog(@"touchesmoved: last mouse pos = %f , %f",lastMousePos.x, lastMousePos.y);
add_event_mouse(lastMousePos.x,lastMousePos.y,mouseDown,1);
}
}