2016-04-27 20:52:28 +00:00
|
|
|
//
|
|
|
|
// ViewController.m
|
|
|
|
// Mini vMac
|
|
|
|
//
|
|
|
|
// Created by Jesús A. Álvarez on 27/04/2016.
|
2018-04-28 10:12:43 +00:00
|
|
|
// Copyright © 2016-2018 namedfork. All rights reserved.
|
2016-04-27 20:52:28 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
#import "ViewController.h"
|
2016-05-01 21:44:47 +00:00
|
|
|
#import "TouchScreen.h"
|
2016-05-14 11:12:21 +00:00
|
|
|
#import "TrackPad.h"
|
2016-05-11 21:04:49 +00:00
|
|
|
#import "AppDelegate.h"
|
2016-05-14 11:01:02 +00:00
|
|
|
#import "KBKeyboardView.h"
|
|
|
|
#import "KBKeyboardLayout.h"
|
2016-04-27 20:52:28 +00:00
|
|
|
|
2024-02-17 12:31:39 +00:00
|
|
|
@interface ViewController () <UIAdaptivePresentationControllerDelegate, UIPointerInteractionDelegate>
|
2016-04-27 20:52:28 +00:00
|
|
|
|
|
|
|
@end
|
|
|
|
|
2024-02-17 12:21:42 +00:00
|
|
|
static int8_t usb_to_adb_scancode[] = {
|
|
|
|
-1, -1, -1, -1, 0, 11, 8, 2, 14, 3, 5, 4, 34, 38, 40, 37,
|
|
|
|
46, 45, 31, 35, 12, 15, 1, 17, 32, 9, 13, 7, 16, 6, 18, 19,
|
|
|
|
20, 21, 23, 22, 26, 28, 25, 29, 36, 53, 51, 48, 49, 27, 24, 33,
|
|
|
|
30, 42, 42, 41, 39, 10, 43, 47, 44, 57, 122, 120, 99, 118, 96, 97,
|
|
|
|
98, 100, 101, 109, 103, 111, 105, 107, 113, 114, 115, 116, 117, 119, 121, 60,
|
|
|
|
59, 61, 62, 71, 75, 67, 78, 69, 76, 83, 84, 85, 86, 87, 88, 89,
|
|
|
|
91, 92, 82, 65, 50, 55, 126, 81, 105, 107, 113, 106, 64, 79, 80, 90,
|
|
|
|
-1, -1, -1, -1, -1, 114, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74,
|
|
|
|
72, 73, -1, -1, -1, 95, -1, 94, -1, 93, -1, -1, -1, -1, -1, -1,
|
|
|
|
104, 102, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
54, 56, 58, 55, 54, 56, 58, 55, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
|
|
|
};
|
|
|
|
|
2016-04-27 20:52:28 +00:00
|
|
|
@implementation ViewController
|
2016-05-01 21:44:47 +00:00
|
|
|
{
|
2016-05-14 11:01:02 +00:00
|
|
|
KBKeyboardView *keyboardView;
|
2016-05-14 11:37:33 +00:00
|
|
|
UISwipeGestureRecognizer *showKeyboardGesture, *hideKeyboardGesture, *insertDiskGesture, *showSettingsGesture;
|
2016-05-01 21:44:47 +00:00
|
|
|
UIControl *pointingDeviceView;
|
2024-02-10 11:15:01 +00:00
|
|
|
UIViewController *_keyboardViewController;
|
2024-02-17 12:21:42 +00:00
|
|
|
BOOL physicalCapsLocked;
|
2024-02-17 13:35:19 +00:00
|
|
|
UIPointerInteraction *pointerInteraction;
|
2016-05-01 21:44:47 +00:00
|
|
|
}
|
2016-04-27 20:52:28 +00:00
|
|
|
|
2016-05-14 11:01:02 +00:00
|
|
|
- (void)viewDidLoad {
|
|
|
|
[super viewDidLoad];
|
2024-02-10 11:15:01 +00:00
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(emulatorDidShutDown:) name:[AppDelegate sharedEmulator].shutdownNotification object:nil];
|
|
|
|
|
|
|
|
#if defined(TARGET_OS_VISION) && TARGET_OS_VISION == 1
|
|
|
|
[self initXr];
|
|
|
|
#else
|
|
|
|
[self scheduleHelpPresentationIfNeededAfterDelay:6.0];
|
|
|
|
[self installGestures];
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(TARGET_OS_VISION) && TARGET_OS_VISION == 1
|
|
|
|
- (UIViewController *)keyboardViewController {
|
|
|
|
if (keyboardView == nil) {
|
|
|
|
[[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"keyboardLayout" options:0 context:NULL];
|
|
|
|
KBKeyboardLayout *layout = [self keyboardLayout];
|
|
|
|
CGSize keyboardSize = CGSizeZero;
|
|
|
|
for (NSValue *size in layout.availableSizes) {
|
|
|
|
if (size.CGSizeValue.width > keyboardSize.width) {
|
|
|
|
keyboardSize = size.CGSizeValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
keyboardView = [[KBKeyboardView alloc] initWithFrame:CGRectMake(0, 0, keyboardSize.width, keyboardSize.height)];
|
2024-02-10 13:23:42 +00:00
|
|
|
keyboardView.layoutMenu = [self keyboardLayoutMenu];
|
2024-02-10 11:15:01 +00:00
|
|
|
keyboardView.layout = layout;
|
|
|
|
keyboardView.delegate = self;
|
|
|
|
}
|
|
|
|
if (_keyboardViewController == nil) {
|
|
|
|
_keyboardViewController = [UIViewController alloc];
|
|
|
|
_keyboardViewController.view = keyboardView;
|
|
|
|
_keyboardViewController.preferredContentSize = keyboardView.frame.size;
|
|
|
|
} else if (_keyboardViewController.view != keyboardView) {
|
|
|
|
_keyboardViewController.view = keyboardView;
|
|
|
|
}
|
|
|
|
return _keyboardViewController;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
- (void)installGestures {
|
2016-05-14 11:01:02 +00:00
|
|
|
[self installKeyboardGestures];
|
2020-06-22 19:07:01 +00:00
|
|
|
insertDiskGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(showInsertDisk:)];
|
2016-05-14 11:37:33 +00:00
|
|
|
insertDiskGesture.direction = UISwipeGestureRecognizerDirectionLeft;
|
|
|
|
insertDiskGesture.numberOfTouchesRequired = 2;
|
|
|
|
[self.view addGestureRecognizer:insertDiskGesture];
|
2024-02-10 11:15:01 +00:00
|
|
|
|
2020-06-22 19:07:01 +00:00
|
|
|
showSettingsGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(showSettings:)];
|
2016-05-14 11:37:33 +00:00
|
|
|
showSettingsGesture.direction = UISwipeGestureRecognizerDirectionRight;
|
|
|
|
showSettingsGesture.numberOfTouchesRequired = 2;
|
|
|
|
[self.view addGestureRecognizer:showSettingsGesture];
|
2024-02-10 11:15:01 +00:00
|
|
|
|
2016-05-14 11:01:02 +00:00
|
|
|
}
|
|
|
|
|
2020-06-22 19:07:01 +00:00
|
|
|
- (void)showSettings:(id)sender {
|
|
|
|
[self performSegueWithIdentifier:@"settings" sender:sender];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)showInsertDisk:(id)sender {
|
|
|
|
[self performSegueWithIdentifier:@"disk" sender:sender];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
2020-06-23 16:32:07 +00:00
|
|
|
[self cancelHelpPresentation];
|
2022-05-26 15:42:45 +00:00
|
|
|
if ([@[@"disk", @"settings"] containsObject:segue.identifier]) {
|
2020-10-01 20:49:54 +00:00
|
|
|
segue.destinationViewController.presentationController.delegate = self;
|
2022-05-26 15:42:45 +00:00
|
|
|
if (self.presentedViewController != nil) {
|
|
|
|
[self dismissViewControllerAnimated:YES completion:nil];
|
|
|
|
}
|
2020-06-22 19:07:01 +00:00
|
|
|
}
|
2024-02-10 13:36:56 +00:00
|
|
|
#if defined(TARGET_OS_VISION) && TARGET_OS_VISION == 1
|
|
|
|
if ([segue.identifier isEqualToString:@"disk"]) {
|
|
|
|
[(UINavigationController*)segue.destinationViewController setToolbarHidden:YES];
|
|
|
|
}
|
|
|
|
#endif
|
2020-06-22 19:07:01 +00:00
|
|
|
}
|
|
|
|
|
2020-10-01 20:49:54 +00:00
|
|
|
- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController {
|
|
|
|
// hack to fix the presenting view controller not returning back to normal size on iOS 13
|
|
|
|
// when the sheet is dismissed interactively (ie dragging it down) after a contextual menu
|
|
|
|
// has been shown, which breaks some autolayout constraints. when this happens, the
|
|
|
|
// presenting view controller won't resize back to normal during the interactive
|
|
|
|
// dismissing of the presented sheet
|
|
|
|
if (@available(iOS 14, *)) {
|
|
|
|
// it works correctly on iOS 14
|
|
|
|
} else {
|
|
|
|
self.view.superview.transform = CGAffineTransformIdentity;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-09 15:06:37 +00:00
|
|
|
#if !defined(TARGET_OS_VISION) || TARGET_OS_VISION == 0
|
2016-05-01 17:05:36 +00:00
|
|
|
- (BOOL)prefersStatusBarHidden {
|
2020-06-22 13:46:31 +00:00
|
|
|
UIScreen *screen = self.view.window.screen;
|
|
|
|
return CGRectEqualToRect(screen.bounds, self.view.window.bounds);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (UIStatusBarStyle)preferredStatusBarStyle {
|
|
|
|
return UIStatusBarStyleLightContent;
|
2016-04-27 20:52:28 +00:00
|
|
|
}
|
2024-02-09 15:06:37 +00:00
|
|
|
#endif
|
2016-04-27 20:52:28 +00:00
|
|
|
|
2018-04-28 14:53:39 +00:00
|
|
|
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
|
|
|
|
return UIRectEdgeAll;
|
|
|
|
}
|
|
|
|
|
2016-05-01 21:44:47 +00:00
|
|
|
- (void)viewDidAppear:(BOOL)animated {
|
|
|
|
[super viewDidAppear:animated];
|
|
|
|
[self setUpPointingDevice];
|
2016-05-14 11:01:02 +00:00
|
|
|
[[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"trackpad" options:0 context:NULL];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)viewDidDisappear:(BOOL)animated {
|
|
|
|
[[NSUserDefaults standardUserDefaults] removeObserver:self forKeyPath:@"trackpad"];
|
2016-05-01 21:44:47 +00:00
|
|
|
}
|
|
|
|
|
2024-03-01 21:49:04 +00:00
|
|
|
- (BOOL)prefersHomeIndicatorAutoHidden {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2016-05-11 21:04:49 +00:00
|
|
|
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
|
|
|
|
if (motion == UIEventSubtypeMotionShake) {
|
|
|
|
[[AppDelegate sharedInstance] showInsertDisk:self];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-14 11:01:02 +00:00
|
|
|
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
|
|
|
|
if (object == [NSUserDefaults standardUserDefaults]) {
|
|
|
|
if ([keyPath isEqualToString:@"keyboardLayout"] && keyboardView != nil) {
|
2024-02-10 11:15:01 +00:00
|
|
|
#if defined(TARGET_OS_VISION) && TARGET_OS_VISION == 1
|
|
|
|
// FIXME: do this nicelier
|
|
|
|
keyboardView = nil;
|
|
|
|
[self keyboardViewController];
|
|
|
|
#else
|
2016-05-14 11:01:02 +00:00
|
|
|
BOOL keyboardWasVisible = self.keyboardVisible;
|
|
|
|
[self setKeyboardVisible:NO animated:NO];
|
|
|
|
[keyboardView removeFromSuperview];
|
|
|
|
keyboardView = nil;
|
|
|
|
if (keyboardWasVisible) {
|
|
|
|
[self setKeyboardVisible:YES animated:NO];
|
|
|
|
}
|
2024-02-10 11:15:01 +00:00
|
|
|
#endif
|
2016-05-14 11:01:02 +00:00
|
|
|
} else if ([keyPath isEqualToString:@"trackpad"]) {
|
|
|
|
[self setUpPointingDevice];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
|
|
|
|
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
2020-06-22 13:46:31 +00:00
|
|
|
if (self.keyboardVisible) {
|
|
|
|
// willTransitionToTraitCollection... is caled before us, so keyboard will already be hidden here in a trait collection transition
|
|
|
|
[self setKeyboardVisible:NO animated:NO];
|
|
|
|
[coordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
|
|
|
|
[self setKeyboardVisible:YES animated:YES];
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
|
|
|
|
[super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];
|
2016-05-14 11:01:02 +00:00
|
|
|
if (self.keyboardVisible) {
|
|
|
|
[self setKeyboardVisible:NO animated:NO];
|
|
|
|
[coordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
|
|
|
|
[self setKeyboardVisible:YES animated:YES];
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-02 13:18:26 +00:00
|
|
|
- (void)emulatorDidShutDown:(NSNotification*)notification {
|
2020-09-24 22:29:30 +00:00
|
|
|
if (notification.object == [AppDelegate sharedEmulator]) {
|
|
|
|
UILabel *shutdownLabel = [[UILabel alloc] initWithFrame:self.view.bounds];
|
|
|
|
shutdownLabel.text = NSLocalizedString(@"the emulated Mac has shut down\ntap to restart", nil);
|
|
|
|
shutdownLabel.textColor = [UIColor whiteColor];
|
|
|
|
[self.view addSubview:shutdownLabel];
|
|
|
|
shutdownLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
|
|
[shutdownLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(restartEmulator:)]];
|
|
|
|
shutdownLabel.numberOfLines = -1;
|
|
|
|
shutdownLabel.textAlignment = NSTextAlignmentCenter;
|
|
|
|
shutdownLabel.userInteractionEnabled = YES;
|
|
|
|
[UIView animateWithDuration:0.5 animations:^{
|
|
|
|
self.screenView.alpha = 0.5;
|
|
|
|
}];
|
|
|
|
[self hideKeyboard:notification];
|
|
|
|
}
|
2016-07-02 13:18:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)restartEmulator:(UITapGestureRecognizer*)gestureRecognizer {
|
|
|
|
if (gestureRecognizer.state == UIGestureRecognizerStateRecognized) {
|
|
|
|
[UIView animateWithDuration:0.5 animations:^{
|
|
|
|
self.screenView.alpha = 1.0;
|
|
|
|
}];
|
|
|
|
[gestureRecognizer.view removeFromSuperview];
|
|
|
|
id emulator = [AppDelegate sharedEmulator];
|
|
|
|
[emulator performSelector:@selector(run) withObject:nil afterDelay:0.1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-23 16:32:07 +00:00
|
|
|
#pragma mark - Gesture Help
|
|
|
|
|
|
|
|
- (void)showGestureHelp:(id)sender {
|
2024-02-10 11:15:01 +00:00
|
|
|
#if !defined(TARGET_OS_VISION) || TARGET_OS_VISION == 0
|
2020-06-23 16:32:07 +00:00
|
|
|
[self setGestureHelpHidden:NO];
|
2024-02-10 11:15:01 +00:00
|
|
|
#endif
|
2020-06-23 16:32:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)hideGestureHelp:(id)sender {
|
|
|
|
[self setGestureHelpHidden:YES];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setGestureHelpHidden:(BOOL)hidden {
|
|
|
|
if (self.helpView.hidden == hidden) {
|
|
|
|
return;
|
|
|
|
} else if (!hidden) {
|
|
|
|
// prepare to show
|
|
|
|
self.helpView.alpha = 0.0;
|
|
|
|
self.helpView.hidden = NO;
|
|
|
|
}
|
|
|
|
[UIView animateWithDuration:0.2
|
|
|
|
animations:^{
|
|
|
|
self.helpView.alpha = hidden ? 0.0 : 1.0;
|
|
|
|
}
|
|
|
|
completion:^(BOOL finished) {
|
|
|
|
self.helpView.hidden = hidden;
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)showGestureHelpIfNeeded:(id)sender {
|
|
|
|
// show help if no disks have been inserted
|
|
|
|
if (![AppDelegate sharedEmulator].anyDiskInserted) {
|
|
|
|
[self showGestureHelp:sender];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)scheduleHelpPresentationIfNeededAfterDelay:(NSTimeInterval)delay {
|
|
|
|
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"autoShowGestureHelp"]) {
|
|
|
|
[self performSelector:@selector(showGestureHelpIfNeeded:) withObject:self afterDelay:delay];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)cancelHelpPresentation {
|
|
|
|
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showGestureHelpIfNeeded:) object:self];
|
|
|
|
}
|
|
|
|
|
2016-05-14 11:01:02 +00:00
|
|
|
#pragma mark - Keyboard
|
|
|
|
|
|
|
|
- (void)installKeyboardGestures {
|
|
|
|
showKeyboardGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(showKeyboard:)];
|
|
|
|
showKeyboardGesture.direction = UISwipeGestureRecognizerDirectionUp;
|
|
|
|
showKeyboardGesture.numberOfTouchesRequired = 2;
|
|
|
|
[self.view addGestureRecognizer:showKeyboardGesture];
|
|
|
|
|
|
|
|
hideKeyboardGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard:)];
|
|
|
|
hideKeyboardGesture.direction = UISwipeGestureRecognizerDirectionDown;
|
|
|
|
hideKeyboardGesture.numberOfTouchesRequired = 2;
|
|
|
|
[self.view addGestureRecognizer:hideKeyboardGesture];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isKeyboardVisible {
|
2024-02-10 11:15:01 +00:00
|
|
|
#if defined(TARGET_OS_VISION) && TARGET_OS_VISION == 1
|
|
|
|
return _keyboardViewController.view.window != nil;
|
|
|
|
#else
|
2016-05-14 11:01:02 +00:00
|
|
|
return keyboardView != nil && CGRectIntersectsRect(keyboardView.frame, self.view.bounds) && !keyboardView.hidden;
|
2024-02-10 11:15:01 +00:00
|
|
|
#endif
|
2016-05-14 11:01:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setKeyboardVisible:(BOOL)keyboardVisible {
|
|
|
|
[self setKeyboardVisible:keyboardVisible animated:YES];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)showKeyboard:(id)sender {
|
|
|
|
[self setKeyboardVisible:YES animated:YES];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)hideKeyboard:(id)sender {
|
|
|
|
[self setKeyboardVisible:NO animated:YES];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setKeyboardVisible:(BOOL)visible animated:(BOOL)animated {
|
2024-02-10 11:15:01 +00:00
|
|
|
#if defined(TARGET_OS_VISION) && TARGET_OS_VISION == 1
|
|
|
|
if (visible) {
|
|
|
|
UISceneSessionActivationRequest *request = [UISceneSessionActivationRequest requestWithRole:UIWindowSceneSessionRoleApplication];
|
|
|
|
request.userActivity = [[NSUserActivity alloc] initWithActivityType:@"net.namedfork.keyboard"];
|
2024-02-17 13:41:22 +00:00
|
|
|
request.userActivity.targetContentIdentifier = @"net.namedfork.keyboard";
|
|
|
|
[[UIApplication sharedApplication] activateSceneSessionForRequest:request errorHandler:^(NSError * _Nonnull error) {
|
|
|
|
NSLog(@"Activation error: %@", error);
|
|
|
|
}];
|
|
|
|
} else {
|
|
|
|
UIScene *keyboardScene = [[AppDelegate sharedInstance] sceneWithName:@"Keyboard"];
|
|
|
|
if (keyboardScene != nil) {
|
|
|
|
[[UIApplication sharedApplication] requestSceneSessionDestruction:keyboardScene.session options:nil errorHandler:nil];
|
|
|
|
}
|
|
|
|
}
|
2024-02-10 11:15:01 +00:00
|
|
|
#else
|
2024-02-17 13:41:22 +00:00
|
|
|
if (self.keyboardVisible == visible) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-14 11:01:02 +00:00
|
|
|
if (visible) {
|
|
|
|
[[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"keyboardLayout" options:0 context:NULL];
|
|
|
|
[self loadKeyboardView];
|
|
|
|
if (keyboardView.layout == nil) {
|
|
|
|
[keyboardView removeFromSuperview];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
[self.view addSubview:keyboardView];
|
|
|
|
keyboardView.hidden = NO;
|
|
|
|
CGRect finalFrame = CGRectMake(0.0, self.view.bounds.size.height - keyboardView.bounds.size.height, keyboardView.bounds.size.width, keyboardView.bounds.size.height);
|
|
|
|
if (animated) {
|
|
|
|
keyboardView.frame = CGRectOffset(finalFrame, 0.0, finalFrame.size.height);
|
|
|
|
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
|
2020-09-30 20:40:32 +00:00
|
|
|
self->keyboardView.frame = finalFrame;
|
2016-05-14 11:01:02 +00:00
|
|
|
} completion:nil];
|
|
|
|
} else {
|
|
|
|
keyboardView.frame = finalFrame;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
[[NSUserDefaults standardUserDefaults] removeObserver:self forKeyPath:@"keyboardLayout"];
|
|
|
|
if (animated) {
|
|
|
|
CGRect finalFrame = CGRectMake(0.0, self.view.bounds.size.height, keyboardView.bounds.size.width, keyboardView.bounds.size.height);
|
|
|
|
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
|
2020-09-30 20:40:32 +00:00
|
|
|
self->keyboardView.frame = finalFrame;
|
2016-05-14 11:01:02 +00:00
|
|
|
} completion:^(BOOL finished) {
|
|
|
|
if (finished) {
|
2020-09-30 20:40:32 +00:00
|
|
|
self->keyboardView.hidden = YES;
|
2016-05-14 11:01:02 +00:00
|
|
|
}
|
|
|
|
}];
|
|
|
|
} else {
|
|
|
|
keyboardView.hidden = YES;
|
|
|
|
}
|
|
|
|
}
|
2024-02-10 11:15:01 +00:00
|
|
|
#endif
|
2016-05-14 11:01:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)loadKeyboardView {
|
|
|
|
if (keyboardView != nil && keyboardView.bounds.size.width != self.view.bounds.size.width) {
|
|
|
|
// keyboard needs resizing
|
|
|
|
[keyboardView removeFromSuperview];
|
|
|
|
keyboardView = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keyboardView == nil) {
|
2017-11-28 18:25:33 +00:00
|
|
|
UIEdgeInsets safeAreaInsets = UIEdgeInsetsZero;
|
|
|
|
if (@available(iOS 11, *)) {
|
|
|
|
safeAreaInsets = self.view.safeAreaInsets;
|
|
|
|
}
|
|
|
|
keyboardView = [[KBKeyboardView alloc] initWithFrame:self.view.bounds safeAreaInsets:safeAreaInsets];
|
2016-05-14 11:01:02 +00:00
|
|
|
keyboardView.layout = [self keyboardLayout];
|
|
|
|
keyboardView.delegate = self;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (KBKeyboardLayout*)keyboardLayout {
|
|
|
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
|
|
NSString *layoutName = [defaults stringForKey:@"keyboardLayout"];
|
2018-04-28 09:49:05 +00:00
|
|
|
NSString *layoutPath = [[[AppDelegate sharedInstance] userKeyboardLayoutsPath] stringByAppendingPathComponent:layoutName];
|
|
|
|
if (![[NSFileManager defaultManager] fileExistsAtPath:layoutPath]) {
|
|
|
|
layoutPath = [[NSBundle mainBundle] pathForResource:layoutName ofType:nil inDirectory:@"Keyboard Layouts"];
|
|
|
|
}
|
2016-05-14 11:01:02 +00:00
|
|
|
if (layoutPath == nil) {
|
|
|
|
NSLog(@"Layout not found: %@", layoutPath);
|
|
|
|
}
|
|
|
|
return layoutPath ? [[KBKeyboardLayout alloc] initWithContentsOfFile:layoutPath] : nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)keyDown:(int)scancode {
|
2016-05-28 11:01:13 +00:00
|
|
|
[[AppDelegate sharedEmulator] keyDown:scancode];
|
2016-05-14 11:01:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)keyUp:(int)scancode {
|
2016-05-28 11:01:13 +00:00
|
|
|
[[AppDelegate sharedEmulator] keyUp:scancode];
|
2016-05-14 11:01:02 +00:00
|
|
|
}
|
|
|
|
|
2024-02-17 12:21:42 +00:00
|
|
|
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
|
|
|
|
for (UIPress *press in presses) {
|
|
|
|
[self handlePressEvent:press];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
|
|
|
|
for (UIPress *press in presses) {
|
|
|
|
[self handlePressEvent:press];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
|
|
|
|
for (UIPress *press in presses) {
|
|
|
|
[self handlePressEvent:press];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)handlePressEvent:(UIPress *)event {
|
|
|
|
long keycode = event.key.keyCode;
|
|
|
|
int scancode = -1;
|
|
|
|
|
|
|
|
BOOL emulatorIsFrontmost = [AppDelegate sharedEmulator].running && [AppDelegate sharedInstance].window.rootViewController.presentedViewController == nil;
|
|
|
|
BOOL isKeyDown = (event.phase == UIPressPhaseBegan);
|
|
|
|
|
|
|
|
if (keycode >= 0 && keycode < sizeof(usb_to_adb_scancode)) {
|
|
|
|
scancode = usb_to_adb_scancode[keycode];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (scancode == KC_CAPSLOCK) {
|
|
|
|
// caps lock
|
|
|
|
if (isKeyDown && !physicalCapsLocked) {
|
|
|
|
[[AppDelegate sharedEmulator] keyDown:KC_CAPSLOCK];
|
|
|
|
physicalCapsLocked = YES;
|
|
|
|
} else if (isKeyDown && physicalCapsLocked) {
|
|
|
|
[[AppDelegate sharedEmulator] keyUp:KC_CAPSLOCK];
|
|
|
|
physicalCapsLocked = NO;
|
|
|
|
}
|
|
|
|
} else if (scancode >= 0 && emulatorIsFrontmost) {
|
|
|
|
[self _updateCapsLockStatus:event];
|
|
|
|
if (isKeyDown) {
|
|
|
|
[[AppDelegate sharedEmulator] keyDown:scancode];
|
|
|
|
} else {
|
|
|
|
[[AppDelegate sharedEmulator] keyUp:scancode];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)_updateCapsLockStatus:(UIPress *)event {
|
|
|
|
BOOL currentCapsLock = (event.key.modifierFlags & UIKeyModifierAlphaShift) != 0;
|
|
|
|
if (currentCapsLock != physicalCapsLocked) {
|
|
|
|
physicalCapsLocked = currentCapsLock;
|
|
|
|
if (physicalCapsLocked) {
|
|
|
|
[[AppDelegate sharedEmulator] keyDown:KC_CAPSLOCK];
|
|
|
|
} else {
|
|
|
|
[[AppDelegate sharedEmulator] keyUp:KC_CAPSLOCK];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-06-23 16:32:49 +00:00
|
|
|
|
2024-02-17 13:35:19 +00:00
|
|
|
#pragma mark - Mouse
|
|
|
|
|
|
|
|
- (void)setUpPointingDevice {
|
|
|
|
if (pointingDeviceView) {
|
|
|
|
[pointingDeviceView removeFromSuperview];
|
|
|
|
pointingDeviceView = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pointerInteraction == nil) {
|
|
|
|
pointerInteraction = [[UIPointerInteraction alloc] initWithDelegate: self];
|
|
|
|
[self.view addInteraction:pointerInteraction];
|
|
|
|
UIHoverGestureRecognizer *hoverGestureRecognizer = [[UIHoverGestureRecognizer alloc] initWithTarget:self action:@selector(hover:)];
|
|
|
|
[self.view addGestureRecognizer:hoverGestureRecognizer];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(TARGET_OS_VISION) && TARGET_OS_VISION == 1
|
|
|
|
Class pointingDeviceClass = [TouchScreen class];
|
|
|
|
#else
|
|
|
|
BOOL useTrackPad = [[NSUserDefaults standardUserDefaults] boolForKey:@"trackpad"];
|
|
|
|
Class pointingDeviceClass = useTrackPad ? [TrackPad class] : [TouchScreen class];
|
|
|
|
#endif
|
|
|
|
pointingDeviceView = [[pointingDeviceClass alloc] initWithFrame:self.view.bounds];
|
|
|
|
pointingDeviceView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
|
|
[self.view insertSubview:pointingDeviceView aboveSubview:self.screenView];
|
|
|
|
if ([UIApplication instancesRespondToSelector:@selector(btcMouseSetRawMode:)]) {
|
|
|
|
[[UIApplication sharedApplication] btcMouseSetRawMode:YES];
|
2020-06-23 16:32:49 +00:00
|
|
|
}
|
2024-02-17 13:35:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (Point)mouseLocForCGPoint:(CGPoint)point {
|
|
|
|
Point mouseLoc;
|
|
|
|
CGRect screenBounds = self.screenView.screenBounds;
|
|
|
|
CGSize screenSize = self.screenView.screenSize;
|
|
|
|
mouseLoc.h = (point.x - screenBounds.origin.x) * (screenSize.width/screenBounds.size.width);
|
|
|
|
mouseLoc.v = (point.y - screenBounds.origin.y) * (screenSize.height/screenBounds.size.height);
|
|
|
|
return mouseLoc;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (UIPointerRegion *)pointerInteraction:(UIPointerInteraction *)interaction regionForRequest:(UIPointerRegionRequest *)request defaultRegion:(UIPointerRegion *)defaultRegion {
|
2020-06-23 16:32:49 +00:00
|
|
|
return defaultRegion;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction styleForRegion:(UIPointerRegion *)region {
|
|
|
|
return [UIPointerStyle hiddenPointerStyle];
|
|
|
|
}
|
|
|
|
|
2024-02-17 13:35:19 +00:00
|
|
|
- (void)hover:(UIHoverGestureRecognizer *)hoverGestureRecognizer {
|
|
|
|
Point mouseLoc = [self mouseLocForCGPoint:[hoverGestureRecognizer locationInView:self.screenView]];
|
|
|
|
[[AppDelegate sharedEmulator] setMouseX:mouseLoc.h Y:mouseLoc.v];
|
|
|
|
}
|
|
|
|
|
2020-06-23 16:32:49 +00:00
|
|
|
@end
|