Port for macOS (#311)
* merged moonlight-mac with moonlight-ios * reverted to the original project.pbxproj * cleaned up the code, fixed lots of unnecessary code duplications * multicontroller support (not tested) * new class that can be used for further modularization of the MainFrameViewController
|
After Width: | Height: | Size: 113 KiB |
BIN
Moonlight macOS/Assets.xcassets/AppIcon.appiconset/128x icon.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
Moonlight macOS/Assets.xcassets/AppIcon.appiconset/16x icon.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 30 KiB |
BIN
Moonlight macOS/Assets.xcassets/AppIcon.appiconset/256x icon.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
BIN
Moonlight macOS/Assets.xcassets/AppIcon.appiconset/32x icon.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 67 KiB |
BIN
Moonlight macOS/Assets.xcassets/AppIcon.appiconset/512x icon.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
Moonlight macOS/Assets.xcassets/AppIcon.appiconset/64x icon.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "16x16",
|
||||
"idiom" : "mac",
|
||||
"filename" : "16x icon.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "16x16",
|
||||
"idiom" : "mac",
|
||||
"filename" : "32x icon-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "32x32",
|
||||
"idiom" : "mac",
|
||||
"filename" : "32x icon.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "32x32",
|
||||
"idiom" : "mac",
|
||||
"filename" : "64x icon.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "128x128",
|
||||
"idiom" : "mac",
|
||||
"filename" : "128x icon.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "128x128",
|
||||
"idiom" : "mac",
|
||||
"filename" : "256x icon-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "256x256",
|
||||
"idiom" : "mac",
|
||||
"filename" : "256x icon.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "256x256",
|
||||
"idiom" : "mac",
|
||||
"filename" : "512x icon-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "512x512",
|
||||
"idiom" : "mac",
|
||||
"filename" : "512x icon.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "512x512",
|
||||
"idiom" : "mac",
|
||||
"filename" : "1024x icon-1.png",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
37
Moonlight macOS/Info.plist
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2018 Felix. All rights reserved.</string>
|
||||
<key>NSMainStoryboardFile</key>
|
||||
<string>Mac</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
17
Moonlight macOS/Input/Control.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Control.h
|
||||
// Moonlight macOS
|
||||
//
|
||||
// Created by Felix Kratz on 15.03.18.
|
||||
// Copyright © 2018 Felix Kratz. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef Control_h
|
||||
#define Control_h
|
||||
|
||||
#include <stdio.h>
|
||||
#import "ControllerSupport.h"
|
||||
|
||||
extern void initGamepad(ControllerSupport* controllerSupport);
|
||||
|
||||
#endif /* Control_h */
|
||||
218
Moonlight macOS/Input/Control.m
Normal file
@@ -0,0 +1,218 @@
|
||||
//
|
||||
// Control.m
|
||||
// Moonlight macOS
|
||||
//
|
||||
// Created by Felix Kratz on 15.03.18.
|
||||
// Copyright © 2018 Felix Kratz. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#include "Gamepad.h"
|
||||
#include "Control.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "Limelight.h"
|
||||
|
||||
#import "Moonlight-Swift.h"
|
||||
@class Controller;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
|
||||
Controller* _controller;
|
||||
ControllerSupport* _controllerSupport;
|
||||
NSMutableDictionary* _controllers;
|
||||
|
||||
typedef enum {
|
||||
SELECT,
|
||||
L3,
|
||||
R3,
|
||||
START,
|
||||
UP,
|
||||
RIGHT,
|
||||
DOWN,
|
||||
LEFT,
|
||||
LB = 10,
|
||||
RB,
|
||||
Y,
|
||||
B,
|
||||
A,
|
||||
X,
|
||||
} ControllerKeys;
|
||||
|
||||
typedef enum {
|
||||
LEFT_X,
|
||||
LEFT_Y,
|
||||
RIGHT_X,
|
||||
RIGHT_Y,
|
||||
LT = 14,
|
||||
RT,
|
||||
} ControllerAxis;
|
||||
|
||||
|
||||
void onButtonDown(struct Gamepad_device * device, unsigned int buttonID, double timestamp, void * context) {
|
||||
_controller = [_controllers objectForKey:[NSNumber numberWithInteger:device->deviceID]];
|
||||
switch (buttonID) {
|
||||
case SELECT:
|
||||
[_controllerSupport setButtonFlag:_controller flags:BACK_FLAG];
|
||||
break;
|
||||
case L3:
|
||||
[_controllerSupport setButtonFlag:_controller flags:LS_CLK_FLAG];
|
||||
break;
|
||||
case R3:
|
||||
[_controllerSupport setButtonFlag:_controller flags:RS_CLK_FLAG];
|
||||
break;
|
||||
case START:
|
||||
[_controllerSupport setButtonFlag:_controller flags:PLAY_FLAG];
|
||||
break;
|
||||
case UP:
|
||||
[_controllerSupport setButtonFlag:_controller flags:UP_FLAG];
|
||||
break;
|
||||
case RIGHT:
|
||||
[_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG];
|
||||
break;
|
||||
case DOWN:
|
||||
[_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG];
|
||||
break;
|
||||
case LEFT:
|
||||
[_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG];
|
||||
break;
|
||||
case LB:
|
||||
[_controllerSupport setButtonFlag:_controller flags:LB_FLAG];
|
||||
break;
|
||||
case RB:
|
||||
[_controllerSupport setButtonFlag:_controller flags:RB_FLAG];
|
||||
break;
|
||||
case Y:
|
||||
[_controllerSupport setButtonFlag:_controller flags:Y_FLAG];
|
||||
break;
|
||||
case B:
|
||||
[_controllerSupport setButtonFlag:_controller flags:B_FLAG];
|
||||
break;
|
||||
case A:
|
||||
[_controllerSupport setButtonFlag:_controller flags:A_FLAG];
|
||||
break;
|
||||
case X:
|
||||
[_controllerSupport setButtonFlag:_controller flags:X_FLAG];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
[_controllerSupport updateFinished:_controller];
|
||||
}
|
||||
|
||||
void onButtonUp(struct Gamepad_device * device, unsigned int buttonID, double timestamp, void * context) {
|
||||
_controller = [_controllers objectForKey:[NSNumber numberWithInteger:device->deviceID]];
|
||||
switch (buttonID) {
|
||||
case SELECT:
|
||||
[_controllerSupport clearButtonFlag:_controller flags:BACK_FLAG];
|
||||
break;
|
||||
case L3:
|
||||
[_controllerSupport clearButtonFlag:_controller flags:LS_CLK_FLAG];
|
||||
break;
|
||||
case R3:
|
||||
[_controllerSupport clearButtonFlag:_controller flags:RS_CLK_FLAG];
|
||||
break;
|
||||
case START:
|
||||
[_controllerSupport clearButtonFlag:_controller flags:PLAY_FLAG];
|
||||
break;
|
||||
case UP:
|
||||
[_controllerSupport clearButtonFlag:_controller flags:UP_FLAG];
|
||||
break;
|
||||
case RIGHT:
|
||||
[_controllerSupport clearButtonFlag:_controller flags:RIGHT_FLAG];
|
||||
break;
|
||||
case DOWN:
|
||||
[_controllerSupport clearButtonFlag:_controller flags:DOWN_FLAG];
|
||||
break;
|
||||
case LEFT:
|
||||
[_controllerSupport clearButtonFlag:_controller flags:LEFT_FLAG];
|
||||
break;
|
||||
case LB:
|
||||
[_controllerSupport clearButtonFlag:_controller flags:LB_FLAG];
|
||||
break;
|
||||
case RB:
|
||||
[_controllerSupport clearButtonFlag:_controller flags:RB_FLAG];
|
||||
break;
|
||||
case Y:
|
||||
[_controllerSupport clearButtonFlag:_controller flags:Y_FLAG];
|
||||
break;
|
||||
case B:
|
||||
[_controllerSupport clearButtonFlag:_controller flags:B_FLAG];
|
||||
break;
|
||||
case A:
|
||||
[_controllerSupport clearButtonFlag:_controller flags:A_FLAG];
|
||||
break;
|
||||
case X:
|
||||
[_controllerSupport clearButtonFlag:_controller flags:X_FLAG];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
[_controllerSupport updateFinished:_controller];
|
||||
}
|
||||
|
||||
void onAxisMoved(struct Gamepad_device * device, unsigned int axisID, float value, float lastValue, double timestamp, void * context) {
|
||||
if (fabsf(lastValue - value) > 0.01) {
|
||||
_controller = [_controllers objectForKey:[NSNumber numberWithInteger:device->deviceID]];
|
||||
// The dualshock controller has much more than these axis because of the motion axis, so it
|
||||
// is better to call the updateFinished in the cases, because otherwise all of these
|
||||
// motion axis will also trigger an updateFinished event.
|
||||
switch (axisID) {
|
||||
case LEFT_X:
|
||||
_controller.lastLeftStickX = value * 0X7FFE;
|
||||
[_controllerSupport updateFinished:_controller];
|
||||
break;
|
||||
case LEFT_Y:
|
||||
_controller.lastLeftStickY = -value * 0X7FFE;
|
||||
[_controllerSupport updateFinished:_controller];
|
||||
break;
|
||||
case RIGHT_X:
|
||||
_controller.lastRightStickX = value * 0X7FFE;
|
||||
[_controllerSupport updateFinished:_controller];
|
||||
break;
|
||||
case RIGHT_Y:
|
||||
_controller.lastRightStickY = -value * 0X7FFE;
|
||||
[_controllerSupport updateFinished:_controller];
|
||||
break;
|
||||
case LT:
|
||||
_controller.lastLeftTrigger = value * 0xFF;
|
||||
[_controllerSupport updateFinished:_controller];
|
||||
break;
|
||||
case RT:
|
||||
_controller.lastRightTrigger = value * 0xFF;
|
||||
[_controllerSupport updateFinished:_controller];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onDeviceAttached(struct Gamepad_device * device, void * context) {
|
||||
[_controllerSupport assignGamepad:device];
|
||||
_controllers = [_controllerSupport getControllers];
|
||||
}
|
||||
|
||||
void onDeviceRemoved(struct Gamepad_device * device, void * context) {
|
||||
[_controllerSupport removeGamepad:device];
|
||||
_controllers = [_controllerSupport getControllers];
|
||||
}
|
||||
|
||||
void initGamepad(ControllerSupport* controllerSupport) {
|
||||
_controllerSupport = controllerSupport;
|
||||
Gamepad_deviceAttachFunc(onDeviceAttached, NULL);
|
||||
Gamepad_deviceRemoveFunc(onDeviceRemoved, NULL);
|
||||
Gamepad_buttonDownFunc(onButtonDown, NULL);
|
||||
Gamepad_buttonUpFunc(onButtonUp, NULL);
|
||||
Gamepad_axisMoveFunc(onAxisMoved, NULL);
|
||||
Gamepad_init();
|
||||
_controller = [[Controller alloc] init];
|
||||
}
|
||||
4
Moonlight macOS/Input/Moonlight macOS-Bridging-Header.h
Normal file
@@ -0,0 +1,4 @@
|
||||
//
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
12
Moonlight macOS/Input/StreamView.h
Normal file
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// StreamView.h
|
||||
// Moonlight macOS
|
||||
//
|
||||
// Created by Felix Kratz on 10.03.18.
|
||||
// Copyright (c) 2018 Felix Kratz. All rights reserved.
|
||||
//
|
||||
|
||||
@interface StreamView : NSView
|
||||
|
||||
|
||||
@end
|
||||
114
Moonlight macOS/Input/StreamView.m
Normal file
@@ -0,0 +1,114 @@
|
||||
//
|
||||
// StreamView.m
|
||||
// Moonlight macOS
|
||||
//
|
||||
// Created by Felix Kratz on 10.3.18.
|
||||
// Copyright (c) 2018 Felix Kratz. All rights reserved.
|
||||
//
|
||||
|
||||
#import "StreamView.h"
|
||||
#include <Limelight.h>
|
||||
#import "DataManager.h"
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include "keyboardTranslation.h"
|
||||
|
||||
@implementation StreamView {
|
||||
BOOL isDragging;
|
||||
NSTrackingArea *trackingArea;
|
||||
}
|
||||
|
||||
- (void) updateTrackingAreas {
|
||||
|
||||
// This will be the area used to track the mouse movement
|
||||
if (trackingArea != nil) {
|
||||
[self removeTrackingArea:trackingArea];
|
||||
}
|
||||
NSTrackingAreaOptions options = (NSTrackingActiveAlways | NSTrackingInVisibleRect |
|
||||
NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved);
|
||||
|
||||
trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
|
||||
options:options
|
||||
owner:self
|
||||
userInfo:nil];
|
||||
[self addTrackingArea:trackingArea];
|
||||
}
|
||||
|
||||
-(void)mouseDragged:(NSEvent *)event {
|
||||
if (isDragging) {
|
||||
[self mouseMoved:event];
|
||||
}
|
||||
else {
|
||||
[self mouseDown:event];
|
||||
isDragging = true;
|
||||
}
|
||||
}
|
||||
|
||||
-(void)rightMouseDragged:(NSEvent *)event {
|
||||
if (isDragging) {
|
||||
[self mouseMoved:event];
|
||||
}
|
||||
else {
|
||||
[self rightMouseDown:event];
|
||||
isDragging = true;
|
||||
}
|
||||
}
|
||||
|
||||
-(void)scrollWheel:(NSEvent *)event {
|
||||
LiSendScrollEvent(event.scrollingDeltaY);
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)mouseEvent {
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)mouseUp:(NSEvent *)mouseEvent {
|
||||
isDragging = false;
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)rightMouseUp:(NSEvent *)mouseEvent {
|
||||
isDragging = false;
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)rightMouseDown:(NSEvent *)mouseEvent {
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)mouseMoved:(NSEvent *)mouseEvent {
|
||||
LiSendMouseMoveEvent(mouseEvent.deltaX, mouseEvent.deltaY);
|
||||
}
|
||||
|
||||
-(void)keyDown:(NSEvent *)event {
|
||||
unsigned char keyChar = keyCharFromKeyCode(event.keyCode);
|
||||
printf("DOWN: KeyCode: %hu, keyChar: %d, keyModifier: %lu \n", event.keyCode, keyChar, event.modifierFlags);
|
||||
|
||||
LiSendKeyboardEvent(keyChar, KEY_ACTION_DOWN, modifierFlagForKeyModifier(event.modifierFlags));
|
||||
}
|
||||
|
||||
-(void)keyUp:(NSEvent *)event {
|
||||
unsigned char keyChar = keyCharFromKeyCode(event.keyCode);
|
||||
printf("UP: KeyChar: %d \n‚", keyChar);
|
||||
LiSendKeyboardEvent(keyChar, KEY_ACTION_UP, modifierFlagForKeyModifier(event.modifierFlags));
|
||||
}
|
||||
|
||||
- (void)flagsChanged:(NSEvent *)event
|
||||
{
|
||||
unsigned char keyChar = keyCodeFromModifierKey(event.modifierFlags);
|
||||
if(keyChar) {
|
||||
printf("DOWN: FlagChanged: %hhu \n", keyChar);
|
||||
LiSendKeyboardEvent(keyChar, KEY_ACTION_DOWN, 0x00);
|
||||
}
|
||||
else {
|
||||
LiSendKeyboardEvent(58, KEY_ACTION_UP, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
18
Moonlight macOS/Moonlight macOS.entitlements
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.bluetooth</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.usb</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
20
Moonlight macOS/Utility/keepAlive.h
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// keepAlive.h
|
||||
// LittleHelper
|
||||
//
|
||||
// Created by Felix Kratz on 31.10.17.
|
||||
// Copyright © 2017 Felix Kratz. All rights reserved.
|
||||
//
|
||||
#import <Foundation/Foundation.h>
|
||||
#ifndef keepAlive_h
|
||||
#define keepAlive_h
|
||||
|
||||
@interface keepAlive : NSObject
|
||||
|
||||
+(void) keepSystemAlive;
|
||||
+(void) allowSleep;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* keepAlive_h */
|
||||
|
||||
30
Moonlight macOS/Utility/keepAlive.m
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// keepAlive.m
|
||||
// LittleHelper
|
||||
//
|
||||
// Created by Felix Kratz on 31.10.17.
|
||||
// Copyright © 2017 Felix Kratz. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <IOKit/pwr_mgt/IOPMLib.h>
|
||||
#import "keepAlive.h"
|
||||
|
||||
|
||||
@implementation keepAlive
|
||||
|
||||
CFStringRef reasonForActivity= CFSTR("Moonlight keeps the system awake");
|
||||
IOPMAssertionID assertionID;
|
||||
|
||||
+(void) keepSystemAlive
|
||||
{
|
||||
|
||||
IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
|
||||
kIOPMAssertionLevelOn, reasonForActivity, &assertionID);
|
||||
}
|
||||
|
||||
+(void) allowSleep
|
||||
{
|
||||
IOPMAssertionRelease(assertionID);
|
||||
}
|
||||
@end
|
||||
18
Moonlight macOS/Utility/keyboardTranslation.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// keyboardTranslation.h
|
||||
// Moonlight macOS
|
||||
//
|
||||
// Created by Felix Kratz on 10.03.18.
|
||||
// Copyright © 2018 Felix Kratz. All rights reserved.
|
||||
//
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
#ifndef keyboardTranslation_h
|
||||
#define keyboardTranslation_h
|
||||
|
||||
CGKeyCode keyCharFromKeyCode(CGKeyCode keyCode);
|
||||
CGKeyCode keyCodeFromModifierKey(NSEventModifierFlags keyModifier);
|
||||
char modifierFlagForKeyModifier(NSEventModifierFlags keyModifier);
|
||||
|
||||
#endif /* keyboardTranslation_h */
|
||||
143
Moonlight macOS/Utility/keyboardTranslation.m
Normal file
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// keyboardTranslation.m
|
||||
// Moonlight macOS
|
||||
//
|
||||
// Created by Felix Kratz on 10.03.18.
|
||||
// Copyright © 2018 Felix Kratz. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "keyboardTranslation.h"
|
||||
#import <Limelight.h>
|
||||
|
||||
typedef enum {
|
||||
NOKEY,
|
||||
VK_BACKSPACE = 0x08,
|
||||
VK_TAB = 0x09,
|
||||
VK_ENTER = 0x0D,
|
||||
VK_SPACE = 0x20,
|
||||
VK_LEFT = 0x25,
|
||||
VK_UP,
|
||||
VK_RIGHT,
|
||||
VK_DOWN,
|
||||
VK_SHIFT = 0xA0,
|
||||
VK_CTRL = 0xA2,
|
||||
VK_ALT = 0xA4,
|
||||
VK_COMMA = 0xBC,
|
||||
VK_MINUS = 0xBD,
|
||||
VK_PERIOD = 0xBE,
|
||||
VK_ESC = 0x1B,
|
||||
VK_F1 = 0x70,
|
||||
VK_F2,
|
||||
VK_F3,
|
||||
VK_F4,
|
||||
VK_F5,
|
||||
VK_F6,
|
||||
VK_F7,
|
||||
VK_F8,
|
||||
VK_F9,
|
||||
VK_F10,
|
||||
VK_F11,
|
||||
VK_F12,
|
||||
VK_F13,
|
||||
VK_F14,
|
||||
VK_F15,
|
||||
VK_DEL = 0x7F,
|
||||
} SpecialKeyCodes;
|
||||
|
||||
CGKeyCode keyCodeFromModifierKey(NSEventModifierFlags keyModifier) {
|
||||
if (keyModifier & kCGEventFlagMaskShift) {
|
||||
return VK_SHIFT;
|
||||
}
|
||||
if (keyModifier & kCGEventFlagMaskAlternate) {
|
||||
return VK_ALT;
|
||||
}
|
||||
if (keyModifier & kCGEventFlagMaskControl) {
|
||||
return VK_CTRL;
|
||||
}
|
||||
return NOKEY;
|
||||
}
|
||||
|
||||
char modifierFlagForKeyModifier(NSEventModifierFlags keyModifier) {
|
||||
if (keyModifier & kCGEventFlagMaskShift) {
|
||||
return MODIFIER_SHIFT;
|
||||
}
|
||||
if (keyModifier & kCGEventFlagMaskAlternate) {
|
||||
return MODIFIER_ALT;
|
||||
}
|
||||
if (keyModifier & kCGEventFlagMaskControl) {
|
||||
return MODIFIER_CTRL;
|
||||
}
|
||||
return NOKEY;
|
||||
}
|
||||
|
||||
CGKeyCode keyCharFromKeyCode(CGKeyCode keyCode) {
|
||||
switch (keyCode) {
|
||||
case kVK_ANSI_A: return 'A';
|
||||
case kVK_ANSI_S: return 'S';
|
||||
case kVK_ANSI_D: return 'D';
|
||||
case kVK_ANSI_F: return 'F';
|
||||
case kVK_ANSI_H: return 'H';
|
||||
case kVK_ANSI_G: return 'G';
|
||||
case kVK_ANSI_Y: return 'Y';
|
||||
case kVK_ANSI_X: return 'X';
|
||||
case kVK_ANSI_C: return 'C';
|
||||
case kVK_ANSI_V: return 'V';
|
||||
case kVK_ANSI_B: return 'B';
|
||||
case kVK_ANSI_Q: return 'Q';
|
||||
case kVK_ANSI_W: return 'W';
|
||||
case kVK_ANSI_E: return 'E';
|
||||
case kVK_ANSI_R: return 'R';
|
||||
case kVK_ANSI_Z: return 'Z';
|
||||
case kVK_ANSI_T: return 'T';
|
||||
case kVK_ANSI_1: return '1';
|
||||
case kVK_ANSI_2: return '2';
|
||||
case kVK_ANSI_3: return '3';
|
||||
case kVK_ANSI_4: return '4';
|
||||
case kVK_ANSI_6: return '6';
|
||||
case kVK_ANSI_5: return '5';
|
||||
case kVK_ANSI_9: return '9';
|
||||
case kVK_ANSI_7: return '7';
|
||||
case kVK_ANSI_8: return '8';
|
||||
case kVK_ANSI_0: return '0';
|
||||
case kVK_ANSI_O: return 'O';
|
||||
case kVK_ANSI_U: return 'U';
|
||||
case kVK_ANSI_I: return 'I';
|
||||
case kVK_ANSI_P: return 'P';
|
||||
case kVK_ANSI_L: return 'L';
|
||||
case kVK_ANSI_J: return 'J';
|
||||
case kVK_ANSI_K: return 'K';
|
||||
case kVK_ANSI_N: return 'N';
|
||||
case kVK_ANSI_M: return 'M';
|
||||
case kVK_Return: return VK_ENTER;
|
||||
case kVK_ANSI_Period: return VK_PERIOD;
|
||||
case kVK_ANSI_Comma: return VK_COMMA;
|
||||
case kVK_ANSI_Minus: return VK_MINUS;
|
||||
case kVK_Tab: return VK_TAB;
|
||||
case kVK_Space: return VK_SPACE;
|
||||
case kVK_Delete: return VK_BACKSPACE;
|
||||
case kVK_Escape: return VK_ESC;
|
||||
case kVK_F1: return VK_F1;
|
||||
case kVK_F2: return VK_F2;
|
||||
case kVK_F3: return VK_F3;
|
||||
case kVK_F4: return VK_F4;
|
||||
case kVK_F5: return VK_F5;
|
||||
case kVK_F6: return VK_F6;
|
||||
case kVK_F7: return VK_F7;
|
||||
case kVK_F8: return VK_F8;
|
||||
case kVK_F9: return VK_F9;
|
||||
case kVK_F10: return VK_F10;
|
||||
case kVK_F11: return VK_F11;
|
||||
case kVK_F12: return VK_F12;
|
||||
case kVK_F13: return VK_F13;
|
||||
case kVK_F14: return VK_F14;
|
||||
case kVK_F15: return VK_F15;
|
||||
case kVK_LeftArrow: return VK_LEFT;
|
||||
case kVK_RightArrow: return VK_RIGHT;
|
||||
case kVK_DownArrow: return VK_DOWN;
|
||||
case kVK_UpArrow: return VK_UP;
|
||||
|
||||
default:
|
||||
return NOKEY;
|
||||
}
|
||||
}
|
||||
23
Moonlight macOS/ViewController/SettingsViewController.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// SettingsViewController.h
|
||||
// Moonlight macOS
|
||||
//
|
||||
// Created by Felix Kratz on 11.03.18.
|
||||
// Copyright © 2018 Felix Kratz. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface SettingsViewController : NSViewController
|
||||
@property (weak) IBOutlet NSTextField *textFieldResolutionHeight;
|
||||
@property (weak) IBOutlet NSTextField *textFieldResolutionWidth;
|
||||
@property (weak) IBOutlet NSTextField *textFieldBitrate;
|
||||
@property (weak) IBOutlet NSTextField *textFieldFPS;
|
||||
@property (weak) IBOutlet NSButton *buttonStreamingRemotelyToggle;
|
||||
- (NSString*) getCurrentHost;
|
||||
- (NSInteger) getChosenBitrate;
|
||||
- (NSInteger) getChosenStreamWidth;
|
||||
- (NSInteger) getChosenStreamHeight;
|
||||
- (NSInteger) getChosenFrameRate;
|
||||
- (NSInteger) getRemoteOptions;
|
||||
@end
|
||||
71
Moonlight macOS/ViewController/SettingsViewController.m
Normal file
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// SettingsViewController.m
|
||||
// Moonlight macOS
|
||||
//
|
||||
// Created by Felix Kratz on 11.03.18.
|
||||
// Copyright © 2018 Felix Kratz. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SettingsViewController.h"
|
||||
#import "DataManager.h"
|
||||
|
||||
@interface SettingsViewController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation SettingsViewController
|
||||
|
||||
NSString* host;
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[self loadSettings];
|
||||
// Do view setup here.
|
||||
}
|
||||
|
||||
- (void) controlTextDidChange:(NSNotification *)obj {
|
||||
//[self saveSettings];
|
||||
}
|
||||
|
||||
- (NSInteger) getRemoteOptions {
|
||||
return _buttonStreamingRemotelyToggle.state == NSOnState ? 1 : 0;
|
||||
}
|
||||
|
||||
- (NSInteger) getChosenFrameRate {
|
||||
return _textFieldFPS.integerValue;
|
||||
}
|
||||
|
||||
- (NSInteger) getChosenStreamHeight {
|
||||
return _textFieldResolutionHeight.integerValue;
|
||||
}
|
||||
|
||||
- (NSInteger) getChosenStreamWidth {
|
||||
return _textFieldResolutionWidth.integerValue;
|
||||
}
|
||||
|
||||
- (NSInteger) getChosenBitrate {
|
||||
return _textFieldBitrate.integerValue;
|
||||
}
|
||||
|
||||
- (void) loadSettings {
|
||||
DataManager* dataMan = [[DataManager alloc] init];
|
||||
TemporarySettings* currentSettings = [dataMan getSettings];
|
||||
|
||||
// Bitrate is persisted in kbps
|
||||
_textFieldBitrate.integerValue = [currentSettings.bitrate integerValue];
|
||||
_textFieldFPS.integerValue = [currentSettings.framerate integerValue];
|
||||
_textFieldResolutionHeight.integerValue = [currentSettings.height integerValue];
|
||||
_textFieldResolutionWidth.integerValue = [currentSettings.width integerValue];
|
||||
_buttonStreamingRemotelyToggle.state = [currentSettings.streamingRemotely integerValue] == 0 ? NSOffState: NSOnState;
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
-(NSString*) getCurrentHost {
|
||||
return host;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
26
Moonlight macOS/ViewController/StreamFrameViewController.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// StreamFrameViewController.h
|
||||
// Moonlight macOS
|
||||
//
|
||||
// Created by Felix Kratz on 09.03.18.
|
||||
// Copyright © 2018 Felix Kratz. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "Connection.h"
|
||||
#import "StreamConfiguration.h"
|
||||
#import "StreamView.h"
|
||||
#import "ViewController.h"
|
||||
|
||||
@interface StreamFrameViewController : NSViewController <ConnectionCallbacks>
|
||||
|
||||
- (ViewController*) _origin;
|
||||
|
||||
- (void)setOrigin: (ViewController*) viewController;
|
||||
|
||||
@property (nonatomic) StreamConfiguration* streamConfig;
|
||||
@property (strong) IBOutlet StreamView *streamView;
|
||||
@property (weak) IBOutlet NSProgressIndicator *progressIndicator;
|
||||
@property (weak) IBOutlet NSTextField *stageLabel;
|
||||
|
||||
@end
|
||||
140
Moonlight macOS/ViewController/StreamFrameViewController.m
Normal file
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// StreamFrameViewController.m
|
||||
// Moonlight macOS
|
||||
//
|
||||
// Created by Felix Kratz on 09.03.18.
|
||||
// Copyright © 2018 Felix Kratz. All rights reserved.
|
||||
//
|
||||
|
||||
#import "StreamFrameViewController.h"
|
||||
#import "VideoDecoderRenderer.h"
|
||||
#import "StreamManager.h"
|
||||
#import "Gamepad.h"
|
||||
#import "keepAlive.h"
|
||||
#import "ControllerSupport.h"
|
||||
|
||||
@interface StreamFrameViewController ()
|
||||
@end
|
||||
|
||||
@implementation StreamFrameViewController {
|
||||
StreamManager *_streamMan;
|
||||
StreamConfiguration *_streamConfig;
|
||||
NSTimer* _eventTimer;
|
||||
NSTimer* _searchTimer;
|
||||
ViewController* _origin;
|
||||
ControllerSupport* _controllerSupport;
|
||||
}
|
||||
|
||||
-(ViewController*) _origin {
|
||||
return _origin;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[keepAlive keepSystemAlive];
|
||||
self.streamConfig = _streamConfig;
|
||||
|
||||
_streamMan = [[StreamManager alloc] initWithConfig:self.streamConfig
|
||||
renderView:self.view
|
||||
connectionCallbacks:self];
|
||||
NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
|
||||
[opQueue addOperation:_streamMan];
|
||||
|
||||
// Initialize the controllers (GC and IOHID)
|
||||
// I have not tested it, but i think there will be a bug, when mixing GC and IOHID Controllers, because all GCControllers also register as IOHID Controllers.
|
||||
// To fix this, we need to get the IOHIDDeviceRef for the GCController and compare it with every IOHID Controller.
|
||||
// This shouldn't be a problem as long as this will not be put on the mac app store, as the IOHIDDeviceRef is a private field.
|
||||
// The other "fix" would be to disable explicit GC support for the mac version for now.
|
||||
// Can someone test this?
|
||||
_controllerSupport = [[ControllerSupport alloc] init];
|
||||
|
||||
// The gamepad currently gets polled at 60Hz, this could very well be set as 1/Framerate in the future.
|
||||
_eventTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/60.0 target:self selector:@selector(eventTimerTick) userInfo:nil repeats:true];
|
||||
|
||||
// We search for new devices every second.
|
||||
_searchTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(searchTimerTick) userInfo:nil repeats:true];
|
||||
}
|
||||
|
||||
- (void)eventTimerTick {
|
||||
Gamepad_processEvents();
|
||||
}
|
||||
|
||||
- (void)searchTimerTick {
|
||||
Gamepad_detectDevices();
|
||||
}
|
||||
|
||||
- (void) viewDidAppear {
|
||||
[super viewDidAppear];
|
||||
|
||||
// Hide the cursor and disconnect it from the mouse movement
|
||||
[NSCursor hide];
|
||||
CGAssociateMouseAndMouseCursorPosition(false);
|
||||
|
||||
//During the setup the window should not be resizable, but to use the fullscreen feature of macOS it has to be resizable.
|
||||
[self.view.window setStyleMask:[self.view.window styleMask] | NSWindowStyleMaskResizable];
|
||||
|
||||
if (self.view.bounds.size.height != NSScreen.mainScreen.frame.size.height || self.view.bounds.size.width != NSScreen.mainScreen.frame.size.width) {
|
||||
[self.view.window toggleFullScreen:self];
|
||||
}
|
||||
[_progressIndicator startAnimation:nil];
|
||||
[_origin dismissController:nil];
|
||||
_origin = nil;
|
||||
}
|
||||
|
||||
-(void)viewWillDisappear {
|
||||
[NSCursor unhide];
|
||||
[keepAlive allowSleep];
|
||||
[_streamMan stopStream];
|
||||
CGAssociateMouseAndMouseCursorPosition(true);
|
||||
if (self.view.bounds.size.height == NSScreen.mainScreen.frame.size.height && self.view.bounds.size.width == NSScreen.mainScreen.frame.size.width) {
|
||||
[self.view.window toggleFullScreen:self];
|
||||
[self.view.window setStyleMask:[self.view.window styleMask] & ~NSWindowStyleMaskResizable];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)connectionStarted {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[_progressIndicator stopAnimation:nil];
|
||||
_progressIndicator.hidden = true;
|
||||
_stageLabel.stringValue = @"Waiting for the first frame";
|
||||
});
|
||||
}
|
||||
|
||||
- (void)connectionTerminated:(long)errorCode {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSLog(@"error has occured: %ld", errorCode);
|
||||
NSStoryboard *storyBoard = [NSStoryboard storyboardWithName:@"Mac" bundle:nil];
|
||||
ViewController* view = (ViewController*)[storyBoard instantiateControllerWithIdentifier :@"setupFrameVC"];
|
||||
[view setError:1];
|
||||
self.view.window.contentViewController = view;
|
||||
});
|
||||
}
|
||||
|
||||
- (void)setOrigin: (ViewController*) viewController
|
||||
{
|
||||
_origin = viewController;
|
||||
}
|
||||
|
||||
- (void)displayMessage:(const char *)message {
|
||||
|
||||
}
|
||||
|
||||
- (void)displayTransientMessage:(const char *)message {
|
||||
}
|
||||
|
||||
- (void)launchFailed:(NSString *)message {
|
||||
|
||||
}
|
||||
|
||||
- (void)stageComplete:(const char *)stageName {
|
||||
|
||||
}
|
||||
|
||||
- (void)stageFailed:(const char *)stageName withError:(long)errorCode {
|
||||
|
||||
}
|
||||
|
||||
- (void)stageStarting:(const char *)stageName {
|
||||
}
|
||||
|
||||
@end
|
||||
35
Moonlight macOS/ViewController/ViewController.h
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// ViewController.h
|
||||
// Moonlight macOS
|
||||
//
|
||||
// Created by Felix Kratz on 09.03.18.
|
||||
// Copyright © 2018 Felix Kratz. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#import "PairManager.h"
|
||||
#import "StreamConfiguration.h"
|
||||
|
||||
@interface ViewController : NSViewController <PairCallback, NSURLConnectionDelegate>
|
||||
|
||||
- (IBAction)buttonLaunchPressed:(id)sender;
|
||||
- (IBAction)textFieldAction:(id)sender;
|
||||
- (IBAction)buttonConnectPressed:(id)sender;
|
||||
- (IBAction)buttonSettingsPressed:(id)sender;
|
||||
- (IBAction)popupButtonSelectionPressed:(id)sender;
|
||||
|
||||
- (void)setError:(long)errorCode;
|
||||
- (long) error;
|
||||
|
||||
@property (weak) IBOutlet NSLayoutConstraint *layoutConstraintSetupFrame;
|
||||
@property (weak) IBOutlet NSButton *buttonConnect;
|
||||
@property (weak) IBOutlet NSTextField *textFieldHost;
|
||||
@property (weak) IBOutlet NSButton *buttonSettings;
|
||||
@property (weak) IBOutlet NSButton *buttonLaunch;
|
||||
@property (weak) IBOutlet NSPopUpButton *popupButtonSelection;
|
||||
@property (weak) IBOutlet NSView *containerViewController;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
228
Moonlight macOS/ViewController/ViewController.m
Normal file
@@ -0,0 +1,228 @@
|
||||
//
|
||||
// ViewController.m
|
||||
// Moonlight macOS
|
||||
//
|
||||
// Created by Felix Kratz on 09.03.18.
|
||||
// Copyright © 2018 Felix Kratz. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ViewController.h"
|
||||
|
||||
#import "CryptoManager.h"
|
||||
#import "HttpManager.h"
|
||||
#import "Connection.h"
|
||||
#import "StreamManager.h"
|
||||
#import "Utils.h"
|
||||
#import "DataManager.h"
|
||||
#import "TemporarySettings.h"
|
||||
#import "WakeOnLanManager.h"
|
||||
#import "AppListResponse.h"
|
||||
#import "ServerInfoResponse.h"
|
||||
#import "StreamFrameViewController.h"
|
||||
#import "TemporaryApp.h"
|
||||
#import "IdManager.h"
|
||||
#import "SettingsViewController.h"
|
||||
#import "ConnectionHelper.h"
|
||||
|
||||
@implementation ViewController{
|
||||
NSOperationQueue* _opQueue;
|
||||
TemporaryHost* _selectedHost;
|
||||
NSString* _uniqueId;
|
||||
NSData* _cert;
|
||||
StreamConfiguration* _streamConfig;
|
||||
NSArray* _sortedAppList;
|
||||
NSSet* _appList;
|
||||
NSString* _host;
|
||||
SettingsViewController *_settingsView;
|
||||
CGFloat settingsFrameHeight;
|
||||
bool showSettings;
|
||||
NSAlert* _alert;
|
||||
long error;
|
||||
}
|
||||
|
||||
- (long)error {
|
||||
return error;
|
||||
}
|
||||
|
||||
- (void)setError:(long)errorCode {
|
||||
error = errorCode;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[CryptoManager generateKeyPairUsingSSl];
|
||||
_uniqueId = [IdManager getUniqueId];
|
||||
_cert = [CryptoManager readCertFromFile];
|
||||
|
||||
_opQueue = [[NSOperationQueue alloc] init];
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
- (void)viewDidAppear {
|
||||
[super viewDidAppear];
|
||||
|
||||
if (self.view.bounds.size.height == NSScreen.mainScreen.frame.size.height && self.view.bounds.size.width == NSScreen.mainScreen.frame.size.width)
|
||||
{
|
||||
[self.view.window toggleFullScreen:self];
|
||||
[self.view.window setStyleMask:[self.view.window styleMask] & ~NSWindowStyleMaskResizable];
|
||||
return;
|
||||
}
|
||||
[_buttonLaunch setEnabled:false];
|
||||
[_popupButtonSelection removeAllItems];
|
||||
_settingsView = [self.childViewControllers lastObject];
|
||||
|
||||
if (_settingsView.getCurrentHost != nil)
|
||||
_textFieldHost.stringValue = _settingsView.getCurrentHost;
|
||||
settingsFrameHeight = _layoutConstraintSetupFrame.constant;
|
||||
_layoutConstraintSetupFrame.constant = 0;
|
||||
showSettings = false;
|
||||
|
||||
if (error != 0) {
|
||||
[self showAlert:[NSString stringWithFormat: @"The connection terminated."]];
|
||||
}
|
||||
}
|
||||
|
||||
-(void) showAlert:(NSString*) message {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
_alert = [NSAlert new];
|
||||
_alert.messageText = message;
|
||||
[_alert beginSheetModalForWindow:[self.view window] completionHandler:^(NSInteger result) {
|
||||
NSLog(@"Success");
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
- (void)setRepresentedObject:(id)representedObject {
|
||||
[super setRepresentedObject:representedObject];
|
||||
|
||||
// Update the view, if already loaded.
|
||||
}
|
||||
|
||||
- (void) saveSettings {
|
||||
DataManager* dataMan = [[DataManager alloc] init];
|
||||
NSInteger framerate = [_settingsView getChosenFrameRate];
|
||||
NSInteger height = [_settingsView getChosenStreamHeight];
|
||||
NSInteger width = [_settingsView getChosenStreamWidth];
|
||||
NSInteger streamingRemotely = [_settingsView getRemoteOptions];
|
||||
NSInteger bitrate = [_settingsView getChosenBitrate];
|
||||
[dataMan saveSettingsWithBitrate:bitrate framerate:framerate height:height width:width
|
||||
onscreenControls:0 remote:streamingRemotely];
|
||||
}
|
||||
|
||||
|
||||
- (void)controlTextDidChange:(NSNotification *)obj {
|
||||
|
||||
}
|
||||
|
||||
- (IBAction)buttonLaunchPressed:(id)sender {
|
||||
[self saveSettings];
|
||||
DataManager* dataMan = [[DataManager alloc] init];
|
||||
TemporarySettings* streamSettings = [dataMan getSettings];
|
||||
_streamConfig = [[StreamConfiguration alloc] init];
|
||||
_streamConfig.frameRate = [streamSettings.framerate intValue];
|
||||
_streamConfig.bitRate = [streamSettings.bitrate intValue];
|
||||
_streamConfig.height = [streamSettings.height intValue];
|
||||
_streamConfig.width = [streamSettings.width intValue];
|
||||
_streamConfig.streamingRemotely = [streamSettings.streamingRemotely intValue];
|
||||
_streamConfig.host = _textFieldHost.stringValue;
|
||||
_streamConfig.appID = [_sortedAppList[_popupButtonSelection.indexOfSelectedItem] id];
|
||||
[self transitionToStreamView];
|
||||
}
|
||||
|
||||
- (IBAction)textFieldAction:(id)sender {
|
||||
[self buttonConnectPressed:self];
|
||||
}
|
||||
|
||||
- (IBAction)buttonConnectPressed:(id)sender {
|
||||
_host = _textFieldHost.stringValue;
|
||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_textFieldHost.stringValue
|
||||
uniqueId:_uniqueId
|
||||
deviceName:@"roth"
|
||||
cert:_cert];
|
||||
|
||||
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
|
||||
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]
|
||||
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
|
||||
|
||||
if ([[serverInfoResp getStringTag:@"PairStatus"] isEqualToString:@"1"]) {
|
||||
NSLog(@"alreadyPaired");
|
||||
[self alreadyPaired];
|
||||
} else {
|
||||
// Polling the server while pairing causes the server to screw up
|
||||
NSLog(@"Pairing");
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
||||
PairManager* pMan = [[PairManager alloc] initWithManager:hMan andCert:_cert callback:self];
|
||||
[_opQueue addOperation:pMan];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)buttonSettingsPressed:(id)sender {
|
||||
showSettings = !showSettings;
|
||||
if(showSettings) {
|
||||
_layoutConstraintSetupFrame.constant = settingsFrameHeight;
|
||||
}
|
||||
else {
|
||||
_layoutConstraintSetupFrame.constant = 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)popupButtonSelectionPressed:(id)sender {
|
||||
}
|
||||
|
||||
- (void)alreadyPaired {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[_popupButtonSelection setEnabled:true];
|
||||
[_popupButtonSelection setHidden:false];
|
||||
[_buttonConnect setEnabled:false];
|
||||
[_buttonConnect setHidden:true];
|
||||
[_buttonLaunch setEnabled:true];
|
||||
[_textFieldHost setEnabled:false];
|
||||
});
|
||||
[self searchForHost:_host];
|
||||
[self updateAppsForHost];
|
||||
[self populatePopupButton];
|
||||
}
|
||||
|
||||
- (void)searchForHost:(NSString*) hostAddress {
|
||||
_appList = [ConnectionHelper getAppListForHostWithHostIP:_textFieldHost.stringValue deviceName:deviceName cert:_cert uniqueID:_uniqueId].getAppList;
|
||||
}
|
||||
|
||||
- (void)populatePopupButton {
|
||||
for (int i = 0; i < _appList.count; i++) {
|
||||
[_popupButtonSelection addItemWithTitle:[_sortedAppList[i] name]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)pairFailed:(NSString *)message {
|
||||
[self showAlert:[NSString stringWithFormat: @"%@", message]];
|
||||
}
|
||||
|
||||
- (void)pairSuccessful {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.view.window endSheet:_alert.window];
|
||||
_alert = nil;
|
||||
[self alreadyPaired];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)showPIN:(NSString *)PIN {
|
||||
[self showAlert:[NSString stringWithFormat: @"PIN: %@", PIN]];
|
||||
}
|
||||
|
||||
- (void) updateAppsForHost {
|
||||
_sortedAppList = [_appList allObjects];
|
||||
_sortedAppList = [_sortedAppList sortedArrayUsingSelector:@selector(compareName:)];
|
||||
}
|
||||
|
||||
- (void)transitionToStreamView {
|
||||
NSStoryboard *storyBoard = [NSStoryboard storyboardWithName:@"Mac" bundle:nil];
|
||||
StreamFrameViewController* streamFrame = (StreamFrameViewController*)[storyBoard instantiateControllerWithIdentifier :@"streamFrameVC"];
|
||||
streamFrame.streamConfig = _streamConfig;
|
||||
[streamFrame setOrigin:self];
|
||||
self.view.window.contentViewController = streamFrame;
|
||||
}
|
||||
|
||||
@end
|
||||
13
Moonlight macOS/main.m
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// main.m
|
||||
// Moonlight macOS
|
||||
//
|
||||
// Created by Felix on 09.03.18.
|
||||
// Copyright © 2018 Felix. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
return NSApplicationMain(argc, argv);
|
||||
}
|
||||