2016-04-27 20:52:28 +00:00
|
|
|
//
|
|
|
|
// AppDelegate.m
|
|
|
|
// Mini vMac
|
|
|
|
//
|
|
|
|
// Created by Jesús A. Álvarez on 27/04/2016.
|
|
|
|
// Copyright © 2016 namedfork. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#import "AppDelegate.h"
|
2016-05-11 21:04:49 +00:00
|
|
|
#import "SettingsViewController.h"
|
|
|
|
#import "InsertDiskViewController.h"
|
2016-05-01 17:05:36 +00:00
|
|
|
#include "CNFGRAPI.h"
|
|
|
|
#include "SYSDEPNS.h"
|
|
|
|
#include "MYOSGLUE.h"
|
|
|
|
|
|
|
|
IMPORTPROC RunEmulator(void);
|
2016-05-01 21:44:47 +00:00
|
|
|
IMPORTFUNC blnr GetSpeedStopped(void);
|
2016-05-01 17:05:36 +00:00
|
|
|
IMPORTPROC SetSpeedStopped(blnr stopped);
|
2016-05-01 21:44:47 +00:00
|
|
|
IMPORTPROC SetMouseButton(blnr down);
|
|
|
|
IMPORTPROC SetMouseLoc(ui4r h, ui4r v);
|
|
|
|
IMPORTPROC SetMouseDelta(ui4r dh, ui4r dv);
|
2016-05-11 21:04:49 +00:00
|
|
|
IMPORTFUNC blnr Sony_Insert1(NSString *filePath, blnr silentfail);
|
|
|
|
IMPORTFUNC blnr Sony_IsInserted(NSString *filePath);
|
2016-05-13 21:47:59 +00:00
|
|
|
EXPORTVAR(ui3b,SpeedValue);
|
2016-05-14 11:01:02 +00:00
|
|
|
IMPORTPROC SetKeyState(int key, blnr down);
|
2016-05-25 18:49:56 +00:00
|
|
|
IMPORTPROC MacInterrupt();
|
|
|
|
IMPORTPROC MacReset();
|
2016-05-01 17:05:36 +00:00
|
|
|
|
|
|
|
static AppDelegate *sharedAppDelegate = nil;
|
2016-05-11 21:04:49 +00:00
|
|
|
NSString * const MNVMDidInsertDiskNotification = @"MNVMDidInsertDisk";
|
|
|
|
NSString * const MNVMDidEjectDiskNotification = @"MNVMDidEjectDisk";
|
2016-04-27 20:52:28 +00:00
|
|
|
|
2016-05-14 13:15:37 +00:00
|
|
|
@interface AppDelegate () <UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning>
|
2016-04-27 20:52:28 +00:00
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation AppDelegate
|
2016-05-14 13:15:37 +00:00
|
|
|
{
|
|
|
|
UISwipeGestureRecognizerDirection modalPanePresentationDirection;
|
|
|
|
}
|
2016-04-27 20:52:28 +00:00
|
|
|
|
2016-05-01 17:05:36 +00:00
|
|
|
+ (instancetype)sharedInstance {
|
|
|
|
return sharedAppDelegate;
|
|
|
|
}
|
2016-04-27 20:52:28 +00:00
|
|
|
|
|
|
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
2016-05-01 21:44:47 +00:00
|
|
|
sharedAppDelegate = self;
|
2016-05-14 12:04:18 +00:00
|
|
|
[self initDefaults];
|
|
|
|
[self performSelector:@selector(runEmulator) withObject:nil afterDelay:0.1];
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)initDefaults {
|
2016-05-14 11:01:02 +00:00
|
|
|
// default settings
|
2016-05-14 13:36:50 +00:00
|
|
|
NSDictionary *layoutForLanguage = @{@"en": @"British.nfkeyboardlayout",
|
|
|
|
@"es": @"Spanish.nfkeyboardlayout",
|
|
|
|
@"en-US": @"US.nfkeyboardlayout"};
|
|
|
|
NSString *firstLanguage = [NSBundle preferredLocalizationsFromArray:layoutForLanguage.allKeys].firstObject;
|
2016-05-14 12:04:18 +00:00
|
|
|
NSDictionary *defaultValues = @{@"trackpad": @([UIDevice currentDevice].userInterfaceIdiom != UIUserInterfaceIdiomPad),
|
|
|
|
@"frameskip": @(0),
|
2016-05-14 13:36:50 +00:00
|
|
|
@"keyboardLayout": layoutForLanguage[firstLanguage]
|
2016-05-14 12:04:18 +00:00
|
|
|
};
|
2016-05-14 13:36:50 +00:00
|
|
|
|
2016-05-14 12:04:18 +00:00
|
|
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
|
|
[defaults registerDefaults:defaultValues];
|
|
|
|
[defaults setValue:@(WantInitSpeedValue) forKey:@"speedValue"];
|
|
|
|
[defaults addObserver:self forKeyPath:@"speedValue" options:0 context:NULL];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
|
|
|
|
if (object == [NSUserDefaults standardUserDefaults]) {
|
|
|
|
if ([keyPath isEqualToString:@"speedValue"]) {
|
|
|
|
SpeedValue = [[NSUserDefaults standardUserDefaults] integerForKey:@"speedValue"];
|
|
|
|
}
|
|
|
|
}
|
2016-04-27 20:52:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
2016-05-07 18:48:53 +00:00
|
|
|
self.emulatorRunning = NO;
|
2016-04-27 20:52:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)applicationWillEnterForeground:(UIApplication *)application {
|
2016-05-07 18:48:53 +00:00
|
|
|
self.emulatorRunning = YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
|
|
|
|
if (![NSThread isMainThread]) {
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
[self showAlertWithTitle:title message:message];
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
|
|
|
|
UIViewController *controller = self.window.rootViewController;
|
|
|
|
[controller presentViewController:alert animated:YES completion:nil];
|
|
|
|
}
|
|
|
|
|
2016-05-14 13:15:37 +00:00
|
|
|
#pragma mark - Settings / Insert Disk panels
|
|
|
|
|
2016-05-11 21:04:49 +00:00
|
|
|
- (void)showSettings:(id)sender {
|
|
|
|
[self showModalPanel:@"settings" sender:sender];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)showInsertDisk:(id)sender {
|
|
|
|
[self showModalPanel:@"disk" sender:sender];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)showModalPanel:(NSString*)name sender:(id)sender {
|
|
|
|
Class classToShow, otherClass;
|
|
|
|
if ([name isEqualToString:@"settings"]) {
|
|
|
|
classToShow = [SettingsViewController class];
|
|
|
|
otherClass = [InsertDiskViewController class];
|
|
|
|
} else {
|
|
|
|
classToShow = [InsertDiskViewController class];
|
|
|
|
otherClass = [SettingsViewController class];
|
|
|
|
}
|
|
|
|
|
|
|
|
UIViewController *rootViewController = self.window.rootViewController;
|
|
|
|
UIViewController *presentedViewController = rootViewController.presentedViewController;
|
|
|
|
UIViewController *presentedTopViewController = [presentedViewController isKindOfClass:[UINavigationController class]] ? [(UINavigationController*)presentedViewController topViewController] : nil;
|
|
|
|
|
|
|
|
if ([presentedTopViewController isKindOfClass:classToShow]) {
|
2016-05-14 13:15:37 +00:00
|
|
|
[presentedViewController dismissViewControllerAnimated:YES completion:nil];
|
2016-05-11 21:04:49 +00:00
|
|
|
return;
|
|
|
|
} else if ([presentedTopViewController isKindOfClass:otherClass]) {
|
|
|
|
// flip
|
|
|
|
UIViewController *viewController = [rootViewController.storyboard instantiateViewControllerWithIdentifier:name];
|
|
|
|
viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
|
|
|
|
viewController.modalPresentationStyle = UIModalPresentationFormSheet;
|
|
|
|
UIView *windowSnapshotView = [self.window snapshotViewAfterScreenUpdates:NO];
|
|
|
|
[self.window addSubview:windowSnapshotView];
|
|
|
|
UIView *oldPanelSnapshotView = [presentedViewController.view snapshotViewAfterScreenUpdates:NO];
|
|
|
|
[viewController.view addSubview:oldPanelSnapshotView];
|
|
|
|
[rootViewController dismissViewControllerAnimated:NO completion:^{
|
|
|
|
[rootViewController presentViewController:viewController animated:NO completion:^{
|
|
|
|
UIView *emptyView = [[UIView alloc] initWithFrame:viewController.view.bounds];
|
|
|
|
[windowSnapshotView removeFromSuperview];
|
|
|
|
viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
|
|
|
|
[UIView transitionFromView:oldPanelSnapshotView
|
|
|
|
toView:emptyView
|
|
|
|
duration:0.5
|
|
|
|
options:UIViewAnimationOptionTransitionFlipFromRight
|
|
|
|
completion:^(BOOL finished) {
|
|
|
|
[emptyView removeFromSuperview];
|
|
|
|
}];
|
|
|
|
}];
|
|
|
|
}];
|
|
|
|
} else {
|
2016-05-14 13:15:37 +00:00
|
|
|
UIViewController *viewController = [rootViewController.storyboard instantiateViewControllerWithIdentifier:name];
|
|
|
|
viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
|
|
|
|
viewController.modalPresentationStyle = UIModalPresentationFormSheet;
|
|
|
|
if ([sender isKindOfClass:[UISwipeGestureRecognizer class]]) {
|
|
|
|
modalPanePresentationDirection = [(UISwipeGestureRecognizer*)sender direction];
|
|
|
|
viewController.transitioningDelegate = self;
|
|
|
|
}
|
|
|
|
[rootViewController presentViewController:viewController animated:YES completion:nil];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
|
|
|
|
return 0.3;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
|
|
|
|
UIView *containerView = [transitionContext containerView];
|
|
|
|
UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
|
|
|
|
|
|
|
|
[containerView addSubview:toView];
|
|
|
|
switch (modalPanePresentationDirection) {
|
|
|
|
case UISwipeGestureRecognizerDirectionLeft:
|
|
|
|
toView.transform = CGAffineTransformMakeTranslation(containerView.bounds.size.width, 0);
|
|
|
|
break;
|
|
|
|
case UISwipeGestureRecognizerDirectionRight:
|
|
|
|
toView.transform = CGAffineTransformMakeTranslation(-containerView.bounds.size.width, 0);
|
|
|
|
break;
|
|
|
|
case UISwipeGestureRecognizerDirectionDown:
|
|
|
|
toView.transform = CGAffineTransformMakeTranslation(0, -containerView.bounds.size.height);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
toView.transform = CGAffineTransformMakeTranslation(0, containerView.bounds.size.height);
|
2016-05-11 21:04:49 +00:00
|
|
|
}
|
2016-05-14 13:15:37 +00:00
|
|
|
|
|
|
|
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
|
|
|
|
toView.transform = CGAffineTransformIdentity;
|
|
|
|
} completion:^(BOOL finished) {
|
|
|
|
[transitionContext completeTransition:finished];
|
|
|
|
}];
|
2016-05-11 21:04:49 +00:00
|
|
|
}
|
|
|
|
|
2016-05-07 18:48:53 +00:00
|
|
|
#pragma mark - Files
|
|
|
|
|
2016-05-11 21:04:49 +00:00
|
|
|
- (NSArray<NSString *> *)diskImageExtensions {
|
|
|
|
return @[@"dsk", @"img", @"dc42", @"diskcopy42"];
|
|
|
|
}
|
|
|
|
|
2016-05-07 18:48:53 +00:00
|
|
|
- (NSString *)documentsPath {
|
|
|
|
static dispatch_once_t onceToken;
|
|
|
|
static NSString *documentsPath;
|
|
|
|
dispatch_once(&onceToken, ^{
|
|
|
|
documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject.stringByStandardizingPath;
|
|
|
|
[[NSFileManager defaultManager] createDirectoryAtPath:documentsPath withIntermediateDirectories:YES attributes:nil error:NULL];
|
|
|
|
});
|
|
|
|
return documentsPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
|
|
|
|
if (url.fileURL) {
|
|
|
|
// opening file
|
|
|
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
|
|
NSString *fileName = url.path.lastPathComponent;
|
|
|
|
NSString *destinationPath = [self.documentsPath stringByAppendingPathComponent:fileName];
|
|
|
|
NSError *error = NULL;
|
|
|
|
NSInteger tries = 1;
|
|
|
|
while ([fileManager fileExistsAtPath:destinationPath]) {
|
|
|
|
NSString *newFileName;
|
|
|
|
if (fileName.pathExtension.length > 0) {
|
|
|
|
newFileName = [NSString stringWithFormat:@"%@ %d.%@", fileName.stringByDeletingPathExtension, (int)tries, fileName.pathExtension];
|
|
|
|
} else {
|
|
|
|
newFileName = [NSString stringWithFormat:@"%@ %d", fileName, (int)tries];
|
|
|
|
}
|
|
|
|
destinationPath = [self.documentsPath stringByAppendingPathComponent:newFileName];
|
|
|
|
tries++;
|
|
|
|
}
|
|
|
|
[fileManager moveItemAtPath:url.path toPath:destinationPath error:&error];
|
|
|
|
if (error) {
|
|
|
|
[self showAlertWithTitle:fileName message:error.localizedFailureReason];
|
|
|
|
} else {
|
|
|
|
[self showAlertWithTitle:@"File Import" message:[NSString stringWithFormat:@"%@ imported to Documents", destinationPath.lastPathComponent]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return YES;
|
2016-04-27 20:52:28 +00:00
|
|
|
}
|
|
|
|
|
2016-05-01 21:44:47 +00:00
|
|
|
#pragma mark - Emulation
|
|
|
|
|
2016-05-01 17:05:36 +00:00
|
|
|
- (void)runEmulator {
|
2016-05-13 21:47:59 +00:00
|
|
|
SpeedValue = [[NSUserDefaults standardUserDefaults] integerForKey:@"speedValue"];
|
2016-05-14 12:04:18 +00:00
|
|
|
if (SpeedValue > 3) {
|
|
|
|
SpeedValue = 3;
|
|
|
|
}
|
2016-05-01 17:05:36 +00:00
|
|
|
RunEmulator();
|
2016-04-27 20:52:28 +00:00
|
|
|
}
|
|
|
|
|
2016-05-01 21:44:47 +00:00
|
|
|
- (BOOL)isEmulatorRunning {
|
|
|
|
return !GetSpeedStopped();
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setEmulatorRunning:(BOOL)emulatorRunning {
|
|
|
|
SetSpeedStopped(emulatorRunning);
|
|
|
|
}
|
|
|
|
|
2016-05-11 21:04:49 +00:00
|
|
|
#pragma mark - Mouse
|
|
|
|
|
2016-05-01 21:44:47 +00:00
|
|
|
- (void)setMouseX:(NSInteger)x Y:(NSInteger)y {
|
|
|
|
SetMouseLoc(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)moveMouseX:(NSInteger)x Y:(NSInteger)y {
|
|
|
|
SetMouseDelta(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setMouseButton:(BOOL)down {
|
|
|
|
SetMouseButton(down);
|
|
|
|
}
|
|
|
|
|
2016-05-25 18:49:56 +00:00
|
|
|
- (void)macInterrupt {
|
|
|
|
MacInterrupt();
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void)macReset {
|
|
|
|
MacReset();
|
|
|
|
}
|
|
|
|
|
2016-05-14 11:01:02 +00:00
|
|
|
#pragma mark - Keyboard
|
|
|
|
|
|
|
|
- (int)translateScanCode:(int)scancode {
|
|
|
|
switch (scancode) {
|
|
|
|
case 54: return 59; // left control
|
|
|
|
case 59: return 70; // arrow left
|
|
|
|
case 60: return 66; // arrow right
|
|
|
|
case 61: return 72; // arrow down
|
|
|
|
case 62: return 77; // arrow up
|
|
|
|
default: return scancode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)keyDown:(int)scancode {
|
|
|
|
SetKeyState([self translateScanCode:scancode], true);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)keyUp:(int)scancode {
|
|
|
|
SetKeyState([self translateScanCode:scancode], false);
|
|
|
|
}
|
|
|
|
|
2016-05-11 21:04:49 +00:00
|
|
|
#pragma mark - Disk Drive
|
|
|
|
|
|
|
|
- (BOOL)insertDisk:(NSString *)path {
|
|
|
|
return Sony_Insert1(path.stringByStandardizingPath, falseblnr);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isDiskInserted:(NSString *)path {
|
|
|
|
return Sony_IsInserted(path.stringByStandardizingPath);
|
|
|
|
}
|
|
|
|
|
2016-04-27 20:52:28 +00:00
|
|
|
@end
|