mirror of
https://github.com/libretro/FBNeo.git
synced 2024-11-27 02:50:29 +00:00
Initial work on input pref. UI
This commit is contained in:
parent
7a2f8d9d62
commit
943a16b463
@ -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 */,
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
38
src/dep/macos/hid/AKGamepad.h
Normal file
38
src/dep/macos/hid/AKGamepad.h
Normal 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
|
237
src/dep/macos/hid/AKGamepad.m
Normal file
237
src/dep/macos/hid/AKGamepad.m
Normal 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];
|
||||
}
|
||||
}
|
21
src/dep/macos/hid/AKGamepadEventData.h
Normal file
21
src/dep/macos/hid/AKGamepadEventData.h
Normal 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
|
19
src/dep/macos/hid/AKGamepadEventData.m
Normal file
19
src/dep/macos/hid/AKGamepadEventData.m
Normal 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
|
56
src/dep/macos/hid/AKGamepadManager.h
Normal file
56
src/dep/macos/hid/AKGamepadManager.h
Normal 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
|
268
src/dep/macos/hid/AKGamepadManager.m
Normal file
268
src/dep/macos/hid/AKGamepadManager.m
Normal 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];
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user