Initial work on input pref. UI

This commit is contained in:
Akop Karapetyan 2021-05-31 02:18:34 -07:00
parent 7a2f8d9d62
commit 943a16b463
10 changed files with 939 additions and 13 deletions

View File

@ -1025,6 +1025,9 @@
FEC0A0E424ACDFBF0015AABF /* d_cischeat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEC0A0E324ACDFBE0015AABF /* d_cischeat.cpp */; };
FEC28FD1266471FE00EF37C2 /* d_redclash.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEC28FD0266471FE00EF37C2 /* d_redclash.cpp */; };
FEC28FD22664774B00EF37C2 /* Alloc.c in Sources */ = {isa = PBXBuildFile; fileRef = FE1B1DE323561A650065200C /* Alloc.c */; };
FEC28FE6266481BD00EF37C2 /* AKGamepad.m in Sources */ = {isa = PBXBuildFile; fileRef = FEC28FE0266481BD00EF37C2 /* AKGamepad.m */; };
FEC28FE7266481BD00EF37C2 /* AKGamepadManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FEC28FE2266481BD00EF37C2 /* AKGamepadManager.m */; };
FEC28FE8266481BD00EF37C2 /* AKGamepadEventData.m in Sources */ = {isa = PBXBuildFile; fileRef = FEC28FE3266481BD00EF37C2 /* AKGamepadEventData.m */; };
FEC5D3D6235C136F00ABA9FB /* FBVideo.mm in Sources */ = {isa = PBXBuildFile; fileRef = FEC5D3D5235C136F00ABA9FB /* FBVideo.mm */; };
FEC5D3D9235C160600ABA9FB /* FBScreenView.mm in Sources */ = {isa = PBXBuildFile; fileRef = FEC5D3D8235C160600ABA9FB /* FBScreenView.mm */; };
FED03ADE23FAF8E900E99A10 /* mdeeprom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FED03ADD23FAF8E900E99A10 /* mdeeprom.cpp */; };
@ -2622,6 +2625,12 @@
FEC0A0E124A6F99A0015AABF /* d_magmax.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = d_magmax.cpp; sourceTree = "<group>"; };
FEC0A0E324ACDFBE0015AABF /* d_cischeat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = d_cischeat.cpp; sourceTree = "<group>"; };
FEC28FD0266471FE00EF37C2 /* d_redclash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = d_redclash.cpp; sourceTree = "<group>"; };
FEC28FE0266481BD00EF37C2 /* AKGamepad.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AKGamepad.m; sourceTree = "<group>"; };
FEC28FE1266481BD00EF37C2 /* AKGamepadEventData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AKGamepadEventData.h; sourceTree = "<group>"; };
FEC28FE2266481BD00EF37C2 /* AKGamepadManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AKGamepadManager.m; sourceTree = "<group>"; };
FEC28FE3266481BD00EF37C2 /* AKGamepadEventData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AKGamepadEventData.m; sourceTree = "<group>"; };
FEC28FE4266481BD00EF37C2 /* AKGamepad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AKGamepad.h; sourceTree = "<group>"; };
FEC28FE5266481BD00EF37C2 /* AKGamepadManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AKGamepadManager.h; sourceTree = "<group>"; };
FEC5D3D4235C136E00ABA9FB /* FBVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBVideo.h; sourceTree = "<group>"; };
FEC5D3D5235C136F00ABA9FB /* FBVideo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FBVideo.mm; sourceTree = "<group>"; };
FEC5D3D7235C160600ABA9FB /* FBScreenView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBScreenView.h; sourceTree = "<group>"; };
@ -3291,6 +3300,7 @@
children = (
FE811001236B6B29000B5F73 /* generated */,
FE1B1DA923561A640065200C /* libs */,
FEC28FDE266481BD00EF37C2 /* macos */,
FEA5E79B23564A3200DA2D9D /* scripts */,
);
name = dep;
@ -5047,6 +5057,27 @@
path = scripts;
sourceTree = "<group>";
};
FEC28FDE266481BD00EF37C2 /* macos */ = {
isa = PBXGroup;
children = (
FEC28FDF266481BD00EF37C2 /* hid */,
);
path = macos;
sourceTree = "<group>";
};
FEC28FDF266481BD00EF37C2 /* hid */ = {
isa = PBXGroup;
children = (
FEC28FE0266481BD00EF37C2 /* AKGamepad.m */,
FEC28FE1266481BD00EF37C2 /* AKGamepadEventData.h */,
FEC28FE2266481BD00EF37C2 /* AKGamepadManager.m */,
FEC28FE3266481BD00EF37C2 /* AKGamepadEventData.m */,
FEC28FE4266481BD00EF37C2 /* AKGamepad.h */,
FEC28FE5266481BD00EF37C2 /* AKGamepadManager.h */,
);
path = hid;
sourceTree = "<group>";
};
FEDF04C325EB472400F3EDD9 /* m377 */ = {
isa = PBXGroup;
children = (
@ -6144,6 +6175,7 @@
FE1B267723561A770065200C /* d_taitob.cpp in Sources */,
FE556116258E95B600A19F2D /* filter_neon_intrinsics.c in Sources */,
FE1B24E923561A760065200C /* d_badlands.cpp in Sources */,
FEC28FE6266481BD00EF37C2 /* AKGamepad.m in Sources */,
FE1B243123561A750065200C /* Bra.c in Sources */,
FE1B250523561A760065200C /* d_shadfrce.cpp in Sources */,
FE1B268323561A770065200C /* pgm_crypt.cpp in Sources */,
@ -6238,6 +6270,7 @@
FE1B271023561A780065200C /* d_qbert.cpp in Sources */,
FE1B24B223561A750065200C /* d_m58.cpp in Sources */,
FE1B270023561A780065200C /* d_holeland.cpp in Sources */,
FEC28FE7266481BD00EF37C2 /* AKGamepadManager.m in Sources */,
FE1B261F23561A770065200C /* d_cps3.cpp in Sources */,
FE1B259523561A760065200C /* d_deco32.cpp in Sources */,
FE1B27D723561A790065200C /* mb87078.cpp in Sources */,
@ -6337,6 +6370,7 @@
FE1B24D623561A750065200C /* d_sailormn.cpp in Sources */,
FE1B267023561A770065200C /* d_superchs.cpp in Sources */,
FE2BC6B523615C3400B9D150 /* FBLogViewerController.m in Sources */,
FEC28FE8266481BD00EF37C2 /* AKGamepadEventData.m in Sources */,
FE1B25C623561A760065200C /* d_ddribble.cpp in Sources */,
FE1B254123561A760065200C /* d_blmbycar.cpp in Sources */,
FE1B244C23561A750065200C /* 7zCrcOpt.c in Sources */,

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15702" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15702"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17701"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -10,6 +10,8 @@
<connections>
<outlet property="contentTabView" destination="oE3-Es-MKD" id="sqi-Yy-NZ7"/>
<outlet property="dipswitchTableView" destination="Riy-Ok-IZT" id="eHL-jy-A8e"/>
<outlet property="inputDevicesPopUp" destination="sk8-nL-CMn" id="OXk-OX-Sl2"/>
<outlet property="inputTableView" destination="w2L-aO-5yK" id="ihu-7W-6d2"/>
<outlet property="restoreDipButton" destination="M0W-M1-aRD" id="dHM-Qp-shl"/>
<outlet property="toolbar" destination="EZn-6C-tNE" id="URm-K2-UMI"/>
<outlet property="window" destination="F0z-JX-Cv5" id="gIp-Ho-8D9"/>
@ -31,7 +33,7 @@
<font key="font" metaFont="system"/>
<tabViewItems>
<tabViewItem label="General" identifier="general" id="oxZ-d9-DIt" userLabel="General">
<view key="view" ambiguous="YES" id="SyU-Ly-vJE">
<view key="view" id="SyU-Ly-vJE">
<rect key="frame" x="0.0" y="0.0" width="600" height="400"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
@ -119,6 +121,99 @@
<view key="view" id="Mhd-ZC-Bf5">
<rect key="frame" x="0.0" y="0.0" width="600" height="400"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xuS-pz-eBX">
<rect key="frame" x="20" y="58" width="560" height="292"/>
<clipView key="contentView" id="0c0-5q-JyF">
<rect key="frame" x="1" y="0.0" width="558" height="291"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" headerView="Wtz-Wf-vp1" id="w2L-aO-5yK">
<rect key="frame" x="0.0" y="0.0" width="558" height="266"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<tableViewGridLines key="gridStyleMask" vertical="YES"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="name" editable="NO" width="116" minWidth="40" maxWidth="1000" id="dBb-jS-ggE">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Description">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="x2o-ck-FlS">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
</tableColumn>
<tableColumn identifier="button" width="436" minWidth="40" maxWidth="1000" id="cm7-Je-q9F">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Input">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="RVy-6E-fG0">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="-2" id="Yhb-c1-y7d"/>
</connections>
</tableView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="NR9-9S-oMc">
<rect key="frame" x="1" y="118" width="238" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="iFL-gb-AzT">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" id="Wtz-Wf-vp1">
<rect key="frame" x="0.0" y="0.0" width="558" height="25"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="sk8-nL-CMn">
<rect key="frame" x="18" y="356" width="238" height="25"/>
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="0tm-fT-5R6" id="U8O-di-wHm">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="Y2Y-JM-Sw9">
<items>
<menuItem title="Item 1" state="on" id="0tm-fT-5R6"/>
<menuItem title="Item 2" id="fCf-U6-KQR"/>
<menuItem title="Item 3" id="YhN-bC-pxZ"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="m7E-tJ-5pF">
<rect key="frame" x="452" y="13" width="134" height="32"/>
<buttonCell key="cell" type="push" title="Restore Default" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="DY5-3t-YRn">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
<constraints>
<constraint firstItem="xuS-pz-eBX" firstAttribute="leading" secondItem="Mhd-ZC-Bf5" secondAttribute="leading" constant="20" symbolic="YES" id="6n6-2V-YhZ"/>
<constraint firstItem="m7E-tJ-5pF" firstAttribute="leading" relation="lessThanOrEqual" secondItem="Mhd-ZC-Bf5" secondAttribute="leading" constant="458" id="B5y-sT-Q1k"/>
<constraint firstItem="sk8-nL-CMn" firstAttribute="top" secondItem="Mhd-ZC-Bf5" secondAttribute="top" constant="20" symbolic="YES" id="FzS-qG-FqT"/>
<constraint firstItem="xuS-pz-eBX" firstAttribute="top" secondItem="sk8-nL-CMn" secondAttribute="bottom" constant="9" id="Hgc-e2-r3D"/>
<constraint firstItem="m7E-tJ-5pF" firstAttribute="top" secondItem="xuS-pz-eBX" secondAttribute="bottom" constant="17" id="LZ3-6e-Nzk"/>
<constraint firstItem="sk8-nL-CMn" firstAttribute="leading" secondItem="Mhd-ZC-Bf5" secondAttribute="leading" constant="20" symbolic="YES" id="OWV-0G-6EQ"/>
<constraint firstAttribute="trailing" secondItem="m7E-tJ-5pF" secondAttribute="trailing" constant="20" symbolic="YES" id="Y8n-lb-eAN"/>
<constraint firstAttribute="trailing" secondItem="xuS-pz-eBX" secondAttribute="trailing" constant="20" symbolic="YES" id="iiQ-o0-T0e"/>
<constraint firstAttribute="bottom" secondItem="m7E-tJ-5pF" secondAttribute="bottom" constant="20" symbolic="YES" id="r4k-b5-efT"/>
<constraint firstAttribute="trailing" relation="lessThanOrEqual" secondItem="sk8-nL-CMn" secondAttribute="trailing" constant="347" id="rAB-BO-oWX"/>
</constraints>
</view>
</tabViewItem>
<tabViewItem label="DIP Switches" identifier="dipswitch" id="wN5-H3-IgF" userLabel="DipSwitches">
@ -126,14 +221,13 @@
<rect key="frame" x="0.0" y="0.0" width="600" height="400"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cXy-Hr-Spn">
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cXy-Hr-Spn">
<rect key="frame" x="20" y="145" width="560" height="235"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<clipView key="contentView" ambiguous="YES" id="EC8-81-kOL">
<clipView key="contentView" id="EC8-81-kOL">
<rect key="frame" x="1" y="0.0" width="558" height="234"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" ambiguous="YES" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" headerView="1qu-Rf-lqe" id="Riy-Ok-IZT">
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" headerView="1qu-Rf-lqe" id="Riy-Ok-IZT">
<rect key="frame" x="0.0" y="0.0" width="558" height="209"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="2"/>
@ -143,7 +237,6 @@
<tableColumns>
<tableColumn identifier="name" editable="NO" width="116" minWidth="40" maxWidth="1000" id="ZSY-Zi-utt">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Name">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
@ -156,7 +249,6 @@
</tableColumn>
<tableColumn identifier="value" width="179" minWidth="40" maxWidth="1000" id="xfd-ul-qQe">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Value">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
@ -193,9 +285,8 @@
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="M0W-M1-aRD">
<rect key="frame" x="437" y="97" width="149" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="M0W-M1-aRD">
<rect key="frame" x="452" y="97" width="134" height="32"/>
<buttonCell key="cell" type="push" title="Restore Default" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="pOb-rW-w6i">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -205,6 +296,15 @@
</connections>
</button>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="M0W-M1-aRD" secondAttribute="trailing" constant="20" symbolic="YES" id="0R7-hw-BGE"/>
<constraint firstAttribute="bottom" secondItem="M0W-M1-aRD" secondAttribute="bottom" constant="104" id="JyX-iP-MKz"/>
<constraint firstItem="cXy-Hr-Spn" firstAttribute="top" secondItem="Ojl-AF-gEP" secondAttribute="top" constant="20" symbolic="YES" id="PYT-KT-Ra4"/>
<constraint firstItem="cXy-Hr-Spn" firstAttribute="leading" secondItem="Ojl-AF-gEP" secondAttribute="leading" constant="20" symbolic="YES" id="RER-cn-iws"/>
<constraint firstAttribute="trailing" secondItem="cXy-Hr-Spn" secondAttribute="trailing" constant="20" symbolic="YES" id="Vzz-hq-T5M"/>
<constraint firstItem="M0W-M1-aRD" firstAttribute="leading" relation="lessThanOrEqual" secondItem="Ojl-AF-gEP" secondAttribute="leading" constant="458" id="Xeu-Ve-6SI"/>
<constraint firstItem="M0W-M1-aRD" firstAttribute="top" secondItem="cXy-Hr-Spn" secondAttribute="bottom" constant="20" symbolic="YES" id="pGw-7x-MbF"/>
</constraints>
</view>
</tabViewItem>
</tabViewItems>
@ -242,6 +342,7 @@
<defaultToolbarItems>
<toolbarItem reference="3CL-cj-z1N"/>
<toolbarItem reference="IgP-tm-58x"/>
<toolbarItem reference="DYc-Hq-yNp"/>
</defaultToolbarItems>
</toolbar>
<connections>

View File

@ -15,13 +15,16 @@
#import <Cocoa/Cocoa.h>
#import "FBMainThread.h"
#import "AKGamepadManager.h"
@interface FBPreferencesController : NSWindowController<NSTabViewDelegate, NSTableViewDataSource, FBMainThreadDelegate>
@interface FBPreferencesController : NSWindowController<NSTabViewDelegate, NSTableViewDataSource, FBMainThreadDelegate, AKGamepadEventDelegate>
{
IBOutlet NSToolbar *toolbar;
IBOutlet NSTabView *contentTabView;
IBOutlet NSTableView *dipswitchTableView;
IBOutlet NSTableView *inputTableView;
IBOutlet NSButton *restoreDipButton;
IBOutlet NSPopUpButton *inputDevicesPopUp;
}
- (IBAction) tabChanged:(id) sender;

View File

@ -19,17 +19,24 @@
@interface FBPreferencesController()
- (void) resetDipSwitches:(NSArray *) switches;
- (void) resetButtonList;
- (void) resetInputDevices;
@end
@implementation FBPreferencesController
{
NSArray<FBDipSetting *> *dipSwitches;
NSMutableArray<NSDictionary *> *_inputDeviceList;
NSMutableDictionary<NSString *, NSDictionary *> *_inputDeviceMap;
NSString *_selectedInputDeviceId;
}
- (id) init
{
if (self = [super initWithWindowNibName:@"Preferences"]) {
_inputDeviceList = [NSMutableArray new];
_inputDeviceMap = [NSMutableDictionary new];
}
return self;
@ -38,10 +45,32 @@
- (void) awakeFromNib
{
[self.runloop addObserver:self];
_selectedInputDeviceId = @"keyboard";
NSDictionary *kybd = @{ @"id": @"keyboard",
@"title": NSLocalizedString(@"Keyboard", @"Device") };
[_inputDeviceList addObject:kybd];
[_inputDeviceMap setObject:kybd
forKey:@"keyboard"];
AKGamepadManager *gm = AKGamepadManager.sharedInstance;
for (int i = 0, n = (int) gm.gamepadCount; i < n; i++) {
AKGamepad *gamepad = [gm gamepadAtIndex:i];
NSString *key = gamepad.vendorProductString;
NSDictionary *gp = @{ @"id": key,
@"title": gamepad.name };
[_inputDeviceList addObject:gp];
[_inputDeviceMap setObject:gp
forKey:key];
}
[self resetInputDevices];
[gm addObserver:self];
}
- (void) dealloc
{
[AKGamepadManager.sharedInstance removeObserver:self];
[self.runloop removeObserver:self];
}
@ -53,6 +82,81 @@
[self resetDipSwitches:[self.runloop dipSwitches]];
}
#pragma mark - AKGamepadDelegate
- (void) gamepadDidConnect:(AKGamepad *) gamepad
{
NSString *key = gamepad.vendorProductString;
@synchronized (_inputDeviceList) {
if (![_inputDeviceMap objectForKey:key]) {
NSDictionary *gp = @{ @"id": key,
@"title": gamepad.name };
[_inputDeviceMap setObject:gp
forKey:key];
[_inputDeviceList addObject:gp];
}
}
[self resetInputDevices];
}
- (void) gamepadDidDisconnect:(AKGamepad *) gamepad
{
NSString *key = gamepad.vendorProductString;
@synchronized (_inputDeviceList) {
NSDictionary *gp = [_inputDeviceMap objectForKey:key];
[_inputDeviceMap removeObjectForKey:key];
[_inputDeviceList removeObject:gp];
}
[self resetInputDevices];
}
- (void) gamepad:(AKGamepad *) gamepad
xChanged:(NSInteger) newValue
center:(NSInteger) center
eventData:(AKGamepadEventData *) eventData
{
// FIXME!!
// if ([[gamepad vendorProductString] isEqualToString:_selectedInputDeviceId]) {
// if ([[self window] firstResponder] == _joyCaptureView) {
// if (center - newValue > FXDeadzoneSize) {
// [_joyCaptureView captureCode:FXGamepadLeft];
// } else if (newValue - center > FXDeadzoneSize) {
// [_joyCaptureView captureCode:FXGamepadRight];
// }
// }
// }
}
- (void) gamepad:(AKGamepad *) gamepad
yChanged:(NSInteger) newValue
center:(NSInteger) center
eventData:(AKGamepadEventData *) eventData
{
// FIXME!!
// if ([[gamepad vendorProductString] isEqualToString:_selectedInputDeviceId]) {
// if ([[self window] firstResponder] == _joyCaptureView) {
// if (center - newValue > FXDeadzoneSize) {
// [_joyCaptureView captureCode:FXGamepadUp];
// } else if (newValue - center > FXDeadzoneSize) {
// [_joyCaptureView captureCode:FXGamepadDown];
// }
// }
// }
}
- (void) gamepad:(AKGamepad *) gamepad
button:(NSUInteger) index
isDown:(BOOL) isDown
eventData:(AKGamepadEventData *) eventData
{
// FIXME!!
// if ([[gamepad vendorProductString] isEqualToString:_selectedInputDeviceId]) {
// if ([[self window] firstResponder] == _joyCaptureView) {
// [_joyCaptureView captureCode:FXMakeButton(index)];
// }
// }
}
#pragma mark - Actions
- (void) tabChanged:(id) sender
@ -201,4 +305,49 @@ objectValueForTableColumn:(NSTableColumn *) tableColumn
[dipswitchTableView reloadData];
}
- (void) resetButtonList
{
[inputTableView abortEditing];
/* FIXME!!
NSInteger index = inputDevicesPopUp.indexOfSelectedItem;
if (index < _inputDeviceList.count) {
_selectedInputDeviceId = [[_inputDeviceList objectAtIndex:index] objectForKey:@"id"];
}
[_inputList removeAllObjects];
BOOL isKeyboard = [@"keyboard" isEqualToString:_selectedInputDeviceId];
FXEmulatorController *emulator = [[FXAppDelegate sharedInstance] emulator];
[[[emulator driver] buttons] enumerateObjectsUsingBlock:^(FXButton *b, NSUInteger idx, BOOL *stop) {
if (isKeyboard) {
FXButtonConfig *bc = [FXButtonConfig new];
[bc setName:[b name]];
[bc setTitle:[b title]];
[bc setVirtualCode:[b code]];
[_inputList addObject:bc];
} else if ([b playerIndex] == 1) {
FXButtonConfig *bc = [FXButtonConfig new];
[bc setName:[b name]];
[bc setTitle:[b neutralTitle]];
[bc setVirtualCode:[b code]];
[_inputList addObject:bc];
}
}];
[inputTableView setEnabled:[_inputList count] > 0];
[inputTableView reloadData];
*/
}
- (void) resetInputDevices
{
[inputDevicesPopUp removeAllItems];
[_inputDeviceList enumerateObjectsUsingBlock:^(NSDictionary *gp, NSUInteger idx, BOOL *stop) {
[inputDevicesPopUp addItemWithTitle:[gp objectForKey:@"title"]];
}];
[inputDevicesPopUp selectItemAtIndex:0]; // select the keyboard
[self resetButtonList];
}
@end

View File

@ -0,0 +1,38 @@
// Copyright (c) Akop Karapetyan
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import <Foundation/Foundation.h>
#import <IOKit/hid/IOHIDLib.h>
@interface AKGamepad : NSObject
@property (nonatomic, weak) id delegate;
@property (nonatomic, assign) NSInteger gamepadId;
@property (nonatomic, assign) NSUInteger index;
@property (nonatomic, readonly) NSInteger locationId;
@property (nonatomic, readonly) NSInteger vendorId;
@property (nonatomic, readonly) NSInteger productId;
@property (nonatomic, readonly) NSString *name;
- (id) initWithHidDevice:(IOHIDDeviceRef) device;
- (void) registerForEvents;
- (NSInteger) vendorProductId;
- (NSString *) vendorProductString;
- (NSMutableDictionary *) currentAxisValues;
@end

View File

@ -0,0 +1,237 @@
// Copyright (c) Akop Karapetyan
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "AKGamepad.h"
#import "AKGamepadManager.h"
#import <IOKit/hid/IOHIDLib.h>
#pragma mark - AKGamepad
static void gamepadInputValueCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value);
@interface AKGamepad()
- (void) unregisterFromEvents;
- (void) didReceiveInputValue:(IOHIDValueRef) valueRef;
@end
@implementation AKGamepad
{
BOOL registeredForEvents;
IOHIDDeviceRef hidDevice;
NSPoint _axes;
}
- (id) initWithHidDevice:(IOHIDDeviceRef) device
{
if ((self = [self init])) {
registeredForEvents = NO;
hidDevice = device;
IOObjectRetain((io_object_t) hidDevice);
_vendorId = 0;
_productId = 0;
_gamepadId = (NSInteger) device;
_axes = NSMakePoint(CGFLOAT_MIN, CGFLOAT_MIN);
CFTypeRef tCFTypeRef;
CFTypeID numericTypeId = CFNumberGetTypeID();
tCFTypeRef = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDVendorIDKey));
if (tCFTypeRef && CFGetTypeID(tCFTypeRef) == numericTypeId) {
CFNumberGetValue((CFNumberRef)tCFTypeRef, kCFNumberSInt32Type, &_vendorId);
}
tCFTypeRef = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductIDKey));
if (tCFTypeRef && CFGetTypeID(tCFTypeRef) == numericTypeId) {
CFNumberGetValue((CFNumberRef)tCFTypeRef, kCFNumberSInt32Type, &_productId);
}
tCFTypeRef = IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDLocationIDKey));
if (tCFTypeRef && CFGetTypeID(tCFTypeRef) == numericTypeId) {
CFNumberGetValue((CFNumberRef)tCFTypeRef, kCFNumberSInt32Type, &_locationId);
}
_name = (__bridge NSString *)IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductKey));
}
return self;
}
- (void) dealloc
{
[self unregisterFromEvents];
IOObjectRelease((io_object_t) hidDevice);
}
- (void) registerForEvents
{
if (!registeredForEvents) {
IOHIDDeviceOpen(hidDevice, kIOHIDOptionsTypeNone);
IOHIDDeviceRegisterInputValueCallback(hidDevice, gamepadInputValueCallback, (__bridge void *)(self));
registeredForEvents = YES;
if ([_delegate respondsToSelector:@selector(gamepadDidConnect:)]) {
[_delegate gamepadDidConnect:self];
}
}
}
- (void) unregisterFromEvents
{
if (registeredForEvents) {
// FIXME: why does this crash the emulator?
// IOHIDDeviceClose(hidDevice, kIOHIDOptionsTypeNone);
registeredForEvents = NO;
if ([_delegate respondsToSelector:@selector(gamepadDidDisconnect:)]) {
[_delegate gamepadDidDisconnect:self];
}
}
}
- (NSString *) vendorProductString
{
return [NSString stringWithFormat:@"%04lx:%04lx",
(long)[self vendorId], (long)[self productId]];
}
- (NSInteger) vendorProductId
{
return (_vendorId << 16) | _productId;
}
- (NSString *) description
{
return [NSString stringWithFormat:@"%@ (0x%04lx:0x%04lx)",
[self name], (long)[self vendorId], (long)[self productId]];
}
- (void) didReceiveInputValue:(IOHIDValueRef) valueRef
{
IOHIDElementRef element = IOHIDValueGetElement(valueRef);
NSInteger usagePage = IOHIDElementGetUsagePage(element);
NSInteger usage = IOHIDElementGetUsage(element);
NSInteger value = IOHIDValueGetIntegerValue(valueRef);
if (usagePage == kHIDPage_GenericDesktop) {
if (usage == kHIDUsage_GD_X) {
NSInteger min = IOHIDElementGetLogicalMin(element);
NSInteger max = IOHIDElementGetLogicalMax(element);
NSInteger center = (max + min) / 2;
NSInteger range = max - min;
if (labs(value) < range * .3) {
value = 0;
}
if (_axes.x != value) {
_axes.x = value;
if ([_delegate respondsToSelector:@selector(gamepad:xChanged:center:eventData:)]) {
AKGamepadEventData *eventData = [[AKGamepadEventData alloc] init];
[eventData setSourceId:IOHIDElementGetCookie(element)];
[_delegate gamepad:self
xChanged:value
center:center
eventData:eventData];
}
}
} else if (usage == kHIDUsage_GD_Y) {
NSInteger min = IOHIDElementGetLogicalMin(element);
NSInteger max = IOHIDElementGetLogicalMax(element);
NSInteger center = (max + min) / 2;
NSInteger range = max - min;
if (labs(value) < range * .3) {
value = 0;
}
if (_axes.y != value) {
_axes.y = value;
if ([_delegate respondsToSelector:@selector(gamepad:yChanged:center:eventData:)]) {
AKGamepadEventData *eventData = [[AKGamepadEventData alloc] init];
[eventData setSourceId:IOHIDElementGetCookie(element)];
[_delegate gamepad:self
yChanged:value
center:center
eventData:eventData];
}
}
}
} else if (usagePage == kHIDPage_Button) {
if ([_delegate respondsToSelector:@selector(gamepad:button:isDown:eventData:)]) {
AKGamepadEventData *eventData = [[AKGamepadEventData alloc] init];
[eventData setSourceId:IOHIDElementGetCookie(element)];
[_delegate gamepad:self
button:usage
isDown:(value & 1)
eventData:eventData];
}
}
}
- (NSMutableDictionary *) currentAxisValues
{
CFArrayRef elements = IOHIDDeviceCopyMatchingElements(hidDevice, NULL, kIOHIDOptionsTypeNone);
NSArray *elementArray = (__bridge NSArray *) elements;
NSMutableDictionary *axesAndValues = [[NSMutableDictionary alloc] init];
[elementArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
IOHIDElementRef element = (__bridge IOHIDElementRef) obj;
NSInteger usagePage = IOHIDElementGetUsagePage(element);
if (usagePage == kHIDPage_GenericDesktop) {
IOHIDElementType type = IOHIDElementGetType(element);
if (type == kIOHIDElementTypeInput_Misc || type == kIOHIDElementTypeInput_Axis) {
NSInteger usage = IOHIDElementGetUsage(element);
if (usage == kHIDUsage_GD_X || usage == kHIDUsage_GD_Y) {
IOHIDValueRef tIOHIDValueRef;
if (IOHIDDeviceGetValue(hidDevice, element, &tIOHIDValueRef) == kIOReturnSuccess) {
IOHIDElementCookie cookie = IOHIDElementGetCookie(element);
NSInteger integerValue = IOHIDValueGetIntegerValue(tIOHIDValueRef);
[axesAndValues setObject:@(integerValue)
forKey:@((NSInteger)cookie)];
}
}
}
}
}];
return axesAndValues;
}
@end
#pragma mark - IOHID C Callbacks
static void gamepadInputValueCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value)
{
@autoreleasepool {
[(__bridge AKGamepad *) context didReceiveInputValue:value];
}
}

