Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5584083809 | ||
|
|
9f9aec70b0 | ||
|
|
a8d1770871 | ||
|
|
d0d60b8ffc | ||
|
|
86f7112789 | ||
|
|
da1115e529 | ||
|
|
593da7ef3e | ||
|
|
de5377a95d | ||
|
|
7d7500b187 | ||
|
|
45dbd46da1 | ||
|
|
89d8bc6009 | ||
|
|
b99988836a | ||
|
|
3e94613eb3 | ||
|
|
832b9189f8 | ||
|
|
3464539bd3 | ||
|
|
815592117d | ||
|
|
b51341ef54 | ||
|
|
9ffbb5f155 | ||
|
|
9716867ade | ||
|
|
7c141c1fd2 | ||
|
|
42c4e7ca58 | ||
|
|
6a6ea4a79a | ||
|
|
5d0ca8451d | ||
|
|
4641f68eb8 | ||
|
|
dd33f57b9a | ||
|
|
f6b225ca9c | ||
|
|
4ac3f11ff8 | ||
|
|
62aaf27293 | ||
|
|
eac2d985e2 | ||
|
|
61ea7f3f1c | ||
|
|
40f7faa1b1 | ||
|
|
9e18b8021b | ||
|
|
ce95f2c153 | ||
|
|
fd50b71b16 | ||
|
|
39ab472cf6 | ||
|
|
48ba7eb2dc | ||
|
|
42edaa1bad | ||
|
|
955fb59156 | ||
|
|
2fbc67ef00 | ||
|
|
23564a3028 | ||
|
|
9a07d5a33a | ||
|
|
84c037f235 | ||
|
|
c13df82f5b | ||
|
|
b15d61a5bf | ||
|
|
5aff719984 | ||
|
|
b0c2978405 | ||
|
|
91dcb505de | ||
|
|
d1f35d938b | ||
|
|
359b822951 | ||
|
|
39580e4352 | ||
|
|
7b3d099449 | ||
|
|
b17c45e9ca | ||
|
|
4c7a2cecdd | ||
|
|
175074ece8 | ||
|
|
8a5ec513bf | ||
|
|
7cfb7f73a2 | ||
|
|
c608685737 | ||
|
|
3beca2fc72 | ||
|
|
c59aafb4bb | ||
|
|
256e40acdc | ||
|
|
39b1b65e16 | ||
|
|
1783abec13 | ||
|
|
983c65d399 | ||
|
|
4caa9672c9 | ||
|
|
15be6a3f75 | ||
|
|
d38eb0a3ba | ||
|
|
e8ea942ad2 | ||
|
|
cb68b10475 | ||
|
|
11c854ce44 | ||
|
|
9636f4742b | ||
|
|
5867317526 | ||
|
|
8a8f7b6903 | ||
|
|
61b6e25a91 | ||
|
|
50cff820de | ||
|
|
4e586a28c8 | ||
|
|
0702b4ed57 | ||
|
|
4a2132a682 | ||
|
|
ba81d1d6a9 | ||
|
|
402ce4b3ec | ||
|
|
fc713453ad | ||
|
|
b222ccffbb | ||
|
|
56ce7329d2 | ||
|
|
99ab6db557 | ||
|
|
d7adf96f3a | ||
|
|
0ae58c61a9 | ||
|
|
2ec7d1d2f1 | ||
|
|
ad1b9059ee | ||
|
|
4439c7cce6 | ||
|
|
b8a4093c75 | ||
|
|
ec3748b26e | ||
|
|
1c1f22e047 | ||
|
|
9aa9b0fc5a | ||
|
|
f8e2ca8500 | ||
|
|
3076e29335 | ||
|
|
fe616d86c5 | ||
|
|
bfa4856bbe | ||
|
|
5ea92a7b48 | ||
|
|
4ba71db7b2 | ||
|
|
c1e6aeb43c | ||
|
|
e3ffb66ef0 | ||
|
|
5daa82b0ba | ||
|
|
a8bcc6afba | ||
|
|
e6aa16ad01 | ||
|
|
ad0705d126 | ||
|
|
2f31f93bf8 | ||
|
|
ea3be613c5 | ||
|
|
b495246f34 | ||
|
|
814470f4bf | ||
|
|
82293a08b6 | ||
|
|
20d66336a7 | ||
|
|
c8441ec9fa | ||
|
|
f72135c227 | ||
|
|
100e6e4ce8 | ||
|
|
ec8be20d62 | ||
|
|
55d48101ef | ||
|
|
c36f4c5f84 | ||
|
|
06289ac4d2 | ||
|
|
e6a2d5d425 | ||
|
|
ea8db9c4ea | ||
|
|
3773e841d1 | ||
|
|
ad1ddd04f3 | ||
|
|
67a8b232b9 | ||
|
|
5293c07fc0 | ||
|
|
e3a42db007 | ||
|
|
3b1462af22 | ||
|
|
74a0c5b1cd | ||
|
|
05a5e4fa64 | ||
|
|
b6445295a7 | ||
|
|
391605ef36 | ||
|
|
695499dea9 | ||
|
|
9ba7f35444 | ||
|
|
37dc00735b | ||
|
|
920cbadc91 | ||
|
|
bc53b4dc32 | ||
|
|
6015c38d17 | ||
|
|
4ea8694a7d | ||
|
|
00f01196fb | ||
|
|
543639c93e | ||
|
|
1da877fed7 | ||
|
|
396b5fc156 | ||
|
|
297dfd4159 | ||
|
|
23e9d48b0d | ||
|
|
9ec650a84f | ||
|
|
90bdbc4ae0 | ||
|
|
dd5f06723b | ||
|
|
55b2871b83 |
@@ -1,2 +1,4 @@
|
||||
**/xcuserdata/
|
||||
**/Moonlight.xcscmblueprint
|
||||
Build
|
||||
DerivedData
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
[submodule "limelight-common-c"]
|
||||
path = limelight-common-c
|
||||
url = git@github.com:limelight-stream/limelight-common-c.git
|
||||
[submodule "moonlight-common/moonlight-common-c"]
|
||||
path = moonlight-common/moonlight-common-c
|
||||
url = https://github.com/moonlight-stream/moonlight-common-c.git
|
||||
|
||||
@@ -1,36 +1,51 @@
|
||||
<?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>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8101.14"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<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">
|
||||
<rect key="frame" x="18" y="439.5" width="444" height="20.5"/>
|
||||
<animations/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
<variation key="widthClass=compact">
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
</variation>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Gnz-uJ-CDw"/>
|
||||
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="404" y="445"/>
|
||||
</view>
|
||||
<navigationController id="vV9-32-ww6">
|
||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="y2P-aE-Haa">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
<color key="barTintColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</navigationBar>
|
||||
<viewControllers>
|
||||
<viewController id="l6V-ue-5Om">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="rEZ-vx-akr"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="gBD-cy-cth"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="6lF-fc-kpK">
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="rW0-BH-s7l">
|
||||
<barButtonItem key="leftBarButtonItem" enabled="NO" id="d9R-Zo-Uml">
|
||||
<button key="customView" opaque="NO" contentMode="center" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="9JC-B5-BAE">
|
||||
<rect key="frame" x="20" y="-1" width="109" height="46"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<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>
|
||||
<resources>
|
||||
<image name="Logo" width="32" height="32"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -83,10 +83,7 @@ static NSOperationQueue* mainQueue;
|
||||
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
|
||||
if (managedObjectContext != nil) {
|
||||
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
|
||||
// Replace this implementation with code to handle the error appropriately.
|
||||
// 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();
|
||||
Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,32 +133,15 @@ static NSOperationQueue* mainQueue;
|
||||
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
|
||||
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
|
||||
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
|
||||
/*
|
||||
Replace this implementation with code to handle the error appropriately.
|
||||
|
||||
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.
|
||||
|
||||
Typical reasons for an error here include:
|
||||
* The persistent store is not accessible;
|
||||
* The schema for the persistent store is incompatible with current managed object model.
|
||||
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();
|
||||
}
|
||||
// Log the error
|
||||
Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
|
||||
|
||||
// Drop the database
|
||||
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
|
||||
|
||||
// Try again
|
||||
return [self persistentStoreCoordinator];
|
||||
}
|
||||
|
||||
return _persistentStoreCoordinator;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -11,15 +11,16 @@
|
||||
@interface CryptoManager : NSObject
|
||||
|
||||
+ (void) generateKeyPairUsingSSl;
|
||||
+ (NSString*) getUniqueID;
|
||||
+ (NSData*) readCertFromFile;
|
||||
+ (NSData*) readKeyFromFile;
|
||||
+ (NSData*) readP12FromFile;
|
||||
+ (NSData*) getSignatureFromCert:(NSData*)cert;
|
||||
+ (NSData*) nullTerminateString:(NSData*)data;
|
||||
|
||||
- (NSData*) createAESKeyFromSalt:(NSData*)saltedPIN;
|
||||
- (NSData*) createAESKeyFromSaltSHA1:(NSData*)saltedPIN;
|
||||
- (NSData*) createAESKeyFromSaltSHA256:(NSData*)saltedPIN;
|
||||
- (NSData*) SHA1HashData:(NSData*)data;
|
||||
- (NSData*) SHA256HashData:(NSData*)data;
|
||||
- (NSData*) aesEncrypt:(NSData*)data withKey:(NSData*)key;
|
||||
- (NSData*) aesDecrypt:(NSData*)data withKey:(NSData*)key;
|
||||
- (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert;
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#import "CryptoManager.h"
|
||||
#import "mkcert.h"
|
||||
#import <AdSupport/ASIdentifierManager.h>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/sha.h>
|
||||
@@ -17,19 +16,31 @@
|
||||
#include <openssl/evp.h>
|
||||
|
||||
@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* cert = nil;
|
||||
static NSData* p12 = nil;
|
||||
|
||||
- (NSData*) createAESKeyFromSalt:(NSData*)saltedPIN {
|
||||
- (NSData*) createAESKeyFromSaltSHA1:(NSData*)saltedPIN {
|
||||
return [[self SHA1HashData:saltedPIN] subdataWithRange:NSMakeRange(0, 16)];
|
||||
}
|
||||
|
||||
- (NSData*) createAESKeyFromSaltSHA256:(NSData*)saltedPIN {
|
||||
return [[self SHA256HashData:saltedPIN] subdataWithRange:NSMakeRange(0, 16)];
|
||||
}
|
||||
|
||||
- (NSData*) SHA1HashData:(NSData*)data {
|
||||
unsigned char sha1[SHA1_DIGEST_LENGTH];
|
||||
unsigned char sha1[SHA1_HASH_LENGTH];
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -85,7 +85,6 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
|
||||
|
||||
if (*pkeyp == NULL) {
|
||||
if ((pk=EVP_PKEY_new()) == NULL) {
|
||||
abort();
|
||||
return(0);
|
||||
}
|
||||
} 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);
|
||||
if (!EVP_PKEY_assign_RSA(pk, rsa)) {
|
||||
abort();
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,16 +11,8 @@
|
||||
|
||||
@class Host;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface App : NSManagedObject
|
||||
|
||||
@property BOOL isRunning;
|
||||
|
||||
- (NSComparisonResult)compareName:(App *)other;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#import "App+CoreDataProperties.h"
|
||||
|
||||
@@ -7,14 +7,7 @@
|
||||
//
|
||||
|
||||
#import "App.h"
|
||||
#import "Host.h"
|
||||
|
||||
@implementation App
|
||||
|
||||
@synthesize isRunning;
|
||||
|
||||
- (NSComparisonResult)compareName:(App *)other {
|
||||
return [self.name caseInsensitiveCompare:other.name];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,22 +7,25 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Settings.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "Host.h"
|
||||
#import "App.h"
|
||||
#import "TemporaryHost.h"
|
||||
#import "TemporaryApp.h"
|
||||
#import "TemporarySettings.h"
|
||||
|
||||
@interface DataManager : NSObject
|
||||
|
||||
@property (strong, nonatomic) AppDelegate* appDelegate;
|
||||
|
||||
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls;
|
||||
- (Settings*) retrieveSettings;
|
||||
- (NSArray*) retrieveHosts;
|
||||
- (void) saveData;
|
||||
- (Host*) createHost;
|
||||
- (void) removeHost:(Host*)host;
|
||||
- (App*) createApp;
|
||||
- (void) removeApp:(App*)app;
|
||||
|
||||
- (NSArray*) getHosts;
|
||||
- (void) updateHost:(TemporaryHost*)host;
|
||||
- (void) updateAppsForExistingHost:(TemporaryHost *)host;
|
||||
- (void) updateIconForExistingApp:(TemporaryApp*)app;
|
||||
- (void) removeHost:(TemporaryHost*)host;
|
||||
- (void) removeApp:(TemporaryApp*)app;
|
||||
|
||||
- (TemporarySettings*) getSettings;
|
||||
|
||||
- (void) updateUniqueId:(NSString*)uniqueId;
|
||||
- (NSString*) getUniqueId;
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,37 +7,142 @@
|
||||
//
|
||||
|
||||
#import "DataManager.h"
|
||||
#import "TemporaryApp.h"
|
||||
#import "TemporarySettings.h"
|
||||
#import "Settings.h"
|
||||
|
||||
@implementation DataManager
|
||||
@implementation DataManager {
|
||||
NSManagedObjectContext *_managedObjectContext;
|
||||
AppDelegate *_appDelegate;
|
||||
}
|
||||
|
||||
- (id) 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;
|
||||
}
|
||||
|
||||
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls {
|
||||
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];
|
||||
- (void) updateUniqueId:(NSString*)uniqueId {
|
||||
[_managedObjectContext performBlockAndWait:^{
|
||||
[self retrieveSettings].uniqueId = uniqueId;
|
||||
[self saveData];
|
||||
}];
|
||||
}
|
||||
|
||||
NSError* error;
|
||||
if (![[self.appDelegate managedObjectContext] save:&error]) {
|
||||
Log(LOG_E, @"Unable to save settings to database: %@", error);
|
||||
}
|
||||
[self.appDelegate saveContext];
|
||||
- (NSString*) getUniqueId {
|
||||
__block NSString *uid;
|
||||
|
||||
[_managedObjectContext performBlockAndWait:^{
|
||||
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 {
|
||||
NSArray* fetchedRecords = [self fetchRecords:@"Settings"];
|
||||
if (fetchedRecords.count == 0) {
|
||||
// create a new settings object with the default values
|
||||
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Settings" inManagedObjectContext:[self.appDelegate managedObjectContext]];
|
||||
Settings* settings = [[Settings alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]];
|
||||
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Settings" inManagedObjectContext:_managedObjectContext];
|
||||
Settings* settings = [[Settings alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
|
||||
|
||||
return settings;
|
||||
} else {
|
||||
@@ -46,49 +151,84 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (Host*) createHost {
|
||||
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:[self.appDelegate managedObjectContext]];
|
||||
return [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]];
|
||||
- (void) removeApp:(TemporaryApp*)app {
|
||||
[_managedObjectContext performBlockAndWait:^{
|
||||
App* managedApp = [self getAppForTemporaryApp:app withAppRecords:[self fetchRecords:@"App"]];
|
||||
if (managedApp != nil) {
|
||||
[_managedObjectContext deleteObject:managedApp];
|
||||
[self saveData];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void) removeHost:(Host*)host {
|
||||
[[self.appDelegate managedObjectContext] deleteObject:host];
|
||||
[self saveData];
|
||||
- (void) removeHost:(TemporaryHost*)host {
|
||||
[_managedObjectContext performBlockAndWait:^{
|
||||
Host* managedHost = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
|
||||
if (managedHost != nil) {
|
||||
[_managedObjectContext deleteObject:managedHost];
|
||||
[self saveData];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void) saveData {
|
||||
NSError* error;
|
||||
if (![[self.appDelegate managedObjectContext] save:&error]) {
|
||||
if (![_managedObjectContext save:&error]) {
|
||||
Log(LOG_E, @"Unable to save hosts to database: %@", error);
|
||||
}
|
||||
[self.appDelegate saveContext];
|
||||
|
||||
[_appDelegate saveContext];
|
||||
}
|
||||
|
||||
- (NSArray*) retrieveHosts {
|
||||
return [self fetchRecords:@"Host"];
|
||||
- (NSArray*) getHosts {
|
||||
__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 {
|
||||
NSEntityDescription* entity = [NSEntityDescription entityForName:@"App" inManagedObjectContext:[self.appDelegate managedObjectContext]];
|
||||
return [[App alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]];
|
||||
// Only call from within performBlockAndWait!!!
|
||||
- (Host*) getHostForTemporaryHost:(TemporaryHost*)tempHost withHostRecords:(NSArray*)hosts {
|
||||
for (Host* host in hosts) {
|
||||
if ([tempHost.uuid isEqualToString:host.uuid]) {
|
||||
return host;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void) removeApp:(App*)app {
|
||||
[[self.appDelegate managedObjectContext] deleteObject:app];
|
||||
// Only call from within performBlockAndWait!!!
|
||||
- (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* fetchedRecords;
|
||||
|
||||
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 setAffectedStores:[NSArray arrayWithObjects:[[self.appDelegate persistentStoreCoordinator] persistentStoreForURL:[self.appDelegate getStoreURL]], nil]];
|
||||
|
||||
NSError* error;
|
||||
NSArray* fetchedRecords = [[self.appDelegate managedObjectContext] executeFetchRequest:fetchRequest error:&error];
|
||||
fetchedRecords = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
|
||||
//TODO: handle errors
|
||||
|
||||
return fetchedRecords;
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,16 +10,8 @@
|
||||
#import <CoreData/CoreData.h>
|
||||
#import "Utils.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface Host : NSManagedObject
|
||||
|
||||
@property (nonatomic) BOOL online;
|
||||
@property (nonatomic) PairState pairState;
|
||||
@property (nonatomic) NSString * activeAddress;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#import "Host+CoreDataProperties.h"
|
||||
|
||||
@@ -10,8 +10,4 @@
|
||||
|
||||
@implementation Host
|
||||
|
||||
@dynamic pairState;
|
||||
@synthesize online;
|
||||
@synthesize activeAddress;
|
||||
|
||||
@end
|
||||
|
||||
@@ -17,5 +17,6 @@
|
||||
@property (nonatomic, retain) NSNumber * height;
|
||||
@property (nonatomic, retain) NSNumber * width;
|
||||
@property (nonatomic, retain) NSNumber * onscreenControls;
|
||||
@property (nonatomic, retain) NSString * uniqueId;
|
||||
|
||||
@end
|
||||
|
||||
@@ -16,5 +16,6 @@
|
||||
@dynamic height;
|
||||
@dynamic width;
|
||||
@dynamic onscreenControls;
|
||||
@dynamic uniqueId;
|
||||
|
||||
@end
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -2,18 +2,17 @@
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "a_button_40x40@1x.png"
|
||||
"filename" : "a_button_80x80@2x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "a_button_80x80@2x.png"
|
||||
"filename" : "a_button_120x120@3x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "a_button_120x120@3x.png"
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
|
Before Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 32 KiB |
@@ -1,76 +1,108 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "app_icon_settings_58x58_@2x-1.png",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "app_icon_settings_87x87_@3x.png",
|
||||
"filename" : "Icon-App-29x29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "app_icon_spotlight_80x80_@2x-1.png",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "app_icon_spotlight_120x120_@3x.png",
|
||||
"filename" : "Icon-App-40x40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "app_icon_120x120_@2x.png",
|
||||
"filename" : "Icon-App-60x60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "app_icon_180x180_@3x.png",
|
||||
"filename" : "Icon-App-60x60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "app_icon_settings_29x29_@1x.png",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "app_icon_settings_58x58_@2x.png",
|
||||
"filename" : "Icon-App-29x29@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "app_icon_spotlight_40x40_@1x.png",
|
||||
"filename" : "Icon-App-40x40@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "app_icon_spotlight_80x80_@2x.png",
|
||||
"filename" : "Icon-App-40x40@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "app_icon_76x76_@1x.png",
|
||||
"filename" : "Icon-App-76x76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "app_icon_152x152_@2x.png",
|
||||
"filename" : "Icon-App-76x76@2x.png",
|
||||
"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" : {
|
||||
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 41 KiB |
@@ -2,18 +2,17 @@
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "b_button_40x40@1x.png"
|
||||
"filename" : "b_button_80x80@2x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "b_button_80x80@2x.png"
|
||||
"filename" : "b_button_120x120@3x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "b_button_120x120@3x.png"
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
|
Before Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -2,18 +2,17 @@
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "down_31x38@1x.png"
|
||||
"filename" : "down_61x75@2x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "down_61x75@2x.png"
|
||||
"filename" : "down_93x114@3x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "down_93x114@3x.png"
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -2,18 +2,17 @@
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "left_38x31@1x.png"
|
||||
"filename" : "left_76x61@2x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "left_76x61@2x.png"
|
||||
"filename" : "left_114x92@3x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "left_114x92@3x.png"
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -6,8 +6,8 @@
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "logo_universal.png"
|
||||
"filename" : "logo.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
|
||||
|
After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.4 KiB |
|
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"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 901 B |
|
After Width: | Height: | Size: 812 B |
|
After Width: | Height: | Size: 1.5 KiB |
@@ -2,18 +2,17 @@
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "right_38x31@1x.png"
|
||||
"filename" : "right_75x61@2x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "right_75x61@2x.png"
|
||||
"filename" : "right_114x93@3x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "right_114x93@3x.png"
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -2,18 +2,17 @@
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "up_31x39@1x.png"
|
||||
"filename" : "up_61x76@2x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "up_61x76@2x.png"
|
||||
"filename" : "up_93x116@3x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "up_93x116@3x.png"
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -2,18 +2,17 @@
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "x_button_40x40@1x.png"
|
||||
"filename" : "x_button_80x80@2x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "x_button_80x80@2x.png"
|
||||
"filename" : "x_button_120x120@3x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "x_button_120x120@3x.png"
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -2,18 +2,17 @@
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "y_button_40x40@1x.png"
|
||||
"filename" : "y_button_80x80@2x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "y_button_80x80@2x.png"
|
||||
"filename" : "y_button_120x120@3x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "y_button_120x120@3x.png"
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
|
Before Width: | Height: | Size: 2.1 KiB |
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -7,7 +7,10 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Controller.h"
|
||||
|
||||
// Swift
|
||||
#import "Moonlight-Swift.h"
|
||||
@class Controller;
|
||||
|
||||
@class OnScreenControls;
|
||||
|
||||
@@ -29,6 +32,7 @@
|
||||
-(void) clearButtonFlag:(Controller*)controller flags:(int)flags;
|
||||
|
||||
-(void) updateFinished:(Controller*)controller;
|
||||
-(Controller*) getOscController;
|
||||
|
||||
@property (nonatomic, strong) id connectObserver;
|
||||
@property (nonatomic, strong) id disconnectObserver;
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
|
||||
#import "ControllerSupport.h"
|
||||
#import "OnScreenControls.h"
|
||||
#import "Controller.h"
|
||||
#include "Limelight.h"
|
||||
|
||||
// Swift
|
||||
#import "Moonlight-Swift.h"
|
||||
@class Controller;
|
||||
|
||||
@import GameController;
|
||||
|
||||
@implementation ControllerSupport {
|
||||
@@ -19,6 +22,10 @@
|
||||
|
||||
OnScreenControls *_osc;
|
||||
|
||||
// This controller object is shared between on-screen controls
|
||||
// and player 0
|
||||
Controller *_player0osc;
|
||||
|
||||
char _controllerNumbers;
|
||||
|
||||
#define EMULATING_SELECT 0x1
|
||||
@@ -139,7 +146,8 @@
|
||||
{
|
||||
[_controllerStreamLock lock];
|
||||
@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];
|
||||
}
|
||||
@@ -272,9 +280,17 @@
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (!(_controllerNumbers & (1 << i))) {
|
||||
_controllerNumbers |= (1 << i);
|
||||
Controller* limeController = [[Controller alloc] init];
|
||||
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]];
|
||||
|
||||
Log(LOG_I, @"Assigning controller index: %d", i);
|
||||
@@ -283,6 +299,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
-(Controller*) getOscController {
|
||||
return _player0osc;
|
||||
}
|
||||
|
||||
-(id) init
|
||||
{
|
||||
self = [super init];
|
||||
@@ -290,6 +310,8 @@
|
||||
_controllerStreamLock = [[NSLock alloc] init];
|
||||
_controllers = [[NSMutableDictionary alloc] init];
|
||||
_controllerNumbers = 0;
|
||||
_player0osc = [[Controller alloc] init];
|
||||
_player0osc.playerIndex = 0;
|
||||
|
||||
Log(LOG_I, @"Number of controllers connected: %ld", (long)[[GCController controllers] count]);
|
||||
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.
|
||||
//
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
|
||||
#import "OnScreenControls.h"
|
||||
#import "ControllerSupport.h"
|
||||
#import "Controller.h"
|
||||
//#import "Controller.h"
|
||||
#include "Limelight.h"
|
||||
|
||||
#import "Moonlight-Swift.h"
|
||||
@class Controller;
|
||||
|
||||
#define UPDATE_BUTTON(x, y) (buttonFlags = \
|
||||
(y) ? (buttonFlags | (x)) : (buttonFlags & ~(x)))
|
||||
|
||||
@@ -41,10 +44,7 @@
|
||||
UITouch* _bTouch;
|
||||
UITouch* _xTouch;
|
||||
UITouch* _yTouch;
|
||||
UITouch* _upTouch;
|
||||
UITouch* _downTouch;
|
||||
UITouch* _leftTouch;
|
||||
UITouch* _rightTouch;
|
||||
UITouch* _dpadTouch;
|
||||
UITouch* _lsTouch;
|
||||
UITouch* _rsTouch;
|
||||
UITouch* _startTouch;
|
||||
@@ -63,25 +63,30 @@
|
||||
BOOL l3Set;
|
||||
BOOL r3Set;
|
||||
|
||||
BOOL _iPad;
|
||||
CGRect _controlArea;
|
||||
UIView* _view;
|
||||
OnScreenControlsLevel _level;
|
||||
|
||||
ControllerSupport *_controllerSupport;
|
||||
Controller *_controller;
|
||||
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_DIST = 20;
|
||||
static float BUTTON_CENTER_X;
|
||||
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_Y;
|
||||
|
||||
static const float DEAD_ZONE_PADDING = 15;
|
||||
|
||||
static const double STICK_CLICK_RATE = 100;
|
||||
static const float STICK_DEAD_ZONE = .1;
|
||||
static float STICK_INNER_SIZE;
|
||||
@@ -114,9 +119,23 @@ static float L3_Y;
|
||||
self = [self init];
|
||||
_view = view;
|
||||
_controllerSupport = controllerSupport;
|
||||
_controller = [[Controller alloc] init];
|
||||
_controller.playerIndex = 0;
|
||||
_controller = [controllerSupport getOscController];
|
||||
_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];
|
||||
_bButton = [CALayer layer];
|
||||
@@ -139,7 +158,7 @@ static float L3_Y;
|
||||
_leftStick = [CALayer layer];
|
||||
_rightStick = [CALayer layer];
|
||||
_edge = [CALayer layer];
|
||||
|
||||
|
||||
[self setupEdgeDetection];
|
||||
|
||||
return self;
|
||||
@@ -167,10 +186,10 @@ static float L3_Y;
|
||||
|
||||
[self hideButtons];
|
||||
[self hideBumpers];
|
||||
[self hideL3R3];
|
||||
[self drawTriggers];
|
||||
[self drawStartSelect];
|
||||
[self drawSticks];
|
||||
[self drawL3R3];
|
||||
break;
|
||||
case OnScreenControlsLevelAutoGCExtendedGamepad:
|
||||
// GCExtendedGamepad is missing R3, L3, and select
|
||||
@@ -219,8 +238,8 @@ static float L3_Y;
|
||||
// Start with the default complex layout
|
||||
[self setupComplexControls];
|
||||
|
||||
START_Y = _view.frame.size.height * .9;
|
||||
SELECT_Y = _view.frame.size.height * .9;
|
||||
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||
}
|
||||
|
||||
// For GCGamepad controls we move triggers, start, and select
|
||||
@@ -229,7 +248,42 @@ static float L3_Y;
|
||||
// Start with the default complex layout
|
||||
[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
|
||||
@@ -237,46 +291,59 @@ static float L3_Y;
|
||||
// Start with the default complex layout
|
||||
[self setupComplexControls];
|
||||
|
||||
START_Y = _view.frame.size.height * .9;
|
||||
SELECT_Y = _view.frame.size.height * .9;
|
||||
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;
|
||||
|
||||
L1_Y = _view.frame.size.height * .7;
|
||||
L2_Y = _view.frame.size.height * .9;
|
||||
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;
|
||||
R2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||
R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||
}
|
||||
|
||||
- (void) setupComplexControls
|
||||
{
|
||||
D_PAD_CENTER_X = _view.frame.size.width * .15;
|
||||
D_PAD_CENTER_Y = _view.frame.size.height * .55;
|
||||
BUTTON_CENTER_X = _view.frame.size.width * .85;
|
||||
BUTTON_CENTER_Y = _view.frame.size.height * .55;
|
||||
D_PAD_CENTER_X = _controlArea.size.width * .1 + _controlArea.origin.x;
|
||||
D_PAD_CENTER_Y = _controlArea.size.height * .60 + _controlArea.origin.y;
|
||||
BUTTON_CENTER_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||
BUTTON_CENTER_Y = _controlArea.size.height * .60 + _controlArea.origin.y;
|
||||
|
||||
LS_CENTER_X = _view.frame.size.width * .35;
|
||||
LS_CENTER_Y = _view.frame.size.height * .75;
|
||||
RS_CENTER_X = _view.frame.size.width * .65;
|
||||
RS_CENTER_Y = _view.frame.size.height * .75;
|
||||
if (_iPad)
|
||||
{
|
||||
// The analog sticks are kept closer to the sides on iPad
|
||||
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_Y = _view.frame.size.height * .1;
|
||||
SELECT_X = _view.frame.size.width * .4;
|
||||
SELECT_Y = _view.frame.size.height * .1;
|
||||
START_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||
SELECT_X = _controlArea.size.width * .1 + _controlArea.origin.x;
|
||||
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||
|
||||
L1_X = _view.frame.size.width * .15;
|
||||
L1_Y = _view.frame.size.height * .27;
|
||||
L2_X = _view.frame.size.width * .15;
|
||||
L2_Y = _view.frame.size.height * .1;
|
||||
R1_X = _view.frame.size.width * .85;
|
||||
R1_Y = _view.frame.size.height * .27;
|
||||
R2_X = _view.frame.size.width * .85;
|
||||
R2_Y = _view.frame.size.height * .1;
|
||||
L3_X = _view.frame.size.width * .25;
|
||||
L3_Y = _view.frame.size.height * .75;
|
||||
R3_X = _view.frame.size.width * .75;
|
||||
R3_Y = _view.frame.size.height * .75;
|
||||
L1_X = _controlArea.size.width * .1 + _controlArea.origin.x;
|
||||
L1_Y = _controlArea.size.height * .27 + _controlArea.origin.y;
|
||||
L2_X = _controlArea.size.width * .1 + _controlArea.origin.x;
|
||||
L2_Y = _controlArea.size.height * .1 + _controlArea.origin.y;
|
||||
R1_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||
R1_Y = _controlArea.size.height * .27 + _controlArea.origin.y;
|
||||
R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||
R2_Y = _controlArea.size.height * .1 + _controlArea.origin.y;
|
||||
L3_X = _controlArea.size.width * .25 + _controlArea.origin.x;
|
||||
L3_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
|
||||
R3_X = _controlArea.size.width * .75 + _controlArea.origin.x;
|
||||
R3_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
|
||||
}
|
||||
|
||||
- (void) drawButtons {
|
||||
@@ -285,43 +352,43 @@ static float L3_Y;
|
||||
_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);
|
||||
[_view.layer addSublayer:_aButton];
|
||||
|
||||
|
||||
// create B button
|
||||
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.contents = (id) bButtonImage.CGImage;
|
||||
[_view.layer addSublayer:_bButton];
|
||||
|
||||
|
||||
// create X Button
|
||||
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.contents = (id) xButtonImage.CGImage;
|
||||
[_view.layer addSublayer:_xButton];
|
||||
|
||||
|
||||
// create Y Button
|
||||
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.contents = (id) yButtonImage.CGImage;
|
||||
[_view.layer addSublayer:_yButton];
|
||||
|
||||
|
||||
// create Down button
|
||||
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.contents = (id) downButtonImage.CGImage;
|
||||
[_view.layer addSublayer:_downButton];
|
||||
|
||||
|
||||
// create Right button
|
||||
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.contents = (id) rightButtonImage.CGImage;
|
||||
[_view.layer addSublayer:_rightButton];
|
||||
|
||||
|
||||
// create Up button
|
||||
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.contents = (id) upButtonImage.CGImage;
|
||||
[_view.layer addSublayer:_upButton];
|
||||
|
||||
|
||||
// create Left button
|
||||
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);
|
||||
@@ -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.contents = (id) startButtonImage.CGImage;
|
||||
[_view.layer addSublayer:_startButton];
|
||||
|
||||
|
||||
// create Select button
|
||||
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);
|
||||
@@ -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.contents = (id) leftStickImage.CGImage;
|
||||
[_view.layer addSublayer:_leftStick];
|
||||
|
||||
|
||||
// create right analog stick
|
||||
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);
|
||||
@@ -463,7 +530,7 @@ static float L3_Y;
|
||||
float lsMaxY = LS_CENTER_Y + STICK_OUTER_SIZE / 2;
|
||||
float lsMinX = LS_CENTER_X - STICK_OUTER_SIZE / 2;
|
||||
float lsMinY = LS_CENTER_Y - STICK_OUTER_SIZE / 2;
|
||||
|
||||
|
||||
for (UITouch* touch in touches) {
|
||||
CGPoint touchLocation = [touch locationInView:_view];
|
||||
float xLoc = touchLocation.x;
|
||||
@@ -473,35 +540,55 @@ static float L3_Y;
|
||||
if (xLoc < lsMinX) xLoc = lsMinX;
|
||||
if (yLoc > lsMaxY) yLoc = lsMaxY;
|
||||
if (yLoc < lsMinY) yLoc = lsMinY;
|
||||
|
||||
|
||||
_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 yStickVal = (yLoc - LS_CENTER_Y) / (lsMaxY - LS_CENTER_Y);
|
||||
|
||||
|
||||
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
|
||||
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
|
||||
|
||||
|
||||
[_controllerSupport updateLeftStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
|
||||
|
||||
|
||||
updated = true;
|
||||
} else if (touch == _rsTouch) {
|
||||
if (xLoc > rsMaxX) xLoc = rsMaxX;
|
||||
if (xLoc < rsMinX) xLoc = rsMinX;
|
||||
if (yLoc > rsMaxY) yLoc = rsMaxY;
|
||||
if (yLoc < rsMinY) yLoc = rsMinY;
|
||||
|
||||
|
||||
_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 yStickVal = (yLoc - RS_CENTER_Y) / (rsMaxY - RS_CENTER_Y);
|
||||
|
||||
|
||||
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
|
||||
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
|
||||
|
||||
|
||||
[_controllerSupport updateRightStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
|
||||
|
||||
|
||||
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) {
|
||||
buttonTouch = true;
|
||||
} else if (touch == _bTouch) {
|
||||
@@ -510,14 +597,6 @@ static float L3_Y;
|
||||
buttonTouch = true;
|
||||
} else if (touch == _yTouch) {
|
||||
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) {
|
||||
buttonTouch = true;
|
||||
} else if (touch == _selectTouch) {
|
||||
@@ -535,11 +614,14 @@ static float L3_Y;
|
||||
} else if (touch == _r3Touch) {
|
||||
buttonTouch = true;
|
||||
}
|
||||
if ([_deadTouches containsObject:touch]) {
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
if (updated) {
|
||||
[_controllerSupport updateFinished:_controller];
|
||||
}
|
||||
return updated || buttonTouch;
|
||||
return updated || buttonTouch;
|
||||
}
|
||||
|
||||
- (BOOL)handleTouchDownEvent:touches {
|
||||
@@ -566,19 +648,19 @@ static float L3_Y;
|
||||
updated = true;
|
||||
} else if ([_upButton.presentationLayer hitTest:touchLocation]) {
|
||||
[_controllerSupport setButtonFlag:_controller flags:UP_FLAG];
|
||||
_upTouch = touch;
|
||||
_dpadTouch = touch;
|
||||
updated = true;
|
||||
} else if ([_downButton.presentationLayer hitTest:touchLocation]) {
|
||||
[_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG];
|
||||
_downTouch = touch;
|
||||
_dpadTouch = touch;
|
||||
updated = true;
|
||||
} else if ([_leftButton.presentationLayer hitTest:touchLocation]) {
|
||||
[_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG];
|
||||
_leftTouch = touch;
|
||||
_dpadTouch = touch;
|
||||
updated = true;
|
||||
} else if ([_rightButton.presentationLayer hitTest:touchLocation]) {
|
||||
[_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG];
|
||||
_rightTouch = touch;
|
||||
_dpadTouch = touch;
|
||||
updated = true;
|
||||
} else if ([_startButton.presentationLayer hitTest:touchLocation]) {
|
||||
[_controllerSupport setButtonFlag:_controller flags:PLAY_FLAG];
|
||||
@@ -653,6 +735,10 @@ static float L3_Y;
|
||||
} else if ([_edge.presentationLayer hitTest:touchLocation]) {
|
||||
_edgeTouch = touch;
|
||||
}
|
||||
if (!updated && !stickTouch && [self isInDeadZone:touch]) {
|
||||
[_deadTouches addObject:touch];
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
if (updated) {
|
||||
[_controllerSupport updateFinished:_controller];
|
||||
@@ -680,21 +766,10 @@ static float L3_Y;
|
||||
[_controllerSupport clearButtonFlag:_controller flags:Y_FLAG];
|
||||
_yTouch = nil;
|
||||
updated = true;
|
||||
} else if (touch == _upTouch) {
|
||||
[_controllerSupport clearButtonFlag:_controller flags:UP_FLAG];
|
||||
_upTouch = nil;
|
||||
updated = true;
|
||||
} 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;
|
||||
} else if (touch == _dpadTouch) {
|
||||
[_controllerSupport clearButtonFlag:_controller
|
||||
flags:UP_FLAG | DOWN_FLAG | LEFT_FLAG | RIGHT_FLAG];
|
||||
_dpadTouch = nil;
|
||||
updated = true;
|
||||
} else if (touch == _startTouch) {
|
||||
[_controllerSupport clearButtonFlag:_controller flags:PLAY_FLAG];
|
||||
@@ -744,15 +819,123 @@ static float L3_Y;
|
||||
touched = true;
|
||||
} else if (touch == _edgeTouch) {
|
||||
_edgeTouch = nil;
|
||||
if (![_edge.presentationLayer hitTest:[touch locationInView:_view]]) {
|
||||
if ([touch locationInView:_view].x >= _view.frame.size.width / 4) {
|
||||
[_edgeDelegate edgeSwiped];
|
||||
}
|
||||
}
|
||||
if ([_deadTouches containsObject:touch]) {
|
||||
[_deadTouches removeObject:touch];
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
if (updated) {
|
||||
[_controllerSupport updateFinished:_controller];
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -13,10 +13,13 @@
|
||||
#import "ControllerSupport.h"
|
||||
|
||||
@implementation StreamView {
|
||||
CGPoint touchLocation;
|
||||
CGPoint touchLocation, originalLocation;
|
||||
BOOL touchMoved;
|
||||
OnScreenControls* onScreenControls;
|
||||
|
||||
BOOL isDragging;
|
||||
NSTimer* dragTimer;
|
||||
|
||||
float xDeltaFactor;
|
||||
float yDeltaFactor;
|
||||
float screenFactor;
|
||||
@@ -32,7 +35,7 @@
|
||||
- (void) setupOnScreenControls:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate {
|
||||
onScreenControls = [[OnScreenControls alloc] initWithView:self controllerSup:controllerSupport swipeDelegate:swipeDelegate];
|
||||
DataManager* dataMan = [[DataManager alloc] init];
|
||||
OnScreenControlsLevel level = (OnScreenControlsLevel)[[dataMan retrieveSettings].onscreenControls integerValue];
|
||||
OnScreenControlsLevel level = (OnScreenControlsLevel)[[dataMan getSettings].onscreenControls integerValue];
|
||||
|
||||
if (level == OnScreenControlsLevelAuto) {
|
||||
[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 {
|
||||
Log(LOG_D, @"Touch down");
|
||||
if (![onScreenControls handleTouchDownEvent:touches]) {
|
||||
UITouch *touch = [[event allTouches] anyObject];
|
||||
touchLocation = [touch locationInView:self];
|
||||
originalLocation = touchLocation = [touch locationInView:self];
|
||||
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 {
|
||||
if (![onScreenControls handleTouchMovedEvent:touches]) {
|
||||
[dragTimer invalidate];
|
||||
dragTimer = nil;
|
||||
if ([[event allTouches] count] == 1) {
|
||||
UITouch *touch = [[event allTouches] anyObject];
|
||||
CGPoint currentLocation = [touch locationInView:self];
|
||||
@@ -67,20 +91,32 @@
|
||||
deltaX *= xDeltaFactor * screenFactor;
|
||||
deltaY *= yDeltaFactor * screenFactor;
|
||||
|
||||
LiSendMouseMoveEvent(deltaX, deltaY);
|
||||
|
||||
touchMoved = true;
|
||||
touchLocation = currentLocation;
|
||||
if (deltaX != 0 || deltaY != 0) {
|
||||
LiSendMouseMoveEvent(deltaX, deltaY);
|
||||
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) {
|
||||
CGPoint firstLocation = [[[[event allTouches] allObjects] objectAtIndex:0] locationInView:self];
|
||||
CGPoint secondLocation = [[[[event allTouches] allObjects] objectAtIndex:1] locationInView:self];
|
||||
|
||||
|
||||
CGPoint avgLocation = CGPointMake((firstLocation.x + secondLocation.x) / 2, (firstLocation.y + secondLocation.y) / 2);
|
||||
if (touchLocation.y != avgLocation.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;
|
||||
}
|
||||
}
|
||||
@@ -90,29 +126,49 @@
|
||||
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
|
||||
Log(LOG_D, @"Touch up");
|
||||
if (![onScreenControls handleTouchUpEvent:touches]) {
|
||||
[dragTimer invalidate];
|
||||
dragTimer = nil;
|
||||
if (!touchMoved) {
|
||||
if ([[event allTouches] count] == 2) {
|
||||
Log(LOG_D, @"Sending right mouse button press");
|
||||
|
||||
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
||||
|
||||
|
||||
// Wait 100 ms to simulate a real button press
|
||||
usleep(100 * 1000);
|
||||
|
||||
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
||||
|
||||
|
||||
} else {
|
||||
Log(LOG_D, @"Sending left mouse button press");
|
||||
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||
|
||||
// Wait 100 ms to simulate a real button press
|
||||
usleep(100 * 1000);
|
||||
|
||||
if (!isDragging){
|
||||
Log(LOG_D, @"Sending left mouse button press");
|
||||
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||
|
||||
// Wait 100 ms to simulate a real button press
|
||||
usleep(100 * 1000);
|
||||
}
|
||||
isDragging = false;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.9.2</string>
|
||||
<string>1.4.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
@@ -50,9 +50,9 @@
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<key>UIRequiresFullScreen</key>
|
||||
<true/>
|
||||
<key>UIStatusBarHidden~ipad</key>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<true/>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
@@ -64,5 +64,7 @@
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>_XCCurrentVersionName</key>
|
||||
<string>Moonlight v1.0.xcdatamodel</string>
|
||||
<string>Moonlight v1.0-2.xcdatamodel</string>
|
||||
</dict>
|
||||
</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"?>
|
||||
<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">
|
||||
<attribute name="id" attributeType="String" 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="height" attributeType="Integer 32" defaultValueString="720" 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"/>
|
||||
</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="120"/>
|
||||
<element name="Settings" positionX="0" positionY="0" width="128" height="135"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -7,20 +7,20 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "App.h"
|
||||
#import "TemporaryApp.h"
|
||||
#import "HttpManager.h"
|
||||
#import "Host.h"
|
||||
#import "TemporaryHost.h"
|
||||
|
||||
@protocol AppAssetCallback <NSObject>
|
||||
|
||||
- (void) receivedAssetForApp:(App*)app;
|
||||
- (void) receivedAssetForApp:(TemporaryApp*)app;
|
||||
|
||||
@end
|
||||
|
||||
@interface AppAssetManager : NSObject
|
||||
|
||||
- (id) initWithCallback:(id<AppAssetCallback>)callback;
|
||||
- (void) retrieveAssetsFromHost:(Host*)host;
|
||||
- (void) retrieveAssetsFromHost:(TemporaryHost*)host;
|
||||
- (void) stopRetrieving;
|
||||
|
||||
@end
|
||||
|
||||
@@ -28,8 +28,8 @@ static const int MAX_REQUEST_COUNT = 4;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) retrieveAssetsFromHost:(Host*)host {
|
||||
for (App* app in host.appList) {
|
||||
- (void) retrieveAssetsFromHost:(TemporaryHost*)host {
|
||||
for (TemporaryApp* app in host.appList) {
|
||||
if (app.image == nil) {
|
||||
AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init];
|
||||
retriever.app = app;
|
||||
@@ -45,7 +45,7 @@ static const int MAX_REQUEST_COUNT = 4;
|
||||
[_opQueue cancelAllOperations];
|
||||
}
|
||||
|
||||
- (void) sendCallBackForApp:(App*)app {
|
||||
- (void) sendCallBackForApp:(TemporaryApp*)app {
|
||||
[_callback receivedAssetForApp:app];
|
||||
}
|
||||
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Host.h"
|
||||
#import "App.h"
|
||||
#import "TemporaryHost.h"
|
||||
#import "TemporaryApp.h"
|
||||
#import "AppAssetManager.h"
|
||||
|
||||
@interface AppAssetRetriever : NSOperation
|
||||
|
||||
@property (nonatomic) Host* host;
|
||||
@property (nonatomic) App* app;
|
||||
@property (nonatomic) TemporaryHost* host;
|
||||
@property (nonatomic) TemporaryApp* app;
|
||||
@property (nonatomic) id<AppAssetCallback> callback;
|
||||
|
||||
@end
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#import "CryptoManager.h"
|
||||
#import "AppAssetResponse.h"
|
||||
#import "HttpRequest.h"
|
||||
#import "IdManager.h"
|
||||
|
||||
@implementation AppAssetRetriever
|
||||
static const double RETRY_DELAY = 2; // seconds
|
||||
@@ -21,7 +22,7 @@ static const int MAX_ATTEMPTS = 5;
|
||||
int attempts = 0;
|
||||
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];
|
||||
[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];
|
||||
}
|
||||
|
||||
- (void) sendCallbackForApp:(App*)app {
|
||||
- (void) sendCallbackForApp:(TemporaryApp*)app {
|
||||
[self.callback receivedAssetForApp:app];
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
@interface AppListResponse : NSObject <Response>
|
||||
|
||||
- (void)populateWithData:(NSData *)data;
|
||||
- (NSArray*) getAppList;
|
||||
- (NSSet*) getAppList;
|
||||
- (BOOL) isStatusOk;
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,23 +7,22 @@
|
||||
//
|
||||
|
||||
#import "AppListResponse.h"
|
||||
#import "App.h"
|
||||
#import "TemporaryApp.h"
|
||||
#import "DataManager.h"
|
||||
#import <libxml2/libxml/xmlreader.h>
|
||||
|
||||
@implementation AppListResponse {
|
||||
NSMutableArray* _appList;
|
||||
NSMutableSet* _appList;
|
||||
}
|
||||
@synthesize data, statusCode, statusMessage;
|
||||
|
||||
static const char* TAG_APP = "App";
|
||||
static const char* TAG_APP_TITLE = "AppTitle";
|
||||
static const char* TAG_APP_ID = "ID";
|
||||
static const char* TAG_APP_IS_RUNNING = "IsRunning";
|
||||
|
||||
- (void)populateWithData:(NSData *)xml {
|
||||
self.data = xml;
|
||||
_appList = [[NSMutableArray alloc] init];
|
||||
_appList = [[NSMutableSet alloc] init];
|
||||
[self parseData];
|
||||
}
|
||||
|
||||
@@ -60,7 +59,6 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
|
||||
self.statusMessage = statusMsg;
|
||||
|
||||
node = node->children;
|
||||
DataManager* dataMan = [[DataManager alloc] init];
|
||||
|
||||
while (node != NULL) {
|
||||
//Log(LOG_D, @"node: %s", node->name);
|
||||
@@ -68,7 +66,6 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
|
||||
xmlNodePtr appInfoNode = node->xmlChildrenNode;
|
||||
NSString* appName = @"";
|
||||
NSString* appId = nil;
|
||||
BOOL appIsRunning = NO;
|
||||
while (appInfoNode != NULL) {
|
||||
if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) {
|
||||
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];
|
||||
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;
|
||||
}
|
||||
if (appId != nil) {
|
||||
App* app = [dataMan createApp];
|
||||
TemporaryApp* app = [[TemporaryApp alloc] init];
|
||||
app.name = appName;
|
||||
app.id = appId;
|
||||
app.isRunning = appIsRunning;
|
||||
[_appList addObject:app];
|
||||
}
|
||||
}
|
||||
@@ -109,7 +97,7 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
|
||||
xmlFreeDoc(docPtr);
|
||||
}
|
||||
|
||||
- (NSArray*) getAppList {
|
||||
- (NSSet*) getAppList {
|
||||
return _appList;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MDNSManager.h"
|
||||
#import "Host.h"
|
||||
#import "TemporaryHost.h"
|
||||
|
||||
@protocol DiscoveryCallback <NSObject>
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
- (void) startDiscovery;
|
||||
- (void) stopDiscovery;
|
||||
- (void) stopDiscoveryBlocking;
|
||||
- (BOOL) addHostToDiscovery:(Host*)host;
|
||||
- (void) removeHostFromDiscovery:(Host*)host;
|
||||
- (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(Host*, NSString*))callback;
|
||||
- (BOOL) addHostToDiscovery:(TemporaryHost*)host;
|
||||
- (void) removeHostFromDiscovery:(TemporaryHost*)host;
|
||||
- (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(TemporaryHost*, NSString*))callback;
|
||||
|
||||
@end
|
||||
|
||||