watch: use watch as trackpad

This commit is contained in:
Jesús A. Álvarez 2024-03-27 20:25:15 +01:00
parent a7619fcc84
commit f1bf501e88
9 changed files with 112 additions and 16 deletions

View File

@ -15,12 +15,14 @@
"subtype" : "42mm"
},
{
"filename" : "Icon 7.png",
"idiom" : "watch",
"role" : "companionSettings",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "Icon 6.png",
"idiom" : "watch",
"role" : "companionSettings",
"scale" : "3x",

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -9,11 +9,14 @@
#import <WatchKit/WatchKit.h>
#import <Foundation/Foundation.h>
#import <SpriteKit/SpriteKit.h>
#import "EmulatorProtocol.h"
@class WCSession;
@interface InterfaceController : WKInterfaceController
@property (class, readonly, strong) id<Emulator> sharedEmulator NS_SWIFT_NAME(emulator);
- (void)sessionReachabilityDidChange:(WCSession *)session;
@end

View File

@ -11,8 +11,10 @@
@import ObjectiveC.runtime;
@import WatchConnectivity;
#import "UIKit+Watch.h"
#import "InterfaceController.h"
#import "EmulatorProtocol.h"
#import "TrackPad.h"
@interface NSObject (fs_override)
+(id)sharedApplication;
@ -32,15 +34,19 @@
-(void)setContentsScale:(CGFloat)value;
-(void)setContentsGravity:(NSString*)gravity;
-(void)setMinificationFilter:(NSString*)filter;
-(void)addTarget:(nullable id)target action:(SEL)action forControlEvents:(NSUInteger)controlEvents;
-(void)setIdleTimerDisabled:(BOOL)disabled;
@end
@interface InterfaceController ()
@end
static NSObject<Emulator> *sharedEmulator = nil;
@implementation InterfaceController
{
NSObject<Emulator> *emulator;
}
+ (void)load {
@ -52,6 +58,10 @@
}
}
+ (id<Emulator>)sharedEmulator {
return sharedEmulator;
}
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
}
@ -71,7 +81,7 @@
}
- (id)fullScreenView {
- (UIView*)fullScreenView {
id parentView = [[[[[[NSClassFromString(@"UIApplication") sharedApplication] keyWindow] rootViewController] viewControllers] firstObject] view];
id view = [self findDescendantViewOfClass:NSClassFromString(@"SPFullScreenView") inView:parentView]; // watchOS 5
if (view == nil) {
@ -94,21 +104,23 @@
- (void)didAppear {
[self hideTimeLabel];
if (emulator == nil) {
if (sharedEmulator == nil) {
[self loadAndStartEmulator];
} else {
sharedEmulator.running = YES;
}
}
- (void)willActivate {
if ([WKExtension sharedExtension].applicationState == WKApplicationStateActive) {
emulator.running = YES;
sharedEmulator.running = YES;
}
}
- (void)didDeactivate {
// This method is called when watch view controller is no longer visible
[super didDeactivate];
emulator.running = NO;
sharedEmulator.running = NO;
}
- (void)sessionReachabilityDidChange:(WCSession *)session {
@ -116,18 +128,26 @@
}
- (void)loadAndStartEmulator {
UIView *fullScreenView = [self fullScreenView];
Class emulatorClass = NSClassFromString(@"MacPlus4MEmulator");
emulator = [emulatorClass new];
emulator.rootViewController = nil;
emulator.showAlert = ^(NSString *title, NSString *message) {
sharedEmulator = [emulatorClass new];
sharedEmulator.rootViewController = nil;
sharedEmulator.showAlert = ^(NSString *title, NSString *message) {
NSLog(@"Alert: %@ - %@", title, message);
};
emulator.dataPath = [NSBundle mainBundle].resourcePath;
emulator.screenLayer = [[self fullScreenView] layer];
emulator.speed = emulator.initialSpeed;
[emulator.screenLayer setContentsGravity:@"CAGravityResizeAspectFill"];
[emulator.screenLayer setAffineTransform:CGAffineTransformScale(CGAffineTransformMakeRotation(M_PI_2), 0.375, 0.375)];
[emulator.screenLayer setMinificationFilter:@"CAFilterTrilinear"];
[emulator performSelector:@selector(run) withObject:nil afterDelay:0.1];
sharedEmulator.dataPath = [NSBundle mainBundle].resourcePath;
sharedEmulator.screenLayer = fullScreenView.layer;
sharedEmulator.speed = sharedEmulator.initialSpeed;
[sharedEmulator.screenLayer setContentsGravity:@"CAGravityResizeAspectFill"];
[sharedEmulator.screenLayer setAffineTransform:CGAffineTransformScale(CGAffineTransformMakeRotation(M_PI_2), 0.375, 0.375)];
[sharedEmulator.screenLayer setMinificationFilter:@"CAFilterTrilinear"];
[sharedEmulator performSelector:@selector(run) withObject:nil afterDelay:0.1];
id app = [NSClassFromString(@"UIApplication") sharedApplication];
[app setIdleTimerDisabled:YES];
TrackPad *trackpad = [[TrackPad alloc] initWithFrame:fullScreenView.bounds];
[fullScreenView addSubview:trackpad];
}
@end

View File

@ -0,0 +1,46 @@
//
// UIKit+Watch.h
// Mini vMac
//
// Created by Jesús A. Álvarez on 2024-03-27.
// Copyright © 2024 namedfork. All rights reserved.
//
#ifndef UIKit_Watch_h
#define UIKit_Watch_h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIResponder : NSObject
@end
@interface UIView : UIResponder
@property(nonatomic,getter=isMultipleTouchEnabled) BOOL multipleTouchEnabled;
@property(nonatomic) CGRect bounds;
- (instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
@end
@interface UITouch : NSObject
@property(nonatomic,readonly) CGFloat force;
- (CGPoint)locationInView:(nullable UIView *)view;
- (CGPoint)previousLocationInView:(nullable UIView *)view;
@end
@interface UIEvent : NSObject
@property(nonatomic,readonly) NSTimeInterval timestamp;
@end
NS_ASSUME_NONNULL_END
#endif /* UIKit_h */

View File

@ -45,6 +45,8 @@
289673912BB4947A0014D8E7 /* MacPlus4M_WatchOS.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 289673422BB209DB0014D8E7 /* MacPlus4M_WatchOS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
289673942BB494FB0014D8E7 /* Mini vMac WatchKit Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 2896738E2BB493F80014D8E7 /* Mini vMac WatchKit Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
289673972BB4958D0014D8E7 /* Mini vMac WatchKit App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 289673742BB492400014D8E7 /* Mini vMac WatchKit App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
2896739B2BB4A2E80014D8E7 /* TrackPad.m in Sources */ = {isa = PBXBuildFile; fileRef = 28BA89841CE73E7200A98104 /* TrackPad.m */; };
2896739E2BB4A90A0014D8E7 /* disk1.dsk in Resources */ = {isa = PBXBuildFile; fileRef = 2896739D2BB4A90A0014D8E7 /* disk1.dsk */; };
289710C31CFB11BF0089D463 /* MYOSGLUE.m in Sources */ = {isa = PBXBuildFile; fileRef = 28CE8ECB1CD4CDC500FE25A8 /* MYOSGLUE.m */; };
289710DC1CFB12240089D463 /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 289710D81CFB121F0089D463 /* Icon.png */; };
289710DD1CFB12240089D463 /* Icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 289710D91CFB121F0089D463 /* Icon@2x.png */; };
@ -365,6 +367,8 @@
289673842BB4937D0014D8E7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
289673852BB4937D0014D8E7 /* Interface.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Interface.storyboard; sourceTree = "<group>"; };
2896738E2BB493F80014D8E7 /* Mini vMac WatchKit Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Mini vMac WatchKit Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
2896739C2BB4A4170014D8E7 /* UIKit+Watch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIKit+Watch.h"; sourceTree = "<group>"; };
2896739D2BB4A90A0014D8E7 /* disk1.dsk */ = {isa = PBXFileReference; lastKnownFileType = file; path = disk1.dsk; sourceTree = "<group>"; };
289710D41CFB11BF0089D463 /* Mac128K.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Mac128K.framework; sourceTree = BUILT_PRODUCTS_DIR; };
289710D61CFB121F0089D463 /* CNFUDOSG.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNFUDOSG.h; sourceTree = "<group>"; };
289710D71CFB121F0089D463 /* CNFUDALL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNFUDALL.h; sourceTree = "<group>"; };
@ -652,6 +656,8 @@
2896737F2BB4937D0014D8E7 /* InterfaceController.h */,
289673802BB4937D0014D8E7 /* InterfaceController.m */,
289673812BB4937D0014D8E7 /* vMac.rom */,
2896739D2BB4A90A0014D8E7 /* disk1.dsk */,
2896739C2BB4A4170014D8E7 /* UIKit+Watch.h */,
);
path = "Mini vMac WatchKit Extension";
sourceTree = "<group>";
@ -1320,6 +1326,7 @@
buildActionMask = 2147483647;
files = (
2896738A2BB493A90014D8E7 /* Assets.xcassets in Resources */,
2896739E2BB4A90A0014D8E7 /* disk1.dsk in Resources */,
2896738D2BB493B20014D8E7 /* vMac.rom in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -1594,6 +1601,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2896739B2BB4A2E80014D8E7 /* TrackPad.m in Sources */,
2896738B2BB493AF0014D8E7 /* InterfaceController.m in Sources */,
2896738C2BB493AF0014D8E7 /* ExtensionDelegate.m in Sources */,
);

View File

@ -8,6 +8,11 @@
#import <UIKit/UIKit.h>
#if TARGET_OS_WATCH
#import "UIKit+Watch.h"
@interface TrackPad : UIView
#else
@interface TrackPad : UIControl
#endif
@end

View File

@ -7,8 +7,14 @@
//
#import "TrackPad.h"
#if TARGET_OS_WATCH
#import "InterfaceController.h"
#define AppDelegate InterfaceController
#define AudioServicesPlaySystemSound
#else
#import "AppDelegate.h"
@import AudioToolbox;
#endif
#define TRACKPAD_ACCEL_N 1
#define TRACKPAD_ACCEL_T 0.2
@ -36,6 +42,7 @@
return self;
}
#if !TARGET_OS_WATCH
- (void)willMoveToSuperview:(UIView *)newSuperview {
[super willMoveToSuperview:newSuperview];
@try {
@ -44,9 +51,14 @@
supportsForceTouch = NO;
}
}
#endif
- (BOOL)isMouseEvent:(UIEvent *)event {
#if TARGET_OS_WATCH
return NO;
#else
return event.buttonMask != 0;
#endif
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
@ -54,7 +66,7 @@
[self startDragging];
return;
}
[currentTouches unionSet:touches];
if (currentTouches.count == 1) {
[self firstTouchBegan:touches.anyObject withEvent:event];