View File

@ -0,0 +1,21 @@
// Copyright (c) Akop Karapetyan
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import <Foundation/Foundation.h>
@interface AKGamepadEventData : NSObject
@property (nonatomic, assign) NSInteger sourceId;
@end

View File

@ -0,0 +1,19 @@
// Copyright (c) Akop Karapetyan
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "AKGamepadEventData.h"
@implementation AKGamepadEventData
@end

View File

@ -0,0 +1,56 @@
// Copyright (c) Akop Karapetyan
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import <Foundation/Foundation.h>
#import <IOKit/hid/IOHIDLib.h>
#import "AKGamepad.h"
#import "AKGamepadEventData.h"
@protocol AKGamepadEventDelegate
@optional
- (void) gamepadDidConnect:(AKGamepad *) gamepad;
- (void) gamepadDidDisconnect:(AKGamepad *) gamepad;
- (void) gamepad:(AKGamepad *) gamepad
xChanged:(NSInteger) newValue
center:(NSInteger) center
eventData:(AKGamepadEventData *) eventData;
- (void) gamepad:(AKGamepad *) gamepad
yChanged:(NSInteger) newValue
center:(NSInteger) center
eventData:(AKGamepadEventData *) eventData;
- (void) gamepad:(AKGamepad *) gamepad
button:(NSUInteger) index
isDown:(BOOL) isDown
eventData:(AKGamepadEventData *) eventData;
@end
@interface AKGamepadManager : NSObject<AKGamepadEventDelegate>
+ (instancetype) sharedInstance;
- (AKGamepad *) gamepadWithId:(NSInteger) gamepadId;
- (AKGamepad *) gamepadAtIndex:(NSUInteger) index;
- (NSArray<AKGamepad *> *) allConnected;
- (NSUInteger) gamepadCount;
- (void) addObserver:(id<AKGamepadEventDelegate>) observer;
- (void) removeObserver:(id<AKGamepadEventDelegate>) observer;
@end

View File

@ -0,0 +1,268 @@
// Copyright (c) Akop Karapetyan
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "AKGamepadManager.h"
#import "AKGamepad.h"
#pragma mark - AKGamepadManager
void gamepadWasAdded(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef device);
void gamepadWasRemoved(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef device);
@interface AKGamepadManager ()
- (void) deviceDidConnect:(IOHIDDeviceRef) device;
- (void) deviceDidDisconnect:(IOHIDDeviceRef) device;
- (void) renumber:(BOOL) sort;
@end
@implementation AKGamepadManager
{
IOHIDManagerRef _hidManager;
NSMutableDictionary<NSNumber *, AKGamepad *> *_gamepadsByDeviceId;
NSMutableArray<AKGamepad *> *_allGamepads;
NSPointerArray *_observers;
}
+ (instancetype) sharedInstance
{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype) init
{
if ((self = [super init])) {
_gamepadsByDeviceId = [NSMutableDictionary dictionary];
_allGamepads = [NSMutableArray array];
_observers = [NSPointerArray weakObjectsPointerArray];
_hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
NSMutableDictionary *gamepadCriterion = [@{ (NSString *) CFSTR(kIOHIDDeviceUsagePageKey): @(kHIDPage_GenericDesktop),
(NSString *) CFSTR(kIOHIDDeviceUsageKey): @(kHIDUsage_GD_GamePad) } mutableCopy];
NSMutableDictionary *joystickCriterion = [@{ (NSString *) CFSTR(kIOHIDDeviceUsagePageKey): @(kHIDPage_GenericDesktop),
(NSString *) CFSTR(kIOHIDDeviceUsageKey): @(kHIDUsage_GD_Joystick) } mutableCopy];
IOHIDManagerSetDeviceMatchingMultiple(_hidManager, (__bridge CFArrayRef) @[ gamepadCriterion, joystickCriterion ]);
IOHIDManagerRegisterDeviceMatchingCallback(_hidManager, gamepadWasAdded, (__bridge void *) self);
IOHIDManagerRegisterDeviceRemovalCallback(_hidManager, gamepadWasRemoved, (__bridge void *) self);
IOHIDManagerScheduleWithRunLoop(_hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
return self;
}
- (void) dealloc
{
IOHIDManagerUnscheduleFromRunLoop(_hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
CFRelease(_hidManager);
}
- (void) deviceDidConnect:(IOHIDDeviceRef) device
{
AKGamepad *gamepad;
@synchronized (_gamepadsByDeviceId) {
gamepad = [[AKGamepad alloc] initWithHidDevice:device];
[_gamepadsByDeviceId setObject:gamepad
forKey:@([gamepad gamepadId])];
[_allGamepads addObject:gamepad];
[self renumber:YES];
[gamepad setDelegate:self];
}
[gamepad registerForEvents];
}
- (void) deviceDidDisconnect:(IOHIDDeviceRef) device
{
@synchronized (_gamepadsByDeviceId) {
AKGamepad *gamepad = [_gamepadsByDeviceId objectForKey:@((NSInteger) device)];
if (gamepad) {
[_gamepadsByDeviceId removeObjectForKey:@([gamepad gamepadId])];
[_allGamepads removeObjectAtIndex:[gamepad index]];
[self renumber:NO];
}
}
}
- (AKGamepad *) gamepadWithId:(NSInteger) gamepadId
{
return [_gamepadsByDeviceId objectForKey:@(gamepadId)];
}
- (AKGamepad *) gamepadAtIndex:(NSUInteger) index
{
AKGamepad *gp = nil;
if (index < [_allGamepads count]) {
gp = [_allGamepads objectAtIndex:index];
}
return gp;
}
- (NSUInteger) gamepadCount
{
return [_allGamepads count];
}
- (NSArray<AKGamepad *> *) allConnected
{
return [NSArray arrayWithArray:_allGamepads];
}
#pragma mark - AKGamepadDelegate
- (void) gamepadDidConnect:(AKGamepad *) gamepad
{
@synchronized (_observers) {
for (id delegate in _observers) {
if ([delegate respondsToSelector:_cmd]) {
[delegate gamepadDidConnect:gamepad];
}
}
}
}
- (void) gamepadDidDisconnect:(AKGamepad *) gamepad
{
@synchronized (_observers) {
for (id delegate in _observers) {
if ([delegate respondsToSelector:_cmd]) {
[delegate gamepadDidDisconnect:gamepad];
}
}
}
}
- (void) gamepad:(AKGamepad *) gamepad
xChanged:(NSInteger) newValue
center:(NSInteger) center
eventData:(AKGamepadEventData *) eventData
{
@synchronized (_observers) {
for (id delegate in _observers) {
if ([delegate respondsToSelector:_cmd]) {
[delegate gamepad:gamepad
xChanged:newValue
center:center
eventData:eventData];
}
}
}
}
- (void) gamepad:(AKGamepad *) gamepad
yChanged:(NSInteger) newValue
center:(NSInteger) center
eventData:(AKGamepadEventData *) eventData
{
@synchronized (_observers) {
for (id delegate in _observers) {
if ([delegate respondsToSelector:_cmd]) {
[delegate gamepad:gamepad
yChanged:newValue
center:center
eventData:eventData];
}
}
}
}
- (void) gamepad:(AKGamepad *) gamepad
button:(NSUInteger) index
isDown:(BOOL) isDown
eventData:(AKGamepadEventData *) eventData
{
@synchronized (_observers) {
for (id delegate in _observers) {
if ([delegate respondsToSelector:_cmd]) {
[delegate gamepad:gamepad
button:index
isDown:isDown
eventData:eventData];
}
}
}
}
- (void) addObserver:(id<AKGamepadEventDelegate>) observer
{
@synchronized (_observers) {
[_observers addPointer:(__bridge void * _Nullable)(observer)];
}
#ifdef DEBUG
NSLog(@"gamepadManager/addObserver");
#endif
}
- (void) removeObserver:(id<AKGamepadEventDelegate>) observer
{
void *remove = (__bridge void * _Nullable)(observer);
@synchronized (_observers) {
for (int i = (int) [_observers count] - 1; i >= 0; i--) {
void *ptr = [_observers pointerAtIndex:i];
if (ptr == remove || ptr == NULL) {
[_observers removePointerAtIndex:i];
}
}
}
#ifdef DEBUG
NSLog(@"gamepadManager/removeObserver");
#endif
}
#pragma mark - Private
- (void) renumber:(BOOL) sort
{
@synchronized (_allGamepads) {
if (sort) {
[_allGamepads sortUsingComparator:^NSComparisonResult(AKGamepad *gp1, AKGamepad *gp2) {
return [gp1 locationId] - [gp2 locationId];
}];
}
[_allGamepads enumerateObjectsUsingBlock:^(AKGamepad *gp, NSUInteger idx, BOOL * _Nonnull stop) {
[gp setIndex:idx];
}];
}
}
@end
#pragma mark - IOHID C Callbacks
void gamepadWasAdded(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef device)
{
@autoreleasepool {
[((__bridge AKGamepadManager *) inContext) deviceDidConnect:device];
}
}
void gamepadWasRemoved(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef device)
{
@autoreleasepool {
[((__bridge AKGamepadManager *) inContext) deviceDidDisconnect:device];
}
}