Compare commits

..
149 Commits
Author SHA1 Message Date
Diego Waxemberg 68f55235ec Bumping app version for v1.5.0 2017-10-17 21:28:30 -07:00
Cameron Gutman 5434b653c7 Reduce bitrate when streaming HEVC to reduce bandwidth at better IQ than H.264 2017-10-17 01:07:41 -07:00
Cameron Gutman 25d7af9453 Fix pairing and game quitting issues with GFE 3.10 2017-10-16 23:59:00 -07:00
Diego Waxemberg 5584083809 Bumping app version for 1.4.0 2017-09-23 21:48:22 -07:00
Cameron Gutman 9f9aec70b0 Add 1024x1024 app icon 2017-09-23 21:47:33 -07:00
Cameron Gutman a8d1770871 Fix Main Thread Checker safety issue in DataManager 2017-09-15 00:51:37 -07:00
Cameron Gutman d0d60b8ffc Suppress system gesture detection during streaming 2017-09-15 00:30:51 -07:00
Cameron Gutman 86f7112789 Adjust settings view for iPhone X 2017-09-14 23:12:52 -07:00
Cameron Gutman da1115e529 Disable reference frame invalidation for HEVC 2017-09-14 22:03:20 -07:00
Cameron Gutman 593da7ef3e Merge branch 'hevc' 2017-09-14 21:54:46 -07:00
Cameron Gutman de5377a95d Only use HEVC if the client has hardware-accelerated decoding 2017-09-14 19:50:53 -07:00
Cameron Gutman 7d7500b187 Suppress accidental movements during drags and clicks 2017-09-10 23:14:13 -07:00
Cameron Gutman 45dbd46da1 Fix mouse cursor jumping on right click gesture where only the 2nd finger is lifted to complete the gesture 2017-09-10 22:58:43 -07:00
Cameron Gutman 89d8bc6009 Fix icon changing between launch screen and main view controller 2017-09-10 22:22:32 -07:00
Cameron Gutman b99988836a Implement HEVC decoding for iOS 11 devices 2017-09-10 00:00:40 -07:00
Cameron Gutman 3e94613eb3 Update common-c 2017-09-02 19:48:09 -07:00
Cameron Gutman 832b9189f8 Fix mDNS overriding manually specified addresses 2017-09-02 19:47:47 -07:00
Cameron Gutman 3464539bd3 Make iconography consistent with other Moonlight clients 2017-09-02 14:54:19 -07:00
Cameron Gutman 815592117d Update common-c 2017-06-11 14:54:17 -07:00
Cameron Gutman b51341ef54 Update to latest moonlight-common-c 2017-06-11 13:36:23 -07:00
Cameron Gutman 9ffbb5f155 Update moonlight-common-c with latency and FEC improvements 2017-06-08 21:09:21 -07:00
Cameron Gutman 9716867ade Update moonlight-common-c 2017-06-05 22:27:15 -07:00
Diego Waxemberg 7c141c1fd2 Bumping version for 1.2.0 2017-05-11 22:36:28 -07:00
Cameron Gutman 42c4e7ca58 Enable reference frame invalidation 2017-05-11 20:46:09 -07:00
Cameron Gutman 6a6ea4a79a Update moonlight-common-c 2017-05-11 20:12:06 -07:00
Cameron Gutman 5d0ca8451d Fix active game not being set when returning from streaming 2017-05-07 23:32:31 -07:00
Cameron Gutman 4641f68eb8 Update common-c with critical FEC fixes 2017-05-07 23:16:00 -07:00
Cameron Gutman dd33f57b9a Fix display of pairing failure dialog when machine is streaming 2017-05-07 16:51:57 -07:00
Cameron Gutman f6b225ca9c Update common-c with FEC changes 2017-05-06 16:09:56 -07:00
Cameron Gutman 4ac3f11ff8 Ensure that OSC always has Player 1 reserved 2017-02-06 19:17:27 -08:00
Cameron Gutman 62aaf27293 Update to new common-c to show the correct number of controllers on the host PC 2017-02-04 20:16:18 -08:00
Diego Waxemberg eac2d985e2 Created build v1.1.4 and removed empty icon sets 2016-12-14 22:05:47 -08:00
Cameron Gutman 61ea7f3f1c Update moonlight-common-c with support for GFE 3.2 2016-12-13 21:29:03 -08:00
Cameron Gutman 40f7faa1b1 Update moonlight-common-c project to recommended settings on Xcode 8.1 2016-10-29 19:55:22 -07:00
Diego Waxemberg 9e18b8021b Bumping app version for v1.1.3 2016-10-26 19:08:33 -07:00
Cameron Gutman ce95f2c153 Fix some pairing glitches and add a cancel button 2016-10-21 12:07:29 -07:00
Cameron Gutman fd50b71b16 Fix detection of running apps on GFE 3.1 2016-10-21 11:41:42 -07:00
Diego Waxemberg 39ab472cf6 Updated to use swift 3 2016-10-05 23:45:48 -07:00
Diego Waxemberg 48ba7eb2dc Bump version for v1.1.2 2016-10-05 23:00:46 -07:00
Diego Waxemberg 42edaa1bad Added DerivedData to gitignore 2016-10-05 22:58:38 -07:00
Diego Waxemberg 955fb59156 Merge branch 'master' of github.com:moonlight-stream/moonlight-ios 2016-10-05 22:57:43 -07:00
Diego Waxemberg 2fbc67ef00 Bumped version for v1.1.1 2016-10-05 22:56:40 -07:00
Cameron Gutman 23564a3028 Add support for GFE 3.0.7 2016-10-05 17:32:30 -07:00
Cameron Gutman 9a07d5a33a Display an error if attempting to close another session's app rather than silently failing 2016-09-24 21:26:50 -07:00
Cameron Gutman 84c037f235 Move the pull arrow up to the top of the left side and make it clickable on the PC view page 2016-09-24 20:39:43 -07:00
Cameron Gutman c13df82f5b Update common-c to fix Gen 3 servers 2016-09-24 19:09:21 -07:00
Cameron Gutman b15d61a5bf Allow existing host to be updated via the Add PC dialog 2016-09-24 18:53:52 -07:00
Cameron Gutman 5aff719984 Add message to enable GameStream for GFE 3.0 2016-09-24 18:51:55 -07:00
Cameron Gutman b0c2978405 Update common-c submodule with const char * change 2016-07-31 17:10:32 -07:00
Cameron Gutman 91dcb505de Fix displaying names of custom added apps on GFE 3.0 2016-07-31 14:40:08 -07:00
Cameron Gutman d1f35d938b Apply Xcode 8 recommended project settings 2016-07-31 12:02:35 -07:00
Cameron Gutman 359b822951 Migrate to Swift 2.3 for Xcode 8 2016-07-31 12:00:09 -07:00
Cameron Gutman 39580e4352 Fix wiki link 2016-05-30 12:23:41 -05:00
Cameron Gutman 7b3d099449 Use the same Controller object for player 0 and the on-screen controls so tapping on-screen buttons doesn't reset all physical controller input to 0. Fixes pressing L3 to run in some games. 2016-05-22 17:11:30 -05:00
Cameron Gutman b17c45e9ca Update common-c to include MTU fix for LTE streaming 2016-05-21 21:32:36 -05:00
Cameron Gutman 4c7a2cecdd Allow the user to slide between directions on the d-pad. This closes #222 2016-05-08 15:42:08 -04:00
Cameron Gutman 175074ece8 Tweaks to dragging behavior to match Moonlight Android 2016-05-08 15:09:43 -04:00
Cameron Gutman 8a5ec513bf Update common-c 2016-05-08 14:59:08 -04:00
Cameron Gutman 7cfb7f73a2 Fix some WOL issues including crashes and broken functionality with DNS names 2016-05-08 14:56:22 -04:00
Cameron Gutman c608685737 Update common-c with bugfixes 2016-04-27 02:24:54 -04:00
Cameron Gutman 3beca2fc72 Update moonlight-common-c to fix a couple crashing bugs 2016-04-18 16:46:59 -04:00
Cameron Gutman c59aafb4bb Merge pull request #215 from Mimiste/master
Drag and drop
2016-04-18 14:02:07 -04:00
Mimiste 256e40acdc 1 Second touch for the drag and drop
Changed the timer duration to 1 second to initiate the drag and drop
2016-04-18 19:44:00 +02:00
Mimiste 39b1b65e16 Merge remote-tracking branch 'moonlight-stream/master' 2016-04-16 18:56:02 +02:00
Cameron Gutman 1783abec13 Lock around LiStartConnection() and LiStopConnection() to fix thread-safety issues. This will hopefully address the crashes seen in 1.0.3 and 1.0.4. 2016-04-12 00:50:59 -04:00
David 983c65d399 Rewrote the Controller class in Swift (#216)
* Enabled Defines Modules for swift code

* Created bridge header, created swift Controller

-  Created Controller.swift
-  Created bridge header for use of objc in swift

* Finished porting Controller files to swift

* Added comments, created MoonlightUnitTest

-  Added comments for Controller.swift
-  Created MoonlightUnitTest for testing new class

* Started writing tests for ControllerUnitTests

-  General formatting
-  Wrote helper functions
-  Wrote tests for first four properties

* Finished writing Controller tests

* Removed commented out lines
2016-04-11 20:44:02 -07:00
Mimiste 4caa9672c9 Drag and drop
The drag and drop is now enabled only if touching with one finger.
The tap to drop does not fire another timer
2016-04-10 13:02:00 +02:00
Mimiste 15be6a3f75 Merge remote-tracking branch 'moonlight-stream/master' 2016-04-10 11:48:30 +02:00
Michelle Bergeron d38eb0a3ba s/current/currently 2016-04-09 23:12:59 -07:00
Mimiste e8ea942ad2 Drag and drop
Possibility to initiate a drag and drop

- Touch for 2 second to initiate a drag
- Move the cursor as usual
- Tap top drop
2016-04-08 00:12:59 +02:00
Diego Waxemberg cb68b10475 Removed "Headers" build phase from common and created v1.0.4 2016-03-31 20:36:07 -07:00
Cameron Gutman 11c854ce44 Update common-c to support Gen 7 2016-03-31 11:27:02 -04:00
Cameron Gutman 9636f4742b Implement pairing for Gen 7 servers 2016-03-31 11:20:18 -04:00
Cameron Gutman 5867317526 Move the submodule and subproject to their new locations 2016-03-31 07:59:35 -04:00
Cameron Gutman 8a8f7b6903 Remove old submodule 2016-03-31 07:23:37 -04:00
Diego Waxemberg 61b6e25a91 Bumping app version for 1.0.3 2016-03-08 22:35:06 -08:00
Diego Waxemberg 50cff820de Added app icon for ipad pro 2016-03-08 22:34:15 -08:00
Cameron Gutman 4e586a28c8 Update common-c to fix RTSP timeout issue 2016-03-08 13:15:33 -08:00
Cameron Gutman 0702b4ed57 Fix a performance regression in handling the applist response 2016-03-07 16:12:10 -08:00
Cameron Gutman 4a2132a682 Update common-c to support GFE 2.11 2016-03-07 14:45:05 -08:00
Diego Waxemberg ba81d1d6a9 Bumping version and creating build 1.0.2 2016-02-19 13:08:01 -08:00
Cameron Gutman 402ce4b3ec Update common-c to support Gen 5 servers 2016-02-19 15:09:37 -05:00
Cameron Gutman fc713453ad Merge branch 'master' of github.com:moonlight-stream/moonlight-ios 2016-02-16 10:38:25 -05:00
Cameron Gutman b222ccffbb Fix analysis warning 2016-02-16 10:37:59 -05:00
Michelle Bergeron 56ce7329d2 Point to website, add wiki link. 2016-02-15 22:39:32 -08:00
Michelle Bergeron 99ab6db557 Added note about Apple TV in effort to stave off some emails 2016-02-07 21:53:55 -08:00
Cameron Gutman d7adf96f3a Newer GFE versions don't mind resuming another device's stream 2016-02-06 23:10:36 -05:00
Cameron Gutman 0ae58c61a9 Remove apps from the database when they are removed from the app list 2016-01-21 16:24:02 -05:00
Cameron Gutman 2ec7d1d2f1 Use the main queue for the managed object context as a hack to prevent merge conflicts 2016-01-21 16:17:05 -05:00
Cameron Gutman ad1b9059ee Ensure the host matches for app entries 2016-01-21 15:01:15 -05:00
Cameron Gutman 4439c7cce6 Fix initial app list loading after pairing 2016-01-21 14:14:29 -05:00
Cameron Gutman b8a4093c75 Preserve app art when updating the app list 2016-01-21 14:03:07 -05:00
Cameron Gutman ec3748b26e Implement hash and isEqual for TemporaryApp and TemporaryHost 2016-01-21 13:34:34 -05:00
Cameron Gutman 1c1f22e047 Update the database on each server info poll 2016-01-21 12:09:49 -05:00
Cameron Gutman 9aa9b0fc5a Copy the pair state into the temporary host 2016-01-21 11:42:19 -05:00
Cameron Gutman f8e2ca8500 We can't hold onto managed objects in our temporary objects because they can disappear from under us, so do the lookup when we propagate values 2016-01-21 11:29:17 -05:00
Cameron Gutman 3076e29335 Basic database access is working 2015-12-02 00:25:38 -08:00
Cameron Gutman fe616d86c5 Reduce usage of DataManager 2015-12-01 20:56:08 -08:00
Cameron Gutman bfa4856bbe Move non-CoreData backed fields out of CoreData objects 2015-12-01 20:36:08 -08:00
Cameron Gutman 5ea92a7b48 Stop using CoreData-backed objects in any non-DataManager code 2015-12-01 20:31:24 -08:00
Diego Waxemberg 4ba71db7b2 bumped build version 2015-11-14 13:07:31 -08:00
Diego Waxemberg c1e6aeb43c Merge branch 'master' of github.com:moonlight-stream/moonlight-ios 2015-11-14 12:33:44 -08:00
Diego Waxemberg e3ffb66ef0 bumping version code 2015-11-14 12:33:41 -08:00
Cameron Gutman 5daa82b0ba Show the hosts in alphabetical order rather than in an undefined order 2015-11-13 19:55:18 -08:00
Cameron Gutman a8bcc6afba Split the work into 2 jobs per computer to retrieve assets faster 2015-11-13 19:52:35 -08:00
Cameron Gutman e6aa16ad01 Revert "Fix concurrent modification crash in app asset caching code"
This reverts commit ad0705d126.
2015-11-13 19:07:15 -08:00
Cameron Gutman ad0705d126 Fix concurrent modification crash in app asset caching code 2015-11-13 18:30:12 -08:00
Cameron Gutman 2f31f93bf8 Add support for GFE 2.8 2015-11-11 18:24:36 -08:00
Cameron Gutman ea3be613c5 Try 5 times to get the app list before failing 2015-11-11 18:14:59 -08:00
Cameron Gutman b495246f34 Only mark a PC offline if server info failed after 3 straight tries 2015-11-11 18:14:04 -08:00
Cameron Gutman 814470f4bf Set the default bitrate based on the selected resolution and FPS combo 2015-11-11 18:11:33 -08:00
Cameron Gutman 82293a08b6 Increase the request timeout to 7 seconds to give a bit more time for slow app lists to come in 2015-11-11 17:53:13 -08:00
Cameron Gutman 20d66336a7 Cache decoded UIImage objects for the scroll view to fix janky scrolling 2015-11-10 21:23:00 -08:00
Cameron Gutman c8441ec9fa Rasterize the cell layer to increase scrolling performance 2015-11-10 20:48:39 -08:00
Cameron Gutman f72135c227 Mark collection cells opaque for better performance 2015-11-10 20:47:09 -08:00
Michelle Bergeron 100e6e4ce8 Remove info about the beta 2015-11-09 21:53:58 -08:00
Michelle Bergeron ec8be20d62 Download link 2015-11-09 21:53:24 -08:00
Diego Waxemberg 55d48101ef Bumped build version
This is the first attempt at submission to the App Store
2015-11-01 00:12:39 -07:00
Cameron Gutman c36f4c5f84 Remove abort calls 2015-10-31 23:45:37 -07:00
Diego Waxemberg 06289ac4d2 No longer use IDFA, now generate UUID and persist in Core Data. Bumped version to 1.0.0 2015-10-31 23:04:32 -07:00
Cameron Gutman e6a2d5d425 Update project file after Xcode 7.1 2015-10-31 19:00:44 -07:00
Cameron Gutman ea8db9c4ea Update common with new bitrate logic 2015-10-31 19:00:05 -07:00
Cameron Gutman 3773e841d1 Update common to support GFE 2.7 2015-10-25 13:28:24 -07:00
Diego Waxemberg ad1ddd04f3 no longer allow multiple apps to be selected at the same time 2015-10-18 16:52:14 -07:00
Diego Waxemberg 67a8b232b9 added pull arrow to side of screen 2015-10-17 16:16:13 -07:00
Diego Waxemberg 5293c07fc0 fixed issue where we wouldn't terminate the stream on failure 2015-10-17 03:46:09 -07:00
Diego Waxemberg e3a42db007 On-screen controls revamp
- controls are bigger
- dead zone around buttons to avoid accidental mouse clicks and movement
- finished implementing control setup for AutoGCGamepad
- swiping to close stream requires swipe to 1/4 the screen width
- no longer send mouse movement if delta is too small
2015-10-17 03:02:55 -07:00
Diego Waxemberg 3b1462af22 removed support for native resolution stream 2015-10-16 23:38:14 -07:00
Cameron Gutman 74a0c5b1cd Merge branch 'master' of github.com:moonlight-stream/moonlight-ios 2015-09-30 20:44:26 -07:00
Cameron Gutman 05a5e4fa64 Fix a crash when apps are removed from GFE 2015-09-30 20:44:14 -07:00
Cameron Gutman b6445295a7 Use a temporary app object and database lock to avoid saving while the database is not in a consistent state 2015-09-30 20:34:52 -07:00
Diego Waxemberg 391605ef36 ignored the new xcsmblueprint files 2015-09-30 19:18:21 -07:00
Diego Waxemberg 695499dea9 host and app buttons now have feedback when tapped 2015-09-30 19:13:37 -07:00
Cameron Gutman 9ba7f35444 Require full-screen since the streaming game will be the primary interaction for the device 2015-09-30 18:00:52 -07:00
Cameron Gutman 37dc00735b Enabling bit code is causing linker errors when deploying to real devices for some reason. Turning it back off. 2015-09-29 00:06:27 -07:00
Cameron Gutman 920cbadc91 Add a workaround/hack to fix duplicating machines 2015-09-29 00:04:40 -07:00
Cameron Gutman bc53b4dc32 First stab at fixing on screen controls on various devices 2015-09-28 23:20:27 -07:00
Cameron Gutman 6015c38d17 Only display the native resolution dialog if the user has just chosen native resolution. Make the dialog a little nicer too. 2015-09-28 22:50:54 -07:00
Cameron Gutman 4ea8694a7d Fix status bar hiding while streaming on iPad 2015-09-28 21:49:46 -07:00
Cameron Gutman 00f01196fb Update placeholder app images to be the correct aspect ratio and invert the colors to better show against the new background 2015-09-28 21:40:10 -07:00
Diego Waxemberg 543639c93e Merge branch 'master' of github.com:moonlight-stream/moonlight-ios 2015-09-28 21:19:18 -07:00
Diego Waxemberg 1da877fed7 Changed theme to light/dark gray and updated launch screen. Also added a border and drop shadow to app icons 2015-09-28 21:18:35 -07:00
Cameron Gutman 396b5fc156 Update common 2015-09-28 19:22:28 -07:00
Cameron Gutman 297dfd4159 Update project file
- Change organization name
- Enable bit code
- Update Xcode compatibility version
2015-09-28 19:09:49 -07:00
Cameron Gutman 23e9d48b0d Update common-c and use the new LiInitializeXXX() functions 2015-08-16 12:27:21 -07:00
Cameron Gutman 9ec650a84f Zero audio renderer callbacks before populating 2015-08-12 01:18:22 -07:00
Cameron Gutman 90bdbc4ae0 Update common library 2015-08-12 01:11:38 -07:00
Cameron Gutman dd5f06723b Update common library to get assertions and a GFE 2.5.11 fix 2015-07-20 17:37:13 -07:00
Michelle Bergeron 55b2871b83 Update about beta program 2015-07-16 16:14:28 -07:00
142 changed files with 3199 additions and 800 deletions

No files matched your search

+2
View File
@@ -1,2 +1,4 @@
**/xcuserdata/ **/xcuserdata/
**/Moonlight.xcscmblueprint
Build Build
DerivedData
+3 -3
View File
@@ -1,3 +1,3 @@
[submodule "limelight-common-c"] [submodule "moonlight-common/moonlight-common-c"]
path = limelight-common-c path = moonlight-common/moonlight-common-c
url = git@github.com:limelight-stream/limelight-common-c.git url = https://github.com/moonlight-stream/moonlight-common-c.git
+42 -27
View File
@@ -1,36 +1,51 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="8121.17" systemVersion="15A204h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="8191" systemVersion="15A279b" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8101.14"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
</dependencies> </dependencies>
<objects> <objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB"> <navigationController id="vV9-32-ww6">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/> <simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <navigationBar key="navigationBar" contentMode="scaleToFill" id="y2P-aE-Haa">
<subviews> <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 Moonlight Stream. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye"> <autoresizingMask key="autoresizingMask"/>
<rect key="frame" x="18" y="439.5" width="444" height="20.5"/> <animations/>
<animations/> <color key="barTintColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> </navigationBar>
<color key="textColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <viewControllers>
<nil key="highlightedColor"/> <viewController id="l6V-ue-5Om">
<variation key="widthClass=compact"> <layoutGuides>
<fontDescription key="fontDescription" type="system" pointSize="11"/> <viewControllerLayoutGuide type="top" id="rEZ-vx-akr"/>
</variation> <viewControllerLayoutGuide type="bottom" id="gBD-cy-cth"/>
</label> </layoutGuides>
</subviews> <view key="view" contentMode="scaleToFill" id="6lF-fc-kpK">
<animations/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <animations/>
<constraints> <color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Gnz-uJ-CDw"/> </view>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/> <navigationItem key="navigationItem" id="rW0-BH-s7l">
</constraints> <barButtonItem key="leftBarButtonItem" enabled="NO" id="d9R-Zo-Uml">
<nil key="simulatedStatusBarMetrics"/> <button key="customView" opaque="NO" contentMode="center" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="9JC-B5-BAE">
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> <rect key="frame" x="20" y="-1" width="109" height="46"/>
<point key="canvasLocation" x="404" y="445"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</view> <animations/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<state key="normal" title="Moonlight" image="Logo">
<color key="titleColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<color key="titleShadowColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
</state>
<variation key="widthClass=regular" preservesSuperviewLayoutMargins="NO"/>
</button>
</barButtonItem>
</navigationItem>
</viewController>
</viewControllers>
</navigationController>
</objects> </objects>
<resources>
<image name="Logo" width="32" height="32"/>
</resources>
</document> </document>
+13
View File
@@ -0,0 +1,13 @@
//
// AppCollectionView.h
// Moonlight
//
// Created by Diego Waxemberg on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface AppCollectionView : UICollectionView
@end
+28
View File
@@ -0,0 +1,28 @@
//
// AppCollectionView.m
// Moonlight
//
// Created by Diego Waxemberg on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "AppCollectionView.h"
@implementation AppCollectionView
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
if ([view isKindOfClass:[UIButton class]]) {
return YES;
}
return [super touchesShouldCancelInContentView:view];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end
+10 -30
View File
@@ -83,10 +83,7 @@ static NSOperationQueue* mainQueue;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext; NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) { if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately. Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
Log(LOG_E, @"Unresolved error %@, %@", error, [error userInfo]);
abort();
} }
} }
} }
@@ -136,32 +133,15 @@ static NSOperationQueue* mainQueue;
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) { if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
/* // Log the error
Replace this implementation with code to handle the error appropriately. Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. // Drop the database
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
Typical reasons for an error here include:
* The persistent store is not accessible; // Try again
* The schema for the persistent store is incompatible with current managed object model. return [self persistentStoreCoordinator];
Check the error message to determine what the actual problem was. }
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
@{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES}
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
Log(LOG_E, @"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator; return _persistentStoreCoordinator;
} }
+13
View File
@@ -0,0 +1,13 @@
//
// ComputerScrollView.h
// Moonlight
//
// Created by Diego Waxemberg on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ComputerScrollView : UIScrollView
@end
+28
View File
@@ -0,0 +1,28 @@
//
// ComputerScrollView.m
// Moonlight
//
// Created by Diego Waxemberg on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "ComputerScrollView.h"
@implementation ComputerScrollView
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
if ([view isKindOfClass:[UIButton class]]) {
return YES;
}
return [super touchesShouldCancelInContentView:view];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end
+3 -2
View File
@@ -11,15 +11,16 @@
@interface CryptoManager : NSObject @interface CryptoManager : NSObject
+ (void) generateKeyPairUsingSSl; + (void) generateKeyPairUsingSSl;
+ (NSString*) getUniqueID;
+ (NSData*) readCertFromFile; + (NSData*) readCertFromFile;
+ (NSData*) readKeyFromFile; + (NSData*) readKeyFromFile;
+ (NSData*) readP12FromFile; + (NSData*) readP12FromFile;
+ (NSData*) getSignatureFromCert:(NSData*)cert; + (NSData*) getSignatureFromCert:(NSData*)cert;
+ (NSData*) nullTerminateString:(NSData*)data; + (NSData*) nullTerminateString:(NSData*)data;
- (NSData*) createAESKeyFromSalt:(NSData*)saltedPIN; - (NSData*) createAESKeyFromSaltSHA1:(NSData*)saltedPIN;
- (NSData*) createAESKeyFromSaltSHA256:(NSData*)saltedPIN;
- (NSData*) SHA1HashData:(NSData*)data; - (NSData*) SHA1HashData:(NSData*)data;
- (NSData*) SHA256HashData:(NSData*)data;
- (NSData*) aesEncrypt:(NSData*)data withKey:(NSData*)key; - (NSData*) aesEncrypt:(NSData*)data withKey:(NSData*)key;
- (NSData*) aesDecrypt:(NSData*)data withKey:(NSData*)key; - (NSData*) aesDecrypt:(NSData*)data withKey:(NSData*)key;
- (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert; - (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert;
+16 -19
View File
@@ -8,7 +8,6 @@
#import "CryptoManager.h" #import "CryptoManager.h"
#import "mkcert.h" #import "mkcert.h"
#import <AdSupport/ASIdentifierManager.h>
#include <openssl/aes.h> #include <openssl/aes.h>
#include <openssl/sha.h> #include <openssl/sha.h>
@@ -17,19 +16,31 @@
#include <openssl/evp.h> #include <openssl/evp.h>
@implementation CryptoManager @implementation CryptoManager
static const int SHA1_DIGEST_LENGTH = 20; static const int SHA1_HASH_LENGTH = 20;
static const int SHA256_HASH_LENGTH = 32;
static NSData* key = nil; static NSData* key = nil;
static NSData* cert = nil; static NSData* cert = nil;
static NSData* p12 = nil; static NSData* p12 = nil;
- (NSData*) createAESKeyFromSalt:(NSData*)saltedPIN { - (NSData*) createAESKeyFromSaltSHA1:(NSData*)saltedPIN {
return [[self SHA1HashData:saltedPIN] subdataWithRange:NSMakeRange(0, 16)]; return [[self SHA1HashData:saltedPIN] subdataWithRange:NSMakeRange(0, 16)];
} }
- (NSData*) createAESKeyFromSaltSHA256:(NSData*)saltedPIN {
return [[self SHA256HashData:saltedPIN] subdataWithRange:NSMakeRange(0, 16)];
}
- (NSData*) SHA1HashData:(NSData*)data { - (NSData*) SHA1HashData:(NSData*)data {
unsigned char sha1[SHA1_DIGEST_LENGTH]; unsigned char sha1[SHA1_HASH_LENGTH];
SHA1([data bytes], [data length], sha1); SHA1([data bytes], [data length], sha1);
NSData* bytes = [NSData dataWithBytes:sha1 length:20]; NSData* bytes = [NSData dataWithBytes:sha1 length:sizeof(sha1)];
return bytes;
}
- (NSData*) SHA256HashData:(NSData*)data {
unsigned char sha256[SHA256_HASH_LENGTH];
SHA256([data bytes], [data length], sha256);
NSData* bytes = [NSData dataWithBytes:sha256 length:sizeof(sha256)];
return bytes; return bytes;
} }
@@ -229,18 +240,4 @@ static NSData* p12 = nil;
}); });
} }
+ (NSString*) getUniqueID {
// generate a UUID
NSUUID* uuid = [ASIdentifierManager sharedManager].advertisingIdentifier;
NSString* idString = [NSString stringWithString:[uuid UUIDString]];
// we need a 16byte hex-string so we take the last 17 characters
// and remove the '-' to get a 16 character string
NSMutableString* uniqueId = [NSMutableString stringWithString:[idString substringFromIndex:19]];
[uniqueId deleteCharactersInRange:NSMakeRange(4, 1)];
//Log(LOG_D, @"Unique ID: %@", uniqueId);
return [NSString stringWithString:uniqueId];
}
@end @end
+15
View File
@@ -0,0 +1,15 @@
//
// IdManager.h
// Moonlight
//
// Created by Diego Waxemberg on 10/31/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface IdManager : NSObject
+ (NSString*) getUniqueId;
@end
+32
View File
@@ -0,0 +1,32 @@
//
// IdManager.m
// Moonlight
//
// Created by Diego Waxemberg on 10/31/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "IdManager.h"
#import "DataManager.h"
@implementation IdManager
+ (NSString*) getUniqueId {
DataManager* dataMan = [[DataManager alloc] init];
NSString* uniqueId = [dataMan getUniqueId];
if (uniqueId == nil) {
uniqueId = [IdManager generateUniqueId];
[dataMan updateUniqueId:uniqueId];
Log(LOG_I, @"No UUID found. Generated new UUID: %@", uniqueId);
}
return uniqueId;
}
+ (NSString*) generateUniqueId {
UInt64 uuidLong = ((UInt64) arc4random() << 32) | arc4random();
return [NSString stringWithFormat:@"%016llx", uuidLong];
}
@end
-2
View File
@@ -85,7 +85,6 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
if (*pkeyp == NULL) { if (*pkeyp == NULL) {
if ((pk=EVP_PKEY_new()) == NULL) { if ((pk=EVP_PKEY_new()) == NULL) {
abort();
return(0); return(0);
} }
} else { } else {
@@ -102,7 +101,6 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL); rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
if (!EVP_PKEY_assign_RSA(pk, rsa)) { if (!EVP_PKEY_assign_RSA(pk, rsa)) {
abort();
goto err; goto err;
} }
-8
View File
@@ -11,16 +11,8 @@
@class Host; @class Host;
NS_ASSUME_NONNULL_BEGIN
@interface App : NSManagedObject @interface App : NSManagedObject
@property BOOL isRunning;
- (NSComparisonResult)compareName:(App *)other;
@end @end
NS_ASSUME_NONNULL_END
#import "App+CoreDataProperties.h" #import "App+CoreDataProperties.h"
-7
View File
@@ -7,14 +7,7 @@
// //
#import "App.h" #import "App.h"
#import "Host.h"
@implementation App @implementation App
@synthesize isRunning;
- (NSComparisonResult)compareName:(App *)other {
return [self.name caseInsensitiveCompare:other.name];
}
@end @end
+15 -12
View File
@@ -7,22 +7,25 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Settings.h"
#import "AppDelegate.h" #import "AppDelegate.h"
#import "Host.h" #import "TemporaryHost.h"
#import "App.h" #import "TemporaryApp.h"
#import "TemporarySettings.h"
@interface DataManager : NSObject @interface DataManager : NSObject
@property (strong, nonatomic) AppDelegate* appDelegate;
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls; - (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls;
- (Settings*) retrieveSettings;
- (NSArray*) retrieveHosts; - (NSArray*) getHosts;
- (void) saveData; - (void) updateHost:(TemporaryHost*)host;
- (Host*) createHost; - (void) updateAppsForExistingHost:(TemporaryHost *)host;
- (void) removeHost:(Host*)host; - (void) updateIconForExistingApp:(TemporaryApp*)app;
- (App*) createApp; - (void) removeHost:(TemporaryHost*)host;
- (void) removeApp:(App*)app; - (void) removeApp:(TemporaryApp*)app;
- (TemporarySettings*) getSettings;
- (void) updateUniqueId:(NSString*)uniqueId;
- (NSString*) getUniqueId;
@end @end
+176 -36
View File
@@ -7,37 +7,142 @@
// //
#import "DataManager.h" #import "DataManager.h"
#import "TemporaryApp.h"
#import "TemporarySettings.h"
#import "Settings.h"
@implementation DataManager @implementation DataManager {
NSManagedObjectContext *_managedObjectContext;
AppDelegate *_appDelegate;
}
- (id) init { - (id) init {
self = [super init]; self = [super init];
self.appDelegate = [[UIApplication sharedApplication] delegate];
// HACK: Avoid calling [UIApplication delegate] off the UI thread to keep
// Main Thread Checker happy.
if ([NSThread isMainThread]) {
_appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
}
else {
dispatch_sync(dispatch_get_main_queue(), ^{
_appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
});
}
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:_appDelegate.persistentStoreCoordinator];
return self; return self;
} }
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls { - (void) updateUniqueId:(NSString*)uniqueId {
Settings* settingsToSave = [self retrieveSettings]; [_managedObjectContext performBlockAndWait:^{
settingsToSave.framerate = [NSNumber numberWithInteger:framerate]; [self retrieveSettings].uniqueId = uniqueId;
// Bitrate is persisted in kbps [self saveData];
settingsToSave.bitrate = [NSNumber numberWithInteger:bitrate]; }];
settingsToSave.height = [NSNumber numberWithInteger:height]; }
settingsToSave.width = [NSNumber numberWithInteger:width];
settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls];
NSError* error; - (NSString*) getUniqueId {
if (![[self.appDelegate managedObjectContext] save:&error]) { __block NSString *uid;
Log(LOG_E, @"Unable to save settings to database: %@", error);
} [_managedObjectContext performBlockAndWait:^{
[self.appDelegate saveContext]; uid = [self retrieveSettings].uniqueId;
}];
return uid;
}
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls {
[_managedObjectContext performBlockAndWait:^{
Settings* settingsToSave = [self retrieveSettings];
settingsToSave.framerate = [NSNumber numberWithInteger:framerate];
// Bitrate is persisted in kbps
settingsToSave.bitrate = [NSNumber numberWithInteger:bitrate];
settingsToSave.height = [NSNumber numberWithInteger:height];
settingsToSave.width = [NSNumber numberWithInteger:width];
settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls];
[self saveData];
}];
}
- (void) updateHost:(TemporaryHost *)host {
[_managedObjectContext performBlockAndWait:^{
// Add a new persistent managed object if one doesn't exist
Host* parent = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
if (parent == nil) {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:_managedObjectContext];
parent = [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
}
// Push changes from the temp host to the persistent one
[host propagateChangesToParent:parent];
[self saveData];
}];
}
- (void) updateAppsForExistingHost:(TemporaryHost *)host {
[_managedObjectContext performBlockAndWait:^{
Host* parent = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
if (parent == nil) {
// The host must exist to be updated
return;
}
NSMutableSet *applist = [[NSMutableSet alloc] init];
NSArray *appRecords = [self fetchRecords:@"App"];
for (TemporaryApp* app in host.appList) {
// Add a new persistent managed object if one doesn't exist
App* parentApp = [self getAppForTemporaryApp:app withAppRecords:appRecords];
if (parentApp == nil) {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"App" inManagedObjectContext:_managedObjectContext];
parentApp = [[App alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
}
[app propagateChangesToParent:parentApp withHost:parent];
[applist addObject:parentApp];
}
parent.appList = applist;
[self saveData];
}];
}
- (void) updateIconForExistingApp:(TemporaryApp*)app {
[_managedObjectContext performBlockAndWait:^{
App* parentApp = [self getAppForTemporaryApp:app withAppRecords:[self fetchRecords:@"App"]];
if (parentApp == nil) {
// The app must exist to be updated
return;
}
parentApp.image = app.image;
[self saveData];
}];
}
- (TemporarySettings*) getSettings {
__block TemporarySettings *tempSettings;
[_managedObjectContext performBlockAndWait:^{
tempSettings = [[TemporarySettings alloc] initFromSettings:[self retrieveSettings]];
}];
return tempSettings;
} }
- (Settings*) retrieveSettings { - (Settings*) retrieveSettings {
NSArray* fetchedRecords = [self fetchRecords:@"Settings"]; NSArray* fetchedRecords = [self fetchRecords:@"Settings"];
if (fetchedRecords.count == 0) { if (fetchedRecords.count == 0) {
// create a new settings object with the default values // create a new settings object with the default values
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Settings" inManagedObjectContext:[self.appDelegate managedObjectContext]]; NSEntityDescription* entity = [NSEntityDescription entityForName:@"Settings" inManagedObjectContext:_managedObjectContext];
Settings* settings = [[Settings alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]]; Settings* settings = [[Settings alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
return settings; return settings;
} else { } else {
@@ -46,49 +151,84 @@
} }
} }
- (Host*) createHost { - (void) removeApp:(TemporaryApp*)app {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:[self.appDelegate managedObjectContext]]; [_managedObjectContext performBlockAndWait:^{
return [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]]; App* managedApp = [self getAppForTemporaryApp:app withAppRecords:[self fetchRecords:@"App"]];
if (managedApp != nil) {
[_managedObjectContext deleteObject:managedApp];
[self saveData];
}
}];
} }
- (void) removeHost:(Host*)host { - (void) removeHost:(TemporaryHost*)host {
[[self.appDelegate managedObjectContext] deleteObject:host]; [_managedObjectContext performBlockAndWait:^{
[self saveData]; Host* managedHost = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
if (managedHost != nil) {
[_managedObjectContext deleteObject:managedHost];
[self saveData];
}
}];
} }
- (void) saveData { - (void) saveData {
NSError* error; NSError* error;
if (![[self.appDelegate managedObjectContext] save:&error]) { if (![_managedObjectContext save:&error]) {
Log(LOG_E, @"Unable to save hosts to database: %@", error); Log(LOG_E, @"Unable to save hosts to database: %@", error);
} }
[self.appDelegate saveContext];
[_appDelegate saveContext];
} }
- (NSArray*) retrieveHosts { - (NSArray*) getHosts {
return [self fetchRecords:@"Host"]; __block NSMutableArray *tempHosts = [[NSMutableArray alloc] init];
[_managedObjectContext performBlockAndWait:^{
NSArray *hosts = [self fetchRecords:@"Host"];
for (Host* host in hosts) {
[tempHosts addObject:[[TemporaryHost alloc] initFromHost:host]];
}
}];
return tempHosts;
} }
- (App*) createApp { // Only call from within performBlockAndWait!!!
NSEntityDescription* entity = [NSEntityDescription entityForName:@"App" inManagedObjectContext:[self.appDelegate managedObjectContext]]; - (Host*) getHostForTemporaryHost:(TemporaryHost*)tempHost withHostRecords:(NSArray*)hosts {
return [[App alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]]; for (Host* host in hosts) {
if ([tempHost.uuid isEqualToString:host.uuid]) {
return host;
}
}
return nil;
} }
- (void) removeApp:(App*)app { // Only call from within performBlockAndWait!!!
[[self.appDelegate managedObjectContext] deleteObject:app]; - (App*) getAppForTemporaryApp:(TemporaryApp*)tempApp withAppRecords:(NSArray*)apps {
for (App* app in apps) {
if ([app.id isEqualToString:tempApp.id] &&
[app.host.uuid isEqualToString:app.host.uuid]) {
return app;
}
}
return nil;
} }
- (NSArray*) fetchRecords:(NSString*)entityName { - (NSArray*) fetchRecords:(NSString*)entityName {
NSArray* fetchedRecords;
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init]; NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription* entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:[self.appDelegate managedObjectContext]]; NSEntityDescription* entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:_managedObjectContext];
[fetchRequest setEntity:entity]; [fetchRequest setEntity:entity];
[fetchRequest setAffectedStores:[NSArray arrayWithObjects:[[self.appDelegate persistentStoreCoordinator] persistentStoreForURL:[self.appDelegate getStoreURL]], nil]];
NSError* error; NSError* error;
NSArray* fetchedRecords = [[self.appDelegate managedObjectContext] executeFetchRequest:fetchRequest error:&error]; fetchedRecords = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
//TODO: handle errors //TODO: handle errors
return fetchedRecords; return fetchedRecords;
} }
@end @end
-8
View File
@@ -10,16 +10,8 @@
#import <CoreData/CoreData.h> #import <CoreData/CoreData.h>
#import "Utils.h" #import "Utils.h"
NS_ASSUME_NONNULL_BEGIN
@interface Host : NSManagedObject @interface Host : NSManagedObject
@property (nonatomic) BOOL online;
@property (nonatomic) PairState pairState;
@property (nonatomic) NSString * activeAddress;
@end @end
NS_ASSUME_NONNULL_END
#import "Host+CoreDataProperties.h" #import "Host+CoreDataProperties.h"
-4
View File
@@ -10,8 +10,4 @@
@implementation Host @implementation Host
@dynamic pairState;
@synthesize online;
@synthesize activeAddress;
@end @end
+1
View File
@@ -17,5 +17,6 @@
@property (nonatomic, retain) NSNumber * height; @property (nonatomic, retain) NSNumber * height;
@property (nonatomic, retain) NSNumber * width; @property (nonatomic, retain) NSNumber * width;
@property (nonatomic, retain) NSNumber * onscreenControls; @property (nonatomic, retain) NSNumber * onscreenControls;
@property (nonatomic, retain) NSString * uniqueId;
@end @end
+1
View File
@@ -16,5 +16,6 @@
@dynamic height; @dynamic height;
@dynamic width; @dynamic width;
@dynamic onscreenControls; @dynamic onscreenControls;
@dynamic uniqueId;
@end @end
+30
View File
@@ -0,0 +1,30 @@
//
// TemporaryApp.h
// Moonlight
//
// Created by Cameron Gutman on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "TemporaryHost.h"
#import "App.h"
@interface TemporaryApp : NSObject
@property (nullable, nonatomic, retain) NSString *id;
@property (nullable, nonatomic, retain) NSData *image;
@property (nullable, nonatomic, retain) NSString *name;
@property (nullable, nonatomic, retain) TemporaryHost *host;
NS_ASSUME_NONNULL_BEGIN
- (id) initFromApp:(App*)app withTempHost:(TemporaryHost*)tempHost;
- (NSComparisonResult)compareName:(TemporaryApp *)other;
- (void) propagateChangesToParent:(App*)parent withHost:(Host*)host;
NS_ASSUME_NONNULL_END
@end
+52
View File
@@ -0,0 +1,52 @@
//
// TemporaryApp.m
// Moonlight
//
// Created by Cameron Gutman on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "TemporaryApp.h"
#import "App.h"
@implementation TemporaryApp
- (id) initFromApp:(App*)app withTempHost:(TemporaryHost*)tempHost {
self = [self init];
self.id = app.id;
self.image = app.image;
self.name = app.name;
self.host = tempHost;
return self;
}
- (void) propagateChangesToParent:(App*)parent withHost:(Host*)host {
parent.id = self.id;
parent.name = self.name;
parent.host = host;
}
- (NSComparisonResult)compareName:(TemporaryApp *)other {
return [self.name caseInsensitiveCompare:other.name];
}
- (NSUInteger)hash {
return [self.host.uuid hash] * 31 + [self.id intValue];
}
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[App class]]) {
return NO;
}
return [self.host.uuid isEqualToString:((App*)object).host.uuid] &&
[self.id isEqualToString:((App*)object).id];
}
@end
+38
View File
@@ -0,0 +1,38 @@
//
// TemporaryHost.h
// Moonlight
//
// Created by Cameron Gutman on 12/1/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Utils.h"
#import "Host.h"
@interface TemporaryHost : NSObject
@property (nonatomic) BOOL online;
@property (nonatomic) PairState pairState;
@property (nonatomic, nullable) NSString * activeAddress;
@property (nonatomic, nullable) NSString * currentGame;
NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, retain) NSString *address;
@property (nonatomic, retain) NSString *externalAddress;
@property (nonatomic, retain) NSString *localAddress;
@property (nonatomic, retain) NSString *mac;
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSString *uuid;
@property (nonatomic, retain) NSMutableSet *appList;
- (id) initFromHost:(Host*)host;
- (NSComparisonResult)compareName:(TemporaryHost *)other;
- (void) propagateChangesToParent:(Host*)host;
NS_ASSUME_NONNULL_END
@end
+78
View File
@@ -0,0 +1,78 @@
//
// TemporaryHost.m
// Moonlight
//
// Created by Cameron Gutman on 12/1/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "DataManager.h"
#import "TemporaryHost.h"
#import "Host.h"
#import "TemporaryApp.h"
#import "App.h"
@implementation TemporaryHost
- (id) init {
self = [super init];
self.appList = [[NSMutableSet alloc] init];
self.currentGame = @"0";
return self;
}
- (id) initFromHost:(Host*)host {
self = [self init];
self.address = host.address;
self.externalAddress = host.externalAddress;
self.localAddress = host.localAddress;
self.mac = host.mac;
self.name = host.name;
self.uuid = host.uuid;
self.pairState = [host.pairState intValue];
NSMutableSet *appList = [[NSMutableSet alloc] init];
for (App* app in host.appList) {
TemporaryApp *tempApp = [[TemporaryApp alloc] initFromApp:app withTempHost:self];
[appList addObject:tempApp];
}
self.appList = appList;
return self;
}
- (void) propagateChangesToParent:(Host*)parentHost {
parentHost.address = self.address;
parentHost.externalAddress = self.externalAddress;
parentHost.localAddress = self.localAddress;
parentHost.mac = self.mac;
parentHost.name = self.name;
parentHost.uuid = self.uuid;
parentHost.pairState = [NSNumber numberWithInt:self.pairState];
}
- (NSComparisonResult)compareName:(TemporaryHost *)other {
return [self.name caseInsensitiveCompare:other.name];
}
- (NSUInteger)hash {
return [self.uuid hash];
}
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[Host class]]) {
return NO;
}
return [self.uuid isEqualToString:((Host*)object).uuid];
}
@end
+25
View File
@@ -0,0 +1,25 @@
//
// TemporarySettings.h
// Moonlight
//
// Created by Cameron Gutman on 12/1/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Settings.h"
@interface TemporarySettings : NSObject
@property (nonatomic, retain) Settings * parent;
@property (nonatomic, retain) NSNumber * bitrate;
@property (nonatomic, retain) NSNumber * framerate;
@property (nonatomic, retain) NSNumber * height;
@property (nonatomic, retain) NSNumber * width;
@property (nonatomic, retain) NSNumber * onscreenControls;
@property (nonatomic, retain) NSString * uniqueId;
- (id) initFromSettings:(Settings*)settings;
@end
+28
View File
@@ -0,0 +1,28 @@
//
// TemporarySettings.m
// Moonlight
//
// Created by Cameron Gutman on 12/1/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "TemporarySettings.h"
@implementation TemporarySettings
- (id) initFromSettings:(Settings*)settings {
self = [self init];
self.parent = settings;
self.bitrate = settings.bitrate;
self.framerate = settings.framerate;
self.height = settings.height;
self.width = settings.width;
self.onscreenControls = settings.onscreenControls;
self.uniqueId = settings.uniqueId;
return self;
}
@end
+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "a_button_80x80@2x.png",
"filename" : "a_button_40x40@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "a_button_120x120@3x.png",
"filename" : "a_button_80x80@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "a_button_120x120@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

@@ -1,76 +1,108 @@
{ {
"images" : [ "images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{ {
"size" : "29x29", "size" : "29x29",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "app_icon_settings_58x58_@2x-1.png", "filename" : "Icon-App-29x29@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "29x29", "size" : "29x29",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "app_icon_settings_87x87_@3x.png", "filename" : "Icon-App-29x29@3x.png",
"scale" : "3x" "scale" : "3x"
}, },
{ {
"size" : "40x40", "size" : "40x40",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "app_icon_spotlight_80x80_@2x-1.png", "filename" : "Icon-App-40x40@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "40x40", "size" : "40x40",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "app_icon_spotlight_120x120_@3x.png", "filename" : "Icon-App-40x40@3x.png",
"scale" : "3x" "scale" : "3x"
}, },
{ {
"size" : "60x60", "size" : "60x60",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "app_icon_120x120_@2x.png", "filename" : "Icon-App-60x60@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "60x60", "size" : "60x60",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "app_icon_180x180_@3x.png", "filename" : "Icon-App-60x60@3x.png",
"scale" : "3x" "scale" : "3x"
}, },
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{ {
"size" : "29x29", "size" : "29x29",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "app_icon_settings_29x29_@1x.png", "filename" : "Icon-App-29x29@1x.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "29x29", "size" : "29x29",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "app_icon_settings_58x58_@2x.png", "filename" : "Icon-App-29x29@2x-1.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "40x40", "size" : "40x40",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "app_icon_spotlight_40x40_@1x.png", "filename" : "Icon-App-40x40@1x.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "40x40", "size" : "40x40",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "app_icon_spotlight_80x80_@2x.png", "filename" : "Icon-App-40x40@2x-1.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "76x76", "size" : "76x76",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "app_icon_76x76_@1x.png", "filename" : "Icon-App-76x76@1x.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "76x76", "size" : "76x76",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "app_icon_152x152_@2x.png", "filename" : "Icon-App-76x76@2x.png",
"scale" : "2x" "scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "1024x icon.png",
"scale" : "1x"
} }
], ],
"info" : { "info" : {
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "b_button_80x80@2x.png",
"filename" : "b_button_40x40@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "b_button_120x120@3x.png",
"filename" : "b_button_80x80@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "b_button_120x120@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

+6
View File
@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "down_61x75@2x.png",
"filename" : "down_31x38@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "down_93x114@3x.png",
"filename" : "down_61x75@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "down_93x114@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "left_76x61@2x.png",
"filename" : "left_38x31@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "left_114x92@3x.png",
"filename" : "left_76x61@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "left_114x92@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

+2 -2
View File
@@ -6,8 +6,8 @@
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "logo.png",
"filename" : "logo_universal.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "pull-arrow-light-14x31@1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "pull-arrow-light-28x61@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "pull-arrow-light-42x92@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "right_75x61@2x.png",
"filename" : "right_38x31@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "right_114x93@3x.png",
"filename" : "right_75x61@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "right_114x93@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "up_61x76@2x.png",
"filename" : "up_31x39@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "up_93x116@3x.png",
"filename" : "up_61x76@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "up_93x116@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "x_button_80x80@2x.png",
"filename" : "x_button_40x40@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "x_button_120x120@3x.png",
"filename" : "x_button_80x80@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "x_button_120x120@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "y_button_80x80@2x.png",
"filename" : "y_button_40x40@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "y_button_120x120@3x.png",
"filename" : "y_button_80x80@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "y_button_120x120@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

-23
View File
@@ -1,23 +0,0 @@
//
// Controller.h
// Moonlight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Controller : NSObject
@property (nonatomic) int playerIndex;
@property (nonatomic) int lastButtonFlags;
@property (nonatomic) int emulatingButtonFlags;
@property (nonatomic) char lastLeftTrigger;
@property (nonatomic) char lastRightTrigger;
@property (nonatomic) short lastLeftStickX;
@property (nonatomic) short lastLeftStickY;
@property (nonatomic) short lastRightStickX;
@property (nonatomic) short lastRightStickY;
@end
-15
View File
@@ -1,15 +0,0 @@
//
// Controller.m
// Moonlight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import "Controller.h"
@implementation Controller
@synthesize playerIndex;
@synthesize lastButtonFlags, emulatingButtonFlags, lastLeftTrigger, lastRightTrigger;
@synthesize lastLeftStickX, lastLeftStickY, lastRightStickX, lastRightStickY;
@end
+26
View File
@@ -0,0 +1,26 @@
//
// Controller.swift
// Moonlight
//
// Created by David Aghassi on 4/11/16.
// Copyright © 2016 Moonlight Stream. All rights reserved.
//
import Foundation
@objc
/**
Defines a controller layout
*/
class Controller: NSObject {
// Swift requires initial properties
var playerIndex: CInt = 0 // Controller number (e.g. 1, 2 ,3 etc)
var lastButtonFlags: CInt = 0
var emulatingButtonFlags: CInt = 0
var lastLeftTrigger: CChar = 0 // Last left trigger pressed
var lastRightTrigger: CChar = 0 // Last right trigger pressed
var lastLeftStickX: CShort = 0 // Last X direction the left joystick went
var lastLeftStickY: CShort = 0 // Last Y direction the left joystick went
var lastRightStickX: CShort = 0 // Last X direction the right joystick went
var lastRightStickY: CShort = 0 // Last Y direction the right joystick went
}
+5 -1
View File
@@ -7,7 +7,10 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Controller.h"
// Swift
#import "Moonlight-Swift.h"
@class Controller;
@class OnScreenControls; @class OnScreenControls;
@@ -29,6 +32,7 @@
-(void) clearButtonFlag:(Controller*)controller flags:(int)flags; -(void) clearButtonFlag:(Controller*)controller flags:(int)flags;
-(void) updateFinished:(Controller*)controller; -(void) updateFinished:(Controller*)controller;
-(Controller*) getOscController;
@property (nonatomic, strong) id connectObserver; @property (nonatomic, strong) id connectObserver;
@property (nonatomic, strong) id disconnectObserver; @property (nonatomic, strong) id disconnectObserver;
+26 -4
View File
@@ -8,9 +8,12 @@
#import "ControllerSupport.h" #import "ControllerSupport.h"
#import "OnScreenControls.h" #import "OnScreenControls.h"
#import "Controller.h"
#include "Limelight.h" #include "Limelight.h"
// Swift
#import "Moonlight-Swift.h"
@class Controller;
@import GameController; @import GameController;
@implementation ControllerSupport { @implementation ControllerSupport {
@@ -19,6 +22,10 @@
OnScreenControls *_osc; OnScreenControls *_osc;
// This controller object is shared between on-screen controls
// and player 0
Controller *_player0osc;
char _controllerNumbers; char _controllerNumbers;
#define EMULATING_SELECT 0x1 #define EMULATING_SELECT 0x1
@@ -139,7 +146,8 @@
{ {
[_controllerStreamLock lock]; [_controllerStreamLock lock];
@synchronized(controller) { @synchronized(controller) {
LiSendMultiControllerEvent(controller.playerIndex, controller.lastButtonFlags, controller.lastLeftTrigger, controller.lastRightTrigger, controller.lastLeftStickX, controller.lastLeftStickY, controller.lastRightStickX, controller.lastRightStickY); // Player 1 is always present for OSC
LiSendMultiControllerEvent(controller.playerIndex, _controllerNumbers | 1, controller.lastButtonFlags, controller.lastLeftTrigger, controller.lastRightTrigger, controller.lastLeftStickX, controller.lastLeftStickY, controller.lastRightStickX, controller.lastRightStickY);
} }
[_controllerStreamLock unlock]; [_controllerStreamLock unlock];
} }
@@ -272,9 +280,17 @@
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (!(_controllerNumbers & (1 << i))) { if (!(_controllerNumbers & (1 << i))) {
_controllerNumbers |= (1 << i); _controllerNumbers |= (1 << i);
Controller* limeController = [[Controller alloc] init];
controller.playerIndex = i; controller.playerIndex = i;
limeController.playerIndex = i;
Controller* limeController;
if (i == 0) {
// Player 0 shares a controller object with the on-screen controls
limeController = _player0osc;
} else {
limeController = [[Controller alloc] init];
limeController.playerIndex = i;
}
[_controllers setObject:limeController forKey:[NSNumber numberWithInteger:controller.playerIndex]]; [_controllers setObject:limeController forKey:[NSNumber numberWithInteger:controller.playerIndex]];
Log(LOG_I, @"Assigning controller index: %d", i); Log(LOG_I, @"Assigning controller index: %d", i);
@@ -283,6 +299,10 @@
} }
} }
-(Controller*) getOscController {
return _player0osc;
}
-(id) init -(id) init
{ {
self = [super init]; self = [super init];
@@ -290,6 +310,8 @@
_controllerStreamLock = [[NSLock alloc] init]; _controllerStreamLock = [[NSLock alloc] init];
_controllers = [[NSMutableDictionary alloc] init]; _controllers = [[NSMutableDictionary alloc] init];
_controllerNumbers = 0; _controllerNumbers = 0;
_player0osc = [[Controller alloc] init];
_player0osc.playerIndex = 0;
Log(LOG_I, @"Number of controllers connected: %ld", (long)[[GCController controllers] count]); Log(LOG_I, @"Number of controllers connected: %ld", (long)[[GCController controllers] count]);
for (GCController* controller in [GCController controllers]) { for (GCController* controller in [GCController controllers]) {
@@ -0,0 +1,4 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
+278 -95
View File
@@ -8,9 +8,12 @@
#import "OnScreenControls.h" #import "OnScreenControls.h"
#import "ControllerSupport.h" #import "ControllerSupport.h"
#import "Controller.h" //#import "Controller.h"
#include "Limelight.h" #include "Limelight.h"
#import "Moonlight-Swift.h"
@class Controller;
#define UPDATE_BUTTON(x, y) (buttonFlags = \ #define UPDATE_BUTTON(x, y) (buttonFlags = \
(y) ? (buttonFlags | (x)) : (buttonFlags & ~(x))) (y) ? (buttonFlags | (x)) : (buttonFlags & ~(x)))
@@ -41,10 +44,7 @@
UITouch* _bTouch; UITouch* _bTouch;
UITouch* _xTouch; UITouch* _xTouch;
UITouch* _yTouch; UITouch* _yTouch;
UITouch* _upTouch; UITouch* _dpadTouch;
UITouch* _downTouch;
UITouch* _leftTouch;
UITouch* _rightTouch;
UITouch* _lsTouch; UITouch* _lsTouch;
UITouch* _rsTouch; UITouch* _rsTouch;
UITouch* _startTouch; UITouch* _startTouch;
@@ -63,25 +63,30 @@
BOOL l3Set; BOOL l3Set;
BOOL r3Set; BOOL r3Set;
BOOL _iPad;
CGRect _controlArea;
UIView* _view; UIView* _view;
OnScreenControlsLevel _level; OnScreenControlsLevel _level;
ControllerSupport *_controllerSupport; ControllerSupport *_controllerSupport;
Controller *_controller; Controller *_controller;
id<EdgeDetectionDelegate> _edgeDelegate; id<EdgeDetectionDelegate> _edgeDelegate;
NSMutableArray* _deadTouches;
} }
static const float EDGE_WIDTH = .1; static const float EDGE_WIDTH = .05;
//static const float BUTTON_SIZE = 50; //static const float BUTTON_SIZE = 50;
static const float BUTTON_DIST = 20; static const float BUTTON_DIST = 20;
static float BUTTON_CENTER_X; static float BUTTON_CENTER_X;
static float BUTTON_CENTER_Y; static float BUTTON_CENTER_Y;
static const float D_PAD_DIST = 15; static const float D_PAD_DIST = 10;
static float D_PAD_CENTER_X; static float D_PAD_CENTER_X;
static float D_PAD_CENTER_Y; static float D_PAD_CENTER_Y;
static const float DEAD_ZONE_PADDING = 15;
static const double STICK_CLICK_RATE = 100; static const double STICK_CLICK_RATE = 100;
static const float STICK_DEAD_ZONE = .1; static const float STICK_DEAD_ZONE = .1;
static float STICK_INNER_SIZE; static float STICK_INNER_SIZE;
@@ -114,9 +119,23 @@ static float L3_Y;
self = [self init]; self = [self init];
_view = view; _view = view;
_controllerSupport = controllerSupport; _controllerSupport = controllerSupport;
_controller = [[Controller alloc] init]; _controller = [controllerSupport getOscController];
_controller.playerIndex = 0;
_edgeDelegate = swipeDelegate; _edgeDelegate = swipeDelegate;
_deadTouches = [[NSMutableArray alloc] init];
_iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
_controlArea = CGRectMake(0, 0, _view.frame.size.width, _view.frame.size.height);
if (_iPad)
{
// Cut down the control area on an iPad so the controls are more reachable
_controlArea.size.height = _view.frame.size.height / 2.0;
_controlArea.origin.y = _view.frame.size.height - _controlArea.size.height;
}
else
{
_controlArea.origin.x = _controlArea.size.width * EDGE_WIDTH;
_controlArea.size.width -= _controlArea.origin.x * 2;
}
_aButton = [CALayer layer]; _aButton = [CALayer layer];
_bButton = [CALayer layer]; _bButton = [CALayer layer];
@@ -139,7 +158,7 @@ static float L3_Y;
_leftStick = [CALayer layer]; _leftStick = [CALayer layer];
_rightStick = [CALayer layer]; _rightStick = [CALayer layer];
_edge = [CALayer layer]; _edge = [CALayer layer];
[self setupEdgeDetection]; [self setupEdgeDetection];
return self; return self;
@@ -167,10 +186,10 @@ static float L3_Y;
[self hideButtons]; [self hideButtons];
[self hideBumpers]; [self hideBumpers];
[self hideL3R3];
[self drawTriggers]; [self drawTriggers];
[self drawStartSelect]; [self drawStartSelect];
[self drawSticks]; [self drawSticks];
[self drawL3R3];
break; break;
case OnScreenControlsLevelAutoGCExtendedGamepad: case OnScreenControlsLevelAutoGCExtendedGamepad:
// GCExtendedGamepad is missing R3, L3, and select // GCExtendedGamepad is missing R3, L3, and select
@@ -219,8 +238,8 @@ static float L3_Y;
// Start with the default complex layout // Start with the default complex layout
[self setupComplexControls]; [self setupComplexControls];
START_Y = _view.frame.size.height * .9; START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_Y = _view.frame.size.height * .9; SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
} }
// For GCGamepad controls we move triggers, start, and select // For GCGamepad controls we move triggers, start, and select
@@ -229,7 +248,42 @@ static float L3_Y;
// Start with the default complex layout // Start with the default complex layout
[self setupComplexControls]; [self setupComplexControls];
// TODO START_X = _controlArea.size.width * .6 + _controlArea.origin.x;
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _controlArea.size.width * .4 + _controlArea.origin.x;
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L2_X = _controlArea.size.width * .1 + _controlArea.origin.x;
R2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
if (_iPad) {
START_X = _controlArea.size.width * .75 + _controlArea.origin.x;
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _controlArea.size.width * .25 + _controlArea.origin.x;
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
// The analog sticks are kept closer to the sides on iPad
LS_CENTER_X = _controlArea.size.width * .18 + _controlArea.origin.x;
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
RS_CENTER_X = _controlArea.size.width * .82 + _controlArea.origin.x;
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
} else {
START_X = _controlArea.size.width * .6 + _controlArea.origin.x;
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _controlArea.size.width * .4 + _controlArea.origin.x;
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
LS_CENTER_X = _controlArea.size.width * .25 + _controlArea.origin.x;
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
RS_CENTER_X = _controlArea.size.width * .75 + _controlArea.origin.x;
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
}
} }
// For simple controls we move the triggers and buttons to the bottom // For simple controls we move the triggers and buttons to the bottom
@@ -237,46 +291,59 @@ static float L3_Y;
// Start with the default complex layout // Start with the default complex layout
[self setupComplexControls]; [self setupComplexControls];
START_Y = _view.frame.size.height * .9; START_X = _controlArea.size.width * .6 + _controlArea.origin.x;
SELECT_Y = _view.frame.size.height * .9; START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _controlArea.size.width * .4 + _controlArea.origin.x;
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L2_X = _controlArea.size.width * .1 + _controlArea.origin.x;
L1_Y = _view.frame.size.height * .7; R2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L2_Y = _view.frame.size.height * .9; R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
L2_X = _view.frame.size.width * .1;
R1_Y = _view.frame.size.height * .7;
R2_Y = _view.frame.size.height * .9;
R2_X = _view.frame.size.width * .9;
} }
- (void) setupComplexControls - (void) setupComplexControls
{ {
D_PAD_CENTER_X = _view.frame.size.width * .15; D_PAD_CENTER_X = _controlArea.size.width * .1 + _controlArea.origin.x;
D_PAD_CENTER_Y = _view.frame.size.height * .55; D_PAD_CENTER_Y = _controlArea.size.height * .60 + _controlArea.origin.y;
BUTTON_CENTER_X = _view.frame.size.width * .85; BUTTON_CENTER_X = _controlArea.size.width * .9 + _controlArea.origin.x;
BUTTON_CENTER_Y = _view.frame.size.height * .55; BUTTON_CENTER_Y = _controlArea.size.height * .60 + _controlArea.origin.y;
LS_CENTER_X = _view.frame.size.width * .35; if (_iPad)
LS_CENTER_Y = _view.frame.size.height * .75; {
RS_CENTER_X = _view.frame.size.width * .65; // The analog sticks are kept closer to the sides on iPad
RS_CENTER_Y = _view.frame.size.height * .75; LS_CENTER_X = _controlArea.size.width * .22 + _controlArea.origin.x;
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
RS_CENTER_X = _controlArea.size.width * .77 + _controlArea.origin.x;
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
}
else
{
LS_CENTER_X = _controlArea.size.width * .35 + _controlArea.origin.x;
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
RS_CENTER_X = _controlArea.size.width * .65 + _controlArea.origin.x;
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
}
START_X = _view.frame.size.width * .6; START_X = _controlArea.size.width * .9 + _controlArea.origin.x;
START_Y = _view.frame.size.height * .1; START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _view.frame.size.width * .4; SELECT_X = _controlArea.size.width * .1 + _controlArea.origin.x;
SELECT_Y = _view.frame.size.height * .1; SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L1_X = _view.frame.size.width * .15; L1_X = _controlArea.size.width * .1 + _controlArea.origin.x;
L1_Y = _view.frame.size.height * .27; L1_Y = _controlArea.size.height * .27 + _controlArea.origin.y;
L2_X = _view.frame.size.width * .15; L2_X = _controlArea.size.width * .1 + _controlArea.origin.x;
L2_Y = _view.frame.size.height * .1; L2_Y = _controlArea.size.height * .1 + _controlArea.origin.y;
R1_X = _view.frame.size.width * .85; R1_X = _controlArea.size.width * .9 + _controlArea.origin.x;
R1_Y = _view.frame.size.height * .27; R1_Y = _controlArea.size.height * .27 + _controlArea.origin.y;
R2_X = _view.frame.size.width * .85; R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
R2_Y = _view.frame.size.height * .1; R2_Y = _controlArea.size.height * .1 + _controlArea.origin.y;
L3_X = _view.frame.size.width * .25; L3_X = _controlArea.size.width * .25 + _controlArea.origin.x;
L3_Y = _view.frame.size.height * .75; L3_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
R3_X = _view.frame.size.width * .75; R3_X = _controlArea.size.width * .75 + _controlArea.origin.x;
R3_Y = _view.frame.size.height * .75; R3_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
} }
- (void) drawButtons { - (void) drawButtons {
@@ -285,43 +352,43 @@ static float L3_Y;
_aButton.contents = (id) aButtonImage.CGImage; _aButton.contents = (id) aButtonImage.CGImage;
_aButton.frame = CGRectMake(BUTTON_CENTER_X - aButtonImage.size.width / 2, BUTTON_CENTER_Y + BUTTON_DIST, aButtonImage.size.width, aButtonImage.size.height); _aButton.frame = CGRectMake(BUTTON_CENTER_X - aButtonImage.size.width / 2, BUTTON_CENTER_Y + BUTTON_DIST, aButtonImage.size.width, aButtonImage.size.height);
[_view.layer addSublayer:_aButton]; [_view.layer addSublayer:_aButton];
// create B button // create B button
UIImage* bButtonImage = [UIImage imageNamed:@"BButton"]; UIImage* bButtonImage = [UIImage imageNamed:@"BButton"];
_bButton.frame = CGRectMake(BUTTON_CENTER_X + BUTTON_DIST, BUTTON_CENTER_Y - bButtonImage.size.height / 2, bButtonImage.size.width, bButtonImage.size.height); _bButton.frame = CGRectMake(BUTTON_CENTER_X + BUTTON_DIST, BUTTON_CENTER_Y - bButtonImage.size.height / 2, bButtonImage.size.width, bButtonImage.size.height);
_bButton.contents = (id) bButtonImage.CGImage; _bButton.contents = (id) bButtonImage.CGImage;
[_view.layer addSublayer:_bButton]; [_view.layer addSublayer:_bButton];
// create X Button // create X Button
UIImage* xButtonImage = [UIImage imageNamed:@"XButton"]; UIImage* xButtonImage = [UIImage imageNamed:@"XButton"];
_xButton.frame = CGRectMake(BUTTON_CENTER_X - BUTTON_DIST - xButtonImage.size.width, BUTTON_CENTER_Y - xButtonImage.size.height/ 2, xButtonImage.size.width, xButtonImage.size.height); _xButton.frame = CGRectMake(BUTTON_CENTER_X - BUTTON_DIST - xButtonImage.size.width, BUTTON_CENTER_Y - xButtonImage.size.height/ 2, xButtonImage.size.width, xButtonImage.size.height);
_xButton.contents = (id) xButtonImage.CGImage; _xButton.contents = (id) xButtonImage.CGImage;
[_view.layer addSublayer:_xButton]; [_view.layer addSublayer:_xButton];
// create Y Button // create Y Button
UIImage* yButtonImage = [UIImage imageNamed:@"YButton"]; UIImage* yButtonImage = [UIImage imageNamed:@"YButton"];
_yButton.frame = CGRectMake(BUTTON_CENTER_X - yButtonImage.size.width / 2, BUTTON_CENTER_Y - BUTTON_DIST - yButtonImage.size.height, yButtonImage.size.width, yButtonImage.size.height); _yButton.frame = CGRectMake(BUTTON_CENTER_X - yButtonImage.size.width / 2, BUTTON_CENTER_Y - BUTTON_DIST - yButtonImage.size.height, yButtonImage.size.width, yButtonImage.size.height);
_yButton.contents = (id) yButtonImage.CGImage; _yButton.contents = (id) yButtonImage.CGImage;
[_view.layer addSublayer:_yButton]; [_view.layer addSublayer:_yButton];
// create Down button // create Down button
UIImage* downButtonImage = [UIImage imageNamed:@"DownButton"]; UIImage* downButtonImage = [UIImage imageNamed:@"DownButton"];
_downButton.frame = CGRectMake(D_PAD_CENTER_X - downButtonImage.size.width / 2, D_PAD_CENTER_Y + D_PAD_DIST, downButtonImage.size.width, downButtonImage.size.height); _downButton.frame = CGRectMake(D_PAD_CENTER_X - downButtonImage.size.width / 2, D_PAD_CENTER_Y + D_PAD_DIST, downButtonImage.size.width, downButtonImage.size.height);
_downButton.contents = (id) downButtonImage.CGImage; _downButton.contents = (id) downButtonImage.CGImage;
[_view.layer addSublayer:_downButton]; [_view.layer addSublayer:_downButton];
// create Right button // create Right button
UIImage* rightButtonImage = [UIImage imageNamed:@"RightButton"]; UIImage* rightButtonImage = [UIImage imageNamed:@"RightButton"];
_rightButton.frame = CGRectMake(D_PAD_CENTER_X + D_PAD_DIST, D_PAD_CENTER_Y - rightButtonImage.size.height / 2, rightButtonImage.size.width, rightButtonImage.size.height); _rightButton.frame = CGRectMake(D_PAD_CENTER_X + D_PAD_DIST, D_PAD_CENTER_Y - rightButtonImage.size.height / 2, rightButtonImage.size.width, rightButtonImage.size.height);
_rightButton.contents = (id) rightButtonImage.CGImage; _rightButton.contents = (id) rightButtonImage.CGImage;
[_view.layer addSublayer:_rightButton]; [_view.layer addSublayer:_rightButton];
// create Up button // create Up button
UIImage* upButtonImage = [UIImage imageNamed:@"UpButton"]; UIImage* upButtonImage = [UIImage imageNamed:@"UpButton"];
_upButton.frame = CGRectMake(D_PAD_CENTER_X - upButtonImage.size.width / 2, D_PAD_CENTER_Y - D_PAD_DIST - upButtonImage.size.height, upButtonImage.size.width, upButtonImage.size.height); _upButton.frame = CGRectMake(D_PAD_CENTER_X - upButtonImage.size.width / 2, D_PAD_CENTER_Y - D_PAD_DIST - upButtonImage.size.height, upButtonImage.size.width, upButtonImage.size.height);
_upButton.contents = (id) upButtonImage.CGImage; _upButton.contents = (id) upButtonImage.CGImage;
[_view.layer addSublayer:_upButton]; [_view.layer addSublayer:_upButton];
// create Left button // create Left button
UIImage* leftButtonImage = [UIImage imageNamed:@"LeftButton"]; UIImage* leftButtonImage = [UIImage imageNamed:@"LeftButton"];
_leftButton.frame = CGRectMake(D_PAD_CENTER_X - D_PAD_DIST - leftButtonImage.size.width, D_PAD_CENTER_Y - leftButtonImage.size.height / 2, leftButtonImage.size.width, leftButtonImage.size.height); _leftButton.frame = CGRectMake(D_PAD_CENTER_X - D_PAD_DIST - leftButtonImage.size.width, D_PAD_CENTER_Y - leftButtonImage.size.height / 2, leftButtonImage.size.width, leftButtonImage.size.height);
@@ -335,7 +402,7 @@ static float L3_Y;
_startButton.frame = CGRectMake(START_X - startButtonImage.size.width / 2, START_Y - startButtonImage.size.height / 2, startButtonImage.size.width, startButtonImage.size.height); _startButton.frame = CGRectMake(START_X - startButtonImage.size.width / 2, START_Y - startButtonImage.size.height / 2, startButtonImage.size.width, startButtonImage.size.height);
_startButton.contents = (id) startButtonImage.CGImage; _startButton.contents = (id) startButtonImage.CGImage;
[_view.layer addSublayer:_startButton]; [_view.layer addSublayer:_startButton];
// create Select button // create Select button
UIImage* selectButtonImage = [UIImage imageNamed:@"SelectButton"]; UIImage* selectButtonImage = [UIImage imageNamed:@"SelectButton"];
_selectButton.frame = CGRectMake(SELECT_X - selectButtonImage.size.width / 2, SELECT_Y - selectButtonImage.size.height / 2, selectButtonImage.size.width, selectButtonImage.size.height); _selectButton.frame = CGRectMake(SELECT_X - selectButtonImage.size.width / 2, SELECT_Y - selectButtonImage.size.height / 2, selectButtonImage.size.width, selectButtonImage.size.height);
@@ -382,7 +449,7 @@ static float L3_Y;
_leftStick.frame = CGRectMake(LS_CENTER_X - leftStickImage.size.width / 2, LS_CENTER_Y - leftStickImage.size.height / 2, leftStickImage.size.width, leftStickImage.size.height); _leftStick.frame = CGRectMake(LS_CENTER_X - leftStickImage.size.width / 2, LS_CENTER_Y - leftStickImage.size.height / 2, leftStickImage.size.width, leftStickImage.size.height);
_leftStick.contents = (id) leftStickImage.CGImage; _leftStick.contents = (id) leftStickImage.CGImage;
[_view.layer addSublayer:_leftStick]; [_view.layer addSublayer:_leftStick];
// create right analog stick // create right analog stick
UIImage* rightStickBgImage = [UIImage imageNamed:@"StickOuter"]; UIImage* rightStickBgImage = [UIImage imageNamed:@"StickOuter"];
_rightStickBackground.frame = CGRectMake(RS_CENTER_X - rightStickBgImage.size.width / 2, RS_CENTER_Y - rightStickBgImage.size.height / 2, rightStickBgImage.size.width, rightStickBgImage.size.height); _rightStickBackground.frame = CGRectMake(RS_CENTER_X - rightStickBgImage.size.width / 2, RS_CENTER_Y - rightStickBgImage.size.height / 2, rightStickBgImage.size.width, rightStickBgImage.size.height);
@@ -463,7 +530,7 @@ static float L3_Y;
float lsMaxY = LS_CENTER_Y + STICK_OUTER_SIZE / 2; float lsMaxY = LS_CENTER_Y + STICK_OUTER_SIZE / 2;
float lsMinX = LS_CENTER_X - STICK_OUTER_SIZE / 2; float lsMinX = LS_CENTER_X - STICK_OUTER_SIZE / 2;
float lsMinY = LS_CENTER_Y - STICK_OUTER_SIZE / 2; float lsMinY = LS_CENTER_Y - STICK_OUTER_SIZE / 2;
for (UITouch* touch in touches) { for (UITouch* touch in touches) {
CGPoint touchLocation = [touch locationInView:_view]; CGPoint touchLocation = [touch locationInView:_view];
float xLoc = touchLocation.x; float xLoc = touchLocation.x;
@@ -473,35 +540,55 @@ static float L3_Y;
if (xLoc < lsMinX) xLoc = lsMinX; if (xLoc < lsMinX) xLoc = lsMinX;
if (yLoc > lsMaxY) yLoc = lsMaxY; if (yLoc > lsMaxY) yLoc = lsMaxY;
if (yLoc < lsMinY) yLoc = lsMinY; if (yLoc < lsMinY) yLoc = lsMinY;
_leftStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE); _leftStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
float xStickVal = (xLoc - LS_CENTER_X) / (lsMaxX - LS_CENTER_X); float xStickVal = (xLoc - LS_CENTER_X) / (lsMaxX - LS_CENTER_X);
float yStickVal = (yLoc - LS_CENTER_Y) / (lsMaxY - LS_CENTER_Y); float yStickVal = (yLoc - LS_CENTER_Y) / (lsMaxY - LS_CENTER_Y);
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0; if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0; if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
[_controllerSupport updateLeftStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal]; [_controllerSupport updateLeftStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
updated = true; updated = true;
} else if (touch == _rsTouch) { } else if (touch == _rsTouch) {
if (xLoc > rsMaxX) xLoc = rsMaxX; if (xLoc > rsMaxX) xLoc = rsMaxX;
if (xLoc < rsMinX) xLoc = rsMinX; if (xLoc < rsMinX) xLoc = rsMinX;
if (yLoc > rsMaxY) yLoc = rsMaxY; if (yLoc > rsMaxY) yLoc = rsMaxY;
if (yLoc < rsMinY) yLoc = rsMinY; if (yLoc < rsMinY) yLoc = rsMinY;
_rightStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE); _rightStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
float xStickVal = (xLoc - RS_CENTER_X) / (rsMaxX - RS_CENTER_X); float xStickVal = (xLoc - RS_CENTER_X) / (rsMaxX - RS_CENTER_X);
float yStickVal = (yLoc - RS_CENTER_Y) / (rsMaxY - RS_CENTER_Y); float yStickVal = (yLoc - RS_CENTER_Y) / (rsMaxY - RS_CENTER_Y);
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0; if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0; if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
[_controllerSupport updateRightStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal]; [_controllerSupport updateRightStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
updated = true; updated = true;
} else if (touch == _dpadTouch) {
[_controllerSupport clearButtonFlag:_controller
flags:UP_FLAG | DOWN_FLAG | LEFT_FLAG | RIGHT_FLAG];
// Allow the user to slide their finger to another d-pad button
if ([_upButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:UP_FLAG];
updated = true;
} else if ([_downButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG];
updated = true;
} else if ([_leftButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG];
updated = true;
} else if ([_rightButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG];
updated = true;
}
buttonTouch = true;
} else if (touch == _aTouch) { } else if (touch == _aTouch) {
buttonTouch = true; buttonTouch = true;
} else if (touch == _bTouch) { } else if (touch == _bTouch) {
@@ -510,14 +597,6 @@ static float L3_Y;
buttonTouch = true; buttonTouch = true;
} else if (touch == _yTouch) { } else if (touch == _yTouch) {
buttonTouch = true; buttonTouch = true;
} else if (touch == _upTouch) {
buttonTouch = true;
} else if (touch == _downTouch) {
buttonTouch = true;
} else if (touch == _leftTouch) {
buttonTouch = true;
} else if (touch == _rightTouch) {
buttonTouch = true;
} else if (touch == _startTouch) { } else if (touch == _startTouch) {
buttonTouch = true; buttonTouch = true;
} else if (touch == _selectTouch) { } else if (touch == _selectTouch) {
@@ -535,11 +614,14 @@ static float L3_Y;
} else if (touch == _r3Touch) { } else if (touch == _r3Touch) {
buttonTouch = true; buttonTouch = true;
} }
if ([_deadTouches containsObject:touch]) {
updated = true;
}
} }
if (updated) { if (updated) {
[_controllerSupport updateFinished:_controller]; [_controllerSupport updateFinished:_controller];
} }
return updated || buttonTouch; return updated || buttonTouch;
} }
- (BOOL)handleTouchDownEvent:touches { - (BOOL)handleTouchDownEvent:touches {
@@ -566,19 +648,19 @@ static float L3_Y;
updated = true; updated = true;
} else if ([_upButton.presentationLayer hitTest:touchLocation]) { } else if ([_upButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:UP_FLAG]; [_controllerSupport setButtonFlag:_controller flags:UP_FLAG];
_upTouch = touch; _dpadTouch = touch;
updated = true; updated = true;
} else if ([_downButton.presentationLayer hitTest:touchLocation]) { } else if ([_downButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG]; [_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG];
_downTouch = touch; _dpadTouch = touch;
updated = true; updated = true;
} else if ([_leftButton.presentationLayer hitTest:touchLocation]) { } else if ([_leftButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG]; [_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG];
_leftTouch = touch; _dpadTouch = touch;
updated = true; updated = true;
} else if ([_rightButton.presentationLayer hitTest:touchLocation]) { } else if ([_rightButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG]; [_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG];
_rightTouch = touch; _dpadTouch = touch;
updated = true; updated = true;
} else if ([_startButton.presentationLayer hitTest:touchLocation]) { } else if ([_startButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:PLAY_FLAG]; [_controllerSupport setButtonFlag:_controller flags:PLAY_FLAG];
@@ -653,6 +735,10 @@ static float L3_Y;
} else if ([_edge.presentationLayer hitTest:touchLocation]) { } else if ([_edge.presentationLayer hitTest:touchLocation]) {
_edgeTouch = touch; _edgeTouch = touch;
} }
if (!updated && !stickTouch && [self isInDeadZone:touch]) {
[_deadTouches addObject:touch];
updated = true;
}
} }
if (updated) { if (updated) {
[_controllerSupport updateFinished:_controller]; [_controllerSupport updateFinished:_controller];
@@ -680,21 +766,10 @@ static float L3_Y;
[_controllerSupport clearButtonFlag:_controller flags:Y_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:Y_FLAG];
_yTouch = nil; _yTouch = nil;
updated = true; updated = true;
} else if (touch == _upTouch) { } else if (touch == _dpadTouch) {
[_controllerSupport clearButtonFlag:_controller flags:UP_FLAG]; [_controllerSupport clearButtonFlag:_controller
_upTouch = nil; flags:UP_FLAG | DOWN_FLAG | LEFT_FLAG | RIGHT_FLAG];
updated = true; _dpadTouch = nil;
} else if (touch == _downTouch) {
[_controllerSupport clearButtonFlag:_controller flags:DOWN_FLAG];
_downTouch = nil;
updated = true;
} else if (touch == _leftTouch) {
[_controllerSupport clearButtonFlag:_controller flags:LEFT_FLAG];
_leftTouch = nil;
updated = true;
} else if (touch == _rightTouch) {
[_controllerSupport clearButtonFlag:_controller flags:RIGHT_FLAG];
_rightTouch = nil;
updated = true; updated = true;
} else if (touch == _startTouch) { } else if (touch == _startTouch) {
[_controllerSupport clearButtonFlag:_controller flags:PLAY_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:PLAY_FLAG];
@@ -744,15 +819,123 @@ static float L3_Y;
touched = true; touched = true;
} else if (touch == _edgeTouch) { } else if (touch == _edgeTouch) {
_edgeTouch = nil; _edgeTouch = nil;
if (![_edge.presentationLayer hitTest:[touch locationInView:_view]]) { if ([touch locationInView:_view].x >= _view.frame.size.width / 4) {
[_edgeDelegate edgeSwiped]; [_edgeDelegate edgeSwiped];
} }
} }
if ([_deadTouches containsObject:touch]) {
[_deadTouches removeObject:touch];
updated = true;
}
} }
if (updated) { if (updated) {
[_controllerSupport updateFinished:_controller]; [_controllerSupport updateFinished:_controller];
} }
return updated || touched; return updated || touched;
} }
- (BOOL) isInDeadZone:(UITouch*) touch {
switch (_level) {
case OnScreenControlsLevelFull:
return [self isDpadDeadZone:touch]
|| [self isAbxyDeadZone:touch]
|| [self isTriggerDeadZone:touch]
|| [self isBumperDeadZone:touch]
|| [self isStartSelectDeadZone:touch];
case OnScreenControlsLevelSimple:
return [self isTriggerDeadZone:touch]
|| [self isStartSelectDeadZone:touch]
|| [self isL3R3DeadZone:touch];
case OnScreenControlsLevelAutoGCExtendedGamepad:
return [self isL3R3DeadZone:touch]
|| [self isStartSelectDeadZone:touch];
case OnScreenControlsLevelAutoGCGamepad:
return [self isTriggerDeadZone:touch]
|| [self isStartSelectDeadZone:touch];
default:
return false;
}
}
- (BOOL) isDpadDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_upButton.frame.origin.y
endX:_rightButton.frame.origin.x + _rightButton.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isAbxyDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_xButton.frame.origin.x
startY:_yButton.frame.origin.y
endX:_view.frame.origin.x + _view.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isBumperDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_l2Button.frame.origin.y + _l2Button.frame.size.height
endX:_l1Button.frame.origin.x + _l1Button.frame.size.width
endY:_upButton.frame.origin.y]
|| [self isDeadZone:touch
startX:_r2Button.frame.origin.x
startY:_r2Button.frame.origin.y + _r2Button.frame.size.height
endX:_view.frame.origin.x + _view.frame.size.width
endY:_yButton.frame.origin.y];
}
- (BOOL) isTriggerDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_l2Button.frame.origin.y
endX:_l2Button.frame.origin.x + _l2Button.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height]
|| [self isDeadZone:touch
startX:_r2Button.frame.origin.x
startY:_r2Button.frame.origin.y
endX:_view.frame.origin.x + _view.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isL3R3DeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_l3Button.frame.origin.y
endX:_view.frame.origin.x
endY:_view.frame.origin.y + _view.frame.size.height]
|| [self isDeadZone:touch
startX:_r3Button.frame.origin.x
startY:_r3Button.frame.origin.y
endX:_view.frame.origin.x + _view.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isStartSelectDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_startButton.frame.origin.x
startY:_startButton.frame.origin.y
endX:_view.frame.origin.x + _view.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height]
|| [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_selectButton.frame.origin.y
endX:_selectButton.frame.origin.x + _selectButton.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isDeadZone:(UITouch*) touch startX:(float)deadZoneStartX startY:(float)deadZoneStartY endX:(float)deadZoneEndX endY:(float)deadZoneEndY {
deadZoneStartX -= DEAD_ZONE_PADDING;
deadZoneStartY -= DEAD_ZONE_PADDING;
deadZoneEndX += DEAD_ZONE_PADDING;
deadZoneEndY += DEAD_ZONE_PADDING;
CGPoint touchLocation = [touch locationInView:_view];
return (touchLocation.x > deadZoneStartX && touchLocation.x < deadZoneEndX
&& touchLocation.y > deadZoneStartY && touchLocation.y < deadZoneEndY);
}
@end @end
+77 -21
View File
@@ -13,10 +13,13 @@
#import "ControllerSupport.h" #import "ControllerSupport.h"
@implementation StreamView { @implementation StreamView {
CGPoint touchLocation; CGPoint touchLocation, originalLocation;
BOOL touchMoved; BOOL touchMoved;
OnScreenControls* onScreenControls; OnScreenControls* onScreenControls;
BOOL isDragging;
NSTimer* dragTimer;
float xDeltaFactor; float xDeltaFactor;
float yDeltaFactor; float yDeltaFactor;
float screenFactor; float screenFactor;
@@ -32,7 +35,7 @@
- (void) setupOnScreenControls:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate { - (void) setupOnScreenControls:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate {
onScreenControls = [[OnScreenControls alloc] initWithView:self controllerSup:controllerSupport swipeDelegate:swipeDelegate]; onScreenControls = [[OnScreenControls alloc] initWithView:self controllerSup:controllerSupport swipeDelegate:swipeDelegate];
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
OnScreenControlsLevel level = (OnScreenControlsLevel)[[dataMan retrieveSettings].onscreenControls integerValue]; OnScreenControlsLevel level = (OnScreenControlsLevel)[[dataMan getSettings].onscreenControls integerValue];
if (level == OnScreenControlsLevelAuto) { if (level == OnScreenControlsLevelAuto) {
[controllerSupport initAutoOnScreenControlMode:onScreenControls]; [controllerSupport initAutoOnScreenControlMode:onScreenControls];
@@ -43,17 +46,38 @@
} }
} }
- (Boolean)isConfirmedMove:(CGPoint)currentPoint from:(CGPoint)originalPoint {
// Movements of greater than 20 pixels are considered confirmed
return hypotf(originalPoint.x - currentPoint.x, originalPoint.y - currentPoint.y) >= 20;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
Log(LOG_D, @"Touch down"); Log(LOG_D, @"Touch down");
if (![onScreenControls handleTouchDownEvent:touches]) { if (![onScreenControls handleTouchDownEvent:touches]) {
UITouch *touch = [[event allTouches] anyObject]; UITouch *touch = [[event allTouches] anyObject];
touchLocation = [touch locationInView:self]; originalLocation = touchLocation = [touch locationInView:self];
touchMoved = false; touchMoved = false;
if ([[event allTouches] count] == 1 && !isDragging) {
dragTimer = [NSTimer scheduledTimerWithTimeInterval:0.650
target:self
selector:@selector(onDragStart:)
userInfo:nil
repeats:NO];
}
}
}
- (void)onDragStart:(NSTimer*)timer {
if (!touchMoved && !isDragging){
isDragging = true;
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
} }
} }
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (![onScreenControls handleTouchMovedEvent:touches]) { if (![onScreenControls handleTouchMovedEvent:touches]) {
[dragTimer invalidate];
dragTimer = nil;
if ([[event allTouches] count] == 1) { if ([[event allTouches] count] == 1) {
UITouch *touch = [[event allTouches] anyObject]; UITouch *touch = [[event allTouches] anyObject];
CGPoint currentLocation = [touch locationInView:self]; CGPoint currentLocation = [touch locationInView:self];
@@ -67,20 +91,32 @@
deltaX *= xDeltaFactor * screenFactor; deltaX *= xDeltaFactor * screenFactor;
deltaY *= yDeltaFactor * screenFactor; deltaY *= yDeltaFactor * screenFactor;
LiSendMouseMoveEvent(deltaX, deltaY); if (deltaX != 0 || deltaY != 0) {
LiSendMouseMoveEvent(deltaX, deltaY);
touchMoved = true; touchLocation = currentLocation;
touchLocation = currentLocation;
// If we've moved far enough to confirm this wasn't just human/machine error,
// mark it as such.
if ([self isConfirmedMove:touchLocation from:originalLocation]) {
touchMoved = true;
}
}
} }
} else if ([[event allTouches] count] == 2) { } else if ([[event allTouches] count] == 2) {
CGPoint firstLocation = [[[[event allTouches] allObjects] objectAtIndex:0] locationInView:self]; CGPoint firstLocation = [[[[event allTouches] allObjects] objectAtIndex:0] locationInView:self];
CGPoint secondLocation = [[[[event allTouches] allObjects] objectAtIndex:1] locationInView:self]; CGPoint secondLocation = [[[[event allTouches] allObjects] objectAtIndex:1] locationInView:self];
CGPoint avgLocation = CGPointMake((firstLocation.x + secondLocation.x) / 2, (firstLocation.y + secondLocation.y) / 2); CGPoint avgLocation = CGPointMake((firstLocation.x + secondLocation.x) / 2, (firstLocation.y + secondLocation.y) / 2);
if (touchLocation.y != avgLocation.y) { if (touchLocation.y != avgLocation.y) {
LiSendScrollEvent(avgLocation.y - touchLocation.y); LiSendScrollEvent(avgLocation.y - touchLocation.y);
} }
touchMoved = true;
// If we've moved far enough to confirm this wasn't just human/machine error,
// mark it as such.
if ([self isConfirmedMove:firstLocation from:originalLocation]) {
touchMoved = true;
}
touchLocation = avgLocation; touchLocation = avgLocation;
} }
} }
@@ -90,29 +126,49 @@
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
Log(LOG_D, @"Touch up"); Log(LOG_D, @"Touch up");
if (![onScreenControls handleTouchUpEvent:touches]) { if (![onScreenControls handleTouchUpEvent:touches]) {
[dragTimer invalidate];
dragTimer = nil;
if (!touchMoved) { if (!touchMoved) {
if ([[event allTouches] count] == 2) { if ([[event allTouches] count] == 2) {
Log(LOG_D, @"Sending right mouse button press"); Log(LOG_D, @"Sending right mouse button press");
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT); LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
// Wait 100 ms to simulate a real button press // Wait 100 ms to simulate a real button press
usleep(100 * 1000); usleep(100 * 1000);
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT); LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
} else { } else {
Log(LOG_D, @"Sending left mouse button press"); if (!isDragging){
Log(LOG_D, @"Sending left mouse button press");
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
// Wait 100 ms to simulate a real button press
usleep(100 * 1000); // Wait 100 ms to simulate a real button press
usleep(100 * 1000);
}
isDragging = false;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
} }
} }
else if (isDragging) {
isDragging = false;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
}
// We we're moving from 2+ touches to 1. Synchronize the current position
// of the active finger so we don't jump unexpectedly on the next touchesMoved
// callback when finger 1 switches on us.
if ([[event allTouches] count] - [touches count] == 1) {
NSMutableSet *activeSet = [[NSMutableSet alloc] initWithCapacity:[[event allTouches] count]];
[activeSet unionSet:[event allTouches]];
[activeSet minusSet:touches];
touchLocation = [[activeSet anyObject] locationInView:self];
// Mark this touch as moved so we don't send a left mouse click if the user
// right clicks without moving their other finger.
touchMoved = true;
}
} }
} }
+5 -3
View File
@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.9.2</string> <string>1.5.0</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
@@ -50,9 +50,9 @@
<array> <array>
<string>armv7</string> <string>armv7</string>
</array> </array>
<key>UIStatusBarHidden</key> <key>UIRequiresFullScreen</key>
<true/> <true/>
<key>UIStatusBarHidden~ipad</key> <key>UIStatusBarHidden</key>
<true/> <true/>
<key>UISupportedInterfaceOrientations</key> <key>UISupportedInterfaceOrientations</key>
<array> <array>
@@ -64,5 +64,7 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict> </dict>
</plist> </plist>
@@ -3,6 +3,6 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>_XCCurrentVersionName</key> <key>_XCCurrentVersionName</key>
<string>Moonlight v1.0.xcdatamodel</string> <string>Moonlight v1.0-2.xcdatamodel</string>
</dict> </dict>
</plist> </plist>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="9057" systemVersion="15B42" minimumToolsVersion="Automatic">
<entity name="App" representedClassName="App" syncable="YES">
<attribute name="id" attributeType="String" syncable="YES"/>
<attribute name="image" optional="YES" attributeType="Binary" allowsExternalBinaryDataStorage="YES" syncable="YES"/>
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="host" maxCount="1" deletionRule="Nullify" destinationEntity="Host" inverseName="appList" inverseEntity="Host" syncable="YES"/>
</entity>
<entity name="Host" representedClassName="Host" syncable="YES">
<attribute name="address" attributeType="String" syncable="YES"/>
<attribute name="externalAddress" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="localAddress" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="mac" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="name" attributeType="String" syncable="YES"/>
<attribute name="pairState" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
<attribute name="uuid" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="appList" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="App" inverseName="host" inverseEntity="App" syncable="YES"/>
</entity>
<entity name="Settings" representedClassName="Settings" syncable="YES">
<attribute name="bitrate" attributeType="Integer 32" defaultValueString="10000" syncable="YES"/>
<attribute name="framerate" attributeType="Integer 32" defaultValueString="60" syncable="YES"/>
<attribute name="height" attributeType="Integer 32" defaultValueString="720" syncable="YES"/>
<attribute name="onscreenControls" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
<attribute name="uniqueId" attributeType="String" syncable="YES"/>
<attribute name="width" attributeType="Integer 32" defaultValueString="1280" syncable="YES"/>
</entity>
<elements>
<element name="App" positionX="0" positionY="54" width="128" height="105"/>
<element name="Host" positionX="0" positionY="0" width="128" height="163"/>
<element name="Settings" positionX="0" positionY="0" width="128" height="135"/>
</elements>
</model>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="8118.17" systemVersion="15A204h" minimumToolsVersion="Automatic"> <model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="9057" systemVersion="15B42" minimumToolsVersion="Automatic">
<entity name="App" representedClassName="App" syncable="YES"> <entity name="App" representedClassName="App" syncable="YES">
<attribute name="id" attributeType="String" syncable="YES"/> <attribute name="id" attributeType="String" syncable="YES"/>
<attribute name="image" optional="YES" attributeType="Binary" allowsExternalBinaryDataStorage="YES" syncable="YES"/> <attribute name="image" optional="YES" attributeType="Binary" allowsExternalBinaryDataStorage="YES" syncable="YES"/>
@@ -21,11 +21,12 @@
<attribute name="framerate" attributeType="Integer 32" defaultValueString="60" syncable="YES"/> <attribute name="framerate" attributeType="Integer 32" defaultValueString="60" syncable="YES"/>
<attribute name="height" attributeType="Integer 32" defaultValueString="720" syncable="YES"/> <attribute name="height" attributeType="Integer 32" defaultValueString="720" syncable="YES"/>
<attribute name="onscreenControls" attributeType="Integer 32" defaultValueString="1" syncable="YES"/> <attribute name="onscreenControls" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
<attribute name="uniqueId" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="width" attributeType="Integer 32" defaultValueString="1280" syncable="YES"/> <attribute name="width" attributeType="Integer 32" defaultValueString="1280" syncable="YES"/>
</entity> </entity>
<elements> <elements>
<element name="App" positionX="0" positionY="54" width="128" height="105"/> <element name="App" positionX="0" positionY="54" width="128" height="105"/>
<element name="Host" positionX="0" positionY="0" width="128" height="163"/> <element name="Host" positionX="0" positionY="0" width="128" height="163"/>
<element name="Settings" positionX="0" positionY="0" width="128" height="120"/> <element name="Settings" positionX="0" positionY="0" width="128" height="135"/>
</elements> </elements>
</model> </model>
+4 -4
View File
@@ -7,20 +7,20 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "App.h" #import "TemporaryApp.h"
#import "HttpManager.h" #import "HttpManager.h"
#import "Host.h" #import "TemporaryHost.h"
@protocol AppAssetCallback <NSObject> @protocol AppAssetCallback <NSObject>
- (void) receivedAssetForApp:(App*)app; - (void) receivedAssetForApp:(TemporaryApp*)app;
@end @end
@interface AppAssetManager : NSObject @interface AppAssetManager : NSObject
- (id) initWithCallback:(id<AppAssetCallback>)callback; - (id) initWithCallback:(id<AppAssetCallback>)callback;
- (void) retrieveAssetsFromHost:(Host*)host; - (void) retrieveAssetsFromHost:(TemporaryHost*)host;
- (void) stopRetrieving; - (void) stopRetrieving;
@end @end
+3 -3
View File
@@ -28,8 +28,8 @@ static const int MAX_REQUEST_COUNT = 4;
return self; return self;
} }
- (void) retrieveAssetsFromHost:(Host*)host { - (void) retrieveAssetsFromHost:(TemporaryHost*)host {
for (App* app in host.appList) { for (TemporaryApp* app in host.appList) {
if (app.image == nil) { if (app.image == nil) {
AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init]; AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init];
retriever.app = app; retriever.app = app;
@@ -45,7 +45,7 @@ static const int MAX_REQUEST_COUNT = 4;
[_opQueue cancelAllOperations]; [_opQueue cancelAllOperations];
} }
- (void) sendCallBackForApp:(App*)app { - (void) sendCallBackForApp:(TemporaryApp*)app {
[_callback receivedAssetForApp:app]; [_callback receivedAssetForApp:app];
} }
+4 -4
View File
@@ -7,14 +7,14 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Host.h" #import "TemporaryHost.h"
#import "App.h" #import "TemporaryApp.h"
#import "AppAssetManager.h" #import "AppAssetManager.h"
@interface AppAssetRetriever : NSOperation @interface AppAssetRetriever : NSOperation
@property (nonatomic) Host* host; @property (nonatomic) TemporaryHost* host;
@property (nonatomic) App* app; @property (nonatomic) TemporaryApp* app;
@property (nonatomic) id<AppAssetCallback> callback; @property (nonatomic) id<AppAssetCallback> callback;
@end @end
+3 -2
View File
@@ -11,6 +11,7 @@
#import "CryptoManager.h" #import "CryptoManager.h"
#import "AppAssetResponse.h" #import "AppAssetResponse.h"
#import "HttpRequest.h" #import "HttpRequest.h"
#import "IdManager.h"
@implementation AppAssetRetriever @implementation AppAssetRetriever
static const double RETRY_DELAY = 2; // seconds static const double RETRY_DELAY = 2; // seconds
@@ -21,7 +22,7 @@ static const int MAX_ATTEMPTS = 5;
int attempts = 0; int attempts = 0;
while (![self isCancelled] && appImage == nil && attempts++ < MAX_ATTEMPTS) { while (![self isCancelled] && appImage == nil && attempts++ < MAX_ATTEMPTS) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.activeAddress uniqueId:[CryptoManager getUniqueID] deviceName:deviceName cert:[CryptoManager readCertFromFile]]; HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.activeAddress uniqueId:[IdManager getUniqueId] deviceName:deviceName cert:[CryptoManager readCertFromFile]];
AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init]; AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.id]]]; [hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.id]]];
@@ -35,7 +36,7 @@ static const int MAX_ATTEMPTS = 5;
[self performSelectorOnMainThread:@selector(sendCallbackForApp:) withObject:self.app waitUntilDone:NO]; [self performSelectorOnMainThread:@selector(sendCallbackForApp:) withObject:self.app waitUntilDone:NO];
} }
- (void) sendCallbackForApp:(App*)app { - (void) sendCallbackForApp:(TemporaryApp*)app {
[self.callback receivedAssetForApp:app]; [self.callback receivedAssetForApp:app];
} }
+1 -1
View File
@@ -11,7 +11,7 @@
@interface AppListResponse : NSObject <Response> @interface AppListResponse : NSObject <Response>
- (void)populateWithData:(NSData *)data; - (void)populateWithData:(NSData *)data;
- (NSArray*) getAppList; - (NSSet*) getAppList;
- (BOOL) isStatusOk; - (BOOL) isStatusOk;
@end @end
+5 -17
View File
@@ -7,23 +7,22 @@
// //
#import "AppListResponse.h" #import "AppListResponse.h"
#import "App.h" #import "TemporaryApp.h"
#import "DataManager.h" #import "DataManager.h"
#import <libxml2/libxml/xmlreader.h> #import <libxml2/libxml/xmlreader.h>
@implementation AppListResponse { @implementation AppListResponse {
NSMutableArray* _appList; NSMutableSet* _appList;
} }
@synthesize data, statusCode, statusMessage; @synthesize data, statusCode, statusMessage;
static const char* TAG_APP = "App"; static const char* TAG_APP = "App";
static const char* TAG_APP_TITLE = "AppTitle"; static const char* TAG_APP_TITLE = "AppTitle";
static const char* TAG_APP_ID = "ID"; static const char* TAG_APP_ID = "ID";
static const char* TAG_APP_IS_RUNNING = "IsRunning";
- (void)populateWithData:(NSData *)xml { - (void)populateWithData:(NSData *)xml {
self.data = xml; self.data = xml;
_appList = [[NSMutableArray alloc] init]; _appList = [[NSMutableSet alloc] init];
[self parseData]; [self parseData];
} }
@@ -60,7 +59,6 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
self.statusMessage = statusMsg; self.statusMessage = statusMsg;
node = node->children; node = node->children;
DataManager* dataMan = [[DataManager alloc] init];
while (node != NULL) { while (node != NULL) {
//Log(LOG_D, @"node: %s", node->name); //Log(LOG_D, @"node: %s", node->name);
@@ -68,7 +66,6 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
xmlNodePtr appInfoNode = node->xmlChildrenNode; xmlNodePtr appInfoNode = node->xmlChildrenNode;
NSString* appName = @""; NSString* appName = @"";
NSString* appId = nil; NSString* appId = nil;
BOOL appIsRunning = NO;
while (appInfoNode != NULL) { while (appInfoNode != NULL) {
if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) { if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1); xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
@@ -84,22 +81,13 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding]; appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal); xmlFree(nodeVal);
} }
} else if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_IS_RUNNING)) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
if (nodeVal != NULL) {
appIsRunning = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"];
xmlFree(nodeVal);
} else {
appIsRunning = NO;
}
} }
appInfoNode = appInfoNode->next; appInfoNode = appInfoNode->next;
} }
if (appId != nil) { if (appId != nil) {
App* app = [dataMan createApp]; TemporaryApp* app = [[TemporaryApp alloc] init];
app.name = appName; app.name = appName;
app.id = appId; app.id = appId;
app.isRunning = appIsRunning;
[_appList addObject:app]; [_appList addObject:app];
} }
} }
@@ -109,7 +97,7 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
xmlFreeDoc(docPtr); xmlFreeDoc(docPtr);
} }
- (NSArray*) getAppList { - (NSSet*) getAppList {
return _appList; return _appList;
} }
+4 -4
View File
@@ -8,7 +8,7 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "MDNSManager.h" #import "MDNSManager.h"
#import "Host.h" #import "TemporaryHost.h"
@protocol DiscoveryCallback <NSObject> @protocol DiscoveryCallback <NSObject>
@@ -22,8 +22,8 @@
- (void) startDiscovery; - (void) startDiscovery;
- (void) stopDiscovery; - (void) stopDiscovery;
- (void) stopDiscoveryBlocking; - (void) stopDiscoveryBlocking;
- (BOOL) addHostToDiscovery:(Host*)host; - (BOOL) addHostToDiscovery:(TemporaryHost*)host;
- (void) removeHostFromDiscovery:(Host*)host; - (void) removeHostFromDiscovery:(TemporaryHost*)host;
- (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(Host*, NSString*))callback; - (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(TemporaryHost*, NSString*))callback;
@end @end
Loaded 100 of 142 files, more files were not shown because too many files have changed in this diff. Show more