Skip to content

Commit c333efc

Browse files
authored
Merge branch 'master' into rotation-state-fix
2 parents ccac372 + 3838cd6 commit c333efc

15 files changed

Lines changed: 551 additions & 64 deletions

File tree

AKPlugin.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import Foundation
1313
private struct AKAppSettingsData: Codable {
1414
var hideTitleBar: Bool?
1515
var floatingWindow: Bool?
16+
var resolution: Int?
17+
var resizableAspectRatioWidth: Int?
18+
var resizableAspectRatioHeight: Int?
1619
}
1720

1821
class AKPlugin: NSObject, Plugin {
@@ -35,6 +38,11 @@ class AKPlugin: NSObject, Plugin {
3538
if self.floatingWindowSetting == true {
3639
window.level = .floating
3740
}
41+
42+
if let aspectRatio = self.aspectRatioSetting {
43+
window.contentAspectRatio = aspectRatio
44+
}
45+
3846
NSWindow.allowsAutomaticWindowTabbing = true
3947
}
4048

@@ -57,6 +65,10 @@ class AKPlugin: NSObject, Plugin {
5765
if self.floatingWindowSetting == true {
5866
win.level = .floating
5967
}
68+
69+
if let aspectRatio = self.aspectRatioSetting {
70+
win.contentAspectRatio = aspectRatio
71+
}
6072
}
6173
}
6274

@@ -278,6 +290,17 @@ class AKPlugin: NSObject, Plugin {
278290
/// Convenience instance property that exposes the cached static preference.
279291
private var hideTitleBarSetting: Bool { Self.akAppSettingsData?.hideTitleBar ?? false }
280292
private var floatingWindowSetting: Bool { Self.akAppSettingsData?.floatingWindow ?? false }
293+
private var aspectRatioSetting: NSSize? {
294+
guard Self.akAppSettingsData?.resolution == 6 else {
295+
return nil
296+
}
297+
let width = Self.akAppSettingsData?.resizableAspectRatioWidth ?? 0
298+
let height = Self.akAppSettingsData?.resizableAspectRatioHeight ?? 0
299+
guard width > 0 && height > 0 else {
300+
return nil
301+
}
302+
return NSSize(width: width, height: height)
303+
}
281304

282305
fileprivate static var akAppSettingsData: AKAppSettingsData? = {
283306
let bundleIdentifier = Bundle.main.bundleIdentifier ?? ""

PlayTools.xcodeproj/project.pbxproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,11 @@
8181
B127172528817C040025112B /* DiscordIPC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B127172428817C040025112B /* DiscordIPC.swift */; };
8282
B1271729288284BE0025112B /* DiscordActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1271728288284BE0025112B /* DiscordActivity.swift */; };
8383
B1E8CF8A28BBE2AB004340D3 /* Keymapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E8CF8928BBE2AB004340D3 /* Keymapping.swift */; };
84+
B444BB0D2F49C1D100ADCC5A /* ControllerFocus.m in Sources */ = {isa = PBXBuildFile; fileRef = B444BB0B2F49C1D100ADCC5A /* ControllerFocus.m */; };
8485
B46C02C72C634AB5007637AB /* BatteryLevel.m in Sources */ = {isa = PBXBuildFile; fileRef = B46C02C62C634AB5007637AB /* BatteryLevel.m */; };
8586
B66E65002C936EA100E48FD0 /* PlayedAppleDBConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66E64FF2C936E9800E48FD0 /* PlayedAppleDBConstants.swift */; };
8687
B6D774FF2ACFC3D900C0D9D8 /* SwordRPC in Frameworks */ = {isa = PBXBuildFile; productRef = B6D774FE2ACFC3D900C0D9D8 /* SwordRPC */; };
88+
D04B12CA2EF6F3DD008FEC14 /* MediaVolume.m in Sources */ = {isa = PBXBuildFile; fileRef = D04B12C92EF6F3DD008FEC14 /* MediaVolume.m */; };
8789
EEB248592B81D074000C230A /* PlayedAppleDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEB248582B81D074000C230A /* PlayedAppleDB.swift */; };
8890
/* End PBXBuildFile section */
8991

@@ -180,9 +182,12 @@
180182
B127172428817C040025112B /* DiscordIPC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscordIPC.swift; sourceTree = "<group>"; };
181183
B1271728288284BE0025112B /* DiscordActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscordActivity.swift; sourceTree = "<group>"; };
182184
B1E8CF8928BBE2AB004340D3 /* Keymapping.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Keymapping.swift; sourceTree = "<group>"; };
185+
B444BB0B2F49C1D100ADCC5A /* ControllerFocus.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ControllerFocus.m; sourceTree = "<group>"; };
183186
B46C02C62C634AB5007637AB /* BatteryLevel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BatteryLevel.m; sourceTree = "<group>"; };
184187
B46C02C82C634C60007637AB /* BatteryLevel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BatteryLevel.h; sourceTree = "<group>"; };
185188
B66E64FF2C936E9800E48FD0 /* PlayedAppleDBConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayedAppleDBConstants.swift; sourceTree = "<group>"; };
189+
D04B12C92EF6F3DD008FEC14 /* MediaVolume.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MediaVolume.m; sourceTree = "<group>"; };
190+
D04B12CC2EF6F3F9008FEC14 /* MediaVolume.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MediaVolume.h; sourceTree = "<group>"; };
186191
EEB248582B81D074000C230A /* PlayedAppleDB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayedAppleDB.swift; sourceTree = "<group>"; };
187192
/* End PBXFileReference section */
188193

@@ -480,6 +485,9 @@
480485
6E7663A428D0FEBE00DE4AF9 /* AKPluginLoader.swift */,
481486
B46C02C62C634AB5007637AB /* BatteryLevel.m */,
482487
B46C02C82C634C60007637AB /* BatteryLevel.h */,
488+
B444BB0B2F49C1D100ADCC5A /* ControllerFocus.m */,
489+
D04B12C92EF6F3DD008FEC14 /* MediaVolume.m */,
490+
D04B12CC2EF6F3F9008FEC14 /* MediaVolume.h */,
483491
);
484492
path = Utils;
485493
sourceTree = "<group>";
@@ -709,6 +717,7 @@
709717
files = (
710718
954389CA2B392D7800B063BB /* DraggableButton.swift in Sources */,
711719
9562D16D2AB505D4002C329D /* ControllerEventAdapter.swift in Sources */,
720+
B444BB0D2F49C1D100ADCC5A /* ControllerFocus.m in Sources */,
712721
AA71975A287A480D00623C15 /* Toucher.swift in Sources */,
713722
AA7197A1287A481500623C15 /* CircleMenuLoader.swift in Sources */,
714723
6E76639B28D0FAE700DE4AF9 /* Plugin.swift in Sources */,
@@ -729,6 +738,7 @@
729738
AA71970D287A44D200623C15 /* PlaySettings.swift in Sources */,
730739
95D474FB2C0BA77B0072797F /* JoystickElement.swift in Sources */,
731740
AA719759287A480D00623C15 /* PlayAction.swift in Sources */,
741+
D04B12CA2EF6F3DD008FEC14 /* MediaVolume.m in Sources */,
732742
954389C82B392D5300B063BB /* Button.swift in Sources */,
733743
6E7663A528D0FEBE00DE4AF9 /* AKPluginLoader.swift in Sources */,
734744
9562D16F2AB50D34002C329D /* ActionDispatcher.swift in Sources */,

PlayTools/Controls/Frontend/ControlMode.swift

Lines changed: 84 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -25,69 +25,118 @@ public class ControlMode: Equatable {
2525
private var keyboardAdapter: KeyboardEventAdapter!
2626
private var mouseAdapter: MouseEventAdapter!
2727
private var controllerAdapter: ControllerEventAdapter!
28+
private var keyWindowObserver: NSObjectProtocol?
2829

2930
public func cursorHidden() -> Bool {
3031
return mouseAdapter?.cursorHidden() ?? false
3132
}
3233

3334
public func initialize() {
34-
let centre = NotificationCenter.default
35-
let main = OperationQueue.main
3635
if PlaySettings.shared.noKMOnInput {
37-
centre.addObserver(forName: UITextField.textDidEndEditingNotification, object: nil, queue: main) { _ in
38-
ModeAutomaton.onUITextInputEndEdit()
39-
Toucher.writeLog(logMessage: "uitextinput end edit")
40-
}
41-
centre.addObserver(forName: UITextField.textDidBeginEditingNotification, object: nil, queue: main) { _ in
42-
ModeAutomaton.onUITextInputBeginEdit()
43-
Toucher.writeLog(logMessage: "uitextinput begin edit")
44-
}
45-
centre.addObserver(forName: UITextView.textDidEndEditingNotification, object: nil, queue: main) { _ in
46-
ModeAutomaton.onUITextInputEndEdit()
47-
Toucher.writeLog(logMessage: "uitextinput end edit")
48-
}
49-
centre.addObserver(forName: UITextView.textDidBeginEditingNotification, object: nil, queue: main) { _ in
50-
ModeAutomaton.onUITextInputBeginEdit()
51-
Toucher.writeLog(logMessage: "uitextinput begin edit")
52-
}
36+
setupTextInputObservers()
5337
set(.arbitraryClick)
5438
} else {
5539
set(.off)
5640
}
5741

42+
setupGameController()
43+
setupKeyboard()
44+
if PlaySettings.shared.enableScrollWheel {
45+
setupScrollWheel()
46+
}
47+
48+
// Mouse polling rate as high as 1000 causes issue to some games
49+
setupMouseMoved(maxPollingRate: 125)
50+
setupMouseButtons()
51+
52+
if PlaySettings.shared.resizableWindow {
53+
initializeResizableWindowSupport()
54+
}
55+
56+
ActionDispatcher.build()
57+
}
58+
59+
private func setupTextInputObservers() {
60+
let centre = NotificationCenter.default
61+
let main = OperationQueue.main
62+
centre.addObserver(forName: UITextField.textDidEndEditingNotification, object: nil, queue: main) { _ in
63+
ModeAutomaton.onUITextInputEndEdit()
64+
Toucher.writeLog(logMessage: "uitextinput end edit")
65+
}
66+
centre.addObserver(forName: UITextField.textDidBeginEditingNotification, object: nil, queue: main) { _ in
67+
ModeAutomaton.onUITextInputBeginEdit()
68+
Toucher.writeLog(logMessage: "uitextinput begin edit")
69+
}
70+
centre.addObserver(forName: UITextView.textDidEndEditingNotification, object: nil, queue: main) { _ in
71+
ModeAutomaton.onUITextInputEndEdit()
72+
Toucher.writeLog(logMessage: "uitextinput end edit")
73+
}
74+
centre.addObserver(forName: UITextView.textDidBeginEditingNotification, object: nil, queue: main) { _ in
75+
ModeAutomaton.onUITextInputBeginEdit()
76+
Toucher.writeLog(logMessage: "uitextinput begin edit")
77+
}
78+
}
79+
80+
private func setupGameController() {
81+
let centre = NotificationCenter.default
82+
let main = OperationQueue.main
5883
centre.addObserver(forName: NSNotification.Name.GCControllerDidConnect, object: nil, queue: main) { _ in
59-
GCController.current?.extendedGamepad?.valueChangedHandler = {profile, element in
84+
GCController.shouldMonitorBackgroundEvents = true
85+
GCController.current?.extendedGamepad?.valueChangedHandler = { profile, element in
6086
self.controllerAdapter.handleValueChanged(profile, element)
6187
}
6288
}
89+
}
6390

64-
AKInterface.shared!.setupKeyboard(keyboard: { keycode, pressed, isRepeat, ctrlModified in
65-
self.keyboardAdapter.handleKey(keycode: keycode, pressed: pressed,
66-
isRepeat: isRepeat, ctrlModified: ctrlModified)},
67-
swapMode: ModeAutomaton.onOption)
68-
69-
if PlaySettings.shared.enableScrollWheel {
70-
AKInterface.shared!.setupScrollWheel({deltaX, deltaY in
71-
self.mouseAdapter.handleScrollWheel(deltaX: deltaX, deltaY: deltaY)
72-
})
73-
}
91+
private func setupKeyboard() {
92+
AKInterface.shared!.setupKeyboard(
93+
keyboard: { keycode, pressed, isRepeat, ctrlModified in
94+
self.keyboardAdapter.handleKey(
95+
keycode: keycode,
96+
pressed: pressed,
97+
isRepeat: isRepeat,
98+
ctrlModified: ctrlModified
99+
)
100+
},
101+
swapMode: ModeAutomaton.onOption
102+
)
103+
}
74104

75-
// Mouse polling rate as high as 1000 causes issue to some games
76-
setupMouseMoved(maxPollingRate: 125)
105+
private func setupScrollWheel() {
106+
AKInterface.shared!.setupScrollWheel({ deltaX, deltaY in
107+
self.mouseAdapter.handleScrollWheel(deltaX: deltaX, deltaY: deltaY)
108+
})
109+
}
77110

78-
AKInterface.shared!.setupMouseButton(left: true, right: false, {_, pressed in
111+
private func setupMouseButtons() {
112+
AKInterface.shared!.setupMouseButton(left: true, right: false, { _, pressed in
79113
self.mouseAdapter.handleLeftButton(pressed: pressed)
80114
})
81115

82-
AKInterface.shared!.setupMouseButton(left: false, right: false, {id, pressed in
116+
AKInterface.shared!.setupMouseButton(left: false, right: false, { id, pressed in
83117
self.mouseAdapter.handleOtherButton(id: id, pressed: pressed)
84118
})
85119

86-
AKInterface.shared!.setupMouseButton(left: false, right: true, {id, pressed in
120+
AKInterface.shared!.setupMouseButton(left: false, right: true, { id, pressed in
87121
self.mouseAdapter.handleOtherButton(id: id, pressed: pressed)
88122
})
123+
}
89124

90-
ActionDispatcher.build()
125+
private func initializeResizableWindowSupport() {
126+
// Reactivate keymapping once the key window is initialized
127+
keyWindowObserver = NotificationCenter.default.addObserver(forName: UIWindow.didBecomeKeyNotification,
128+
object: nil, queue: .main) { _ in
129+
ActionDispatcher.build()
130+
if let observer = self.keyWindowObserver {
131+
NotificationCenter.default.removeObserver(observer)
132+
self.keyWindowObserver = nil
133+
}
134+
}
135+
// Reactivate keymapping once the user finishes resizing the window
136+
NotificationCenter.default.addObserver(forName: Notification.Name("NSWindowDidEndLiveResizeNotification"),
137+
object: nil, queue: .main) { _ in
138+
ActionDispatcher.build()
139+
}
91140
}
92141

93142
private func setupMouseMoved(maxPollingRate: Int) {

PlayTools/Controls/Frontend/EventAdapter/Mouse/Instances/TouchscreenMouseEventAdapter.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ public class TouchscreenMouseEventAdapter: MouseEventAdapter {
1818
if rect.width < 1 || rect.height < 1 {
1919
return nil
2020
}
21+
if screen.resizable && !screen.fullscreen {
22+
// Allow user to resize window by dragging edges
23+
let margin = CGFloat(10)
24+
if point.x < margin || point.x > rect.width - margin ||
25+
point.y < margin || point.y > rect.height - margin {
26+
return nil
27+
}
28+
}
2129
let viewRect: CGRect = screen.screenRect
2230
let widthRate = viewRect.width / rect.width
2331
var rate = viewRect.height / rect.height

PlayTools/Controls/MenuController.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,17 @@ var keymapping = [
150150
NSLocalizedString("menu.keymapping.nextKeymap", tableName: "Playtools",
151151
value: "Next Keymap", comment: "")
152152
]
153+
var iconsSelctor = [
154+
UIImage(systemName: "pencil"),
155+
UIImage(systemName: "trash.fill"),
156+
UIImage(systemName: "square.resize.up"),
157+
UIImage(systemName: "square.resize.down"),
158+
UIImage(systemName: "rectangle.landscape.rotate"),
159+
UIImage(systemName: "wrench.and.screwdriver"),
160+
UIImage(systemName: "pointer.arrow.slash"),
161+
UIImage(systemName: "arrow.down.square"),
162+
UIImage(systemName: "arrow.up.square")
163+
]
153164
var keymappingSelectors = [#selector(UIApplication.switchEditorMode(_:)),
154165
#selector(UIApplication.removeElement(_:)),
155166
#selector(UIApplication.upscaleElement(_:)),
@@ -229,8 +240,9 @@ class MenuController {
229240
"[", // Previous keymap
230241
"]" // Next keymap
231242
]
232-
let arrowKeyChildrenCommands = zip(keyCommands, keymapping).map { (command, btn) in
233-
UIKeyCommand(title: btn, image: nil,
243+
let arrowKeyChildrenCommands = zip(zip(keyCommands, keymapping), iconsSelctor).map { (arg0, image) in
244+
let (command, btn) = arg0
245+
return UIKeyCommand(title: btn, image: image,
234246
action: keymappingSelectors[keymapping.firstIndex(of: btn)!],
235247
input: command,
236248
modifierFlags: .command,

PlayTools/Controls/PTFakeTouch/NSObject+Swizzle.m

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@ - (double) get_default_width {
149149

150150
}
151151

152+
- (CGRect) hook_boundsResizable {
153+
return [PlayScreen boundsResizable:[self hook_boundsResizable]];
154+
}
155+
156+
- (BOOL) hook_requiresFullScreen {
157+
return NO;
158+
}
159+
152160
- (void) hook_setCurrentSubscription:(VSSubscription *)currentSubscription {
153161
// do nothing
154162
}
@@ -240,7 +248,13 @@ @implementation PTSwizzleLoader
240248
+ (void)load {
241249
// This might need refactor soon
242250
if(@available(iOS 16.3, *)) {
243-
if ([[PlaySettings shared] adaptiveDisplay]) {
251+
if ([[PlaySettings shared] resizableWindow]) {
252+
[objc_getClass("_UIApplicationInfoParser") swizzleInstanceMethod:NSSelectorFromString(@"requiresFullScreen") withMethod:@selector(hook_requiresFullScreen)];
253+
[objc_getClass("UIScreen") swizzleInstanceMethod:@selector(bounds) withMethod:@selector(hook_boundsResizable)];
254+
[objc_getClass("UIScreen") swizzleInstanceMethod:@selector(nativeScale) withMethod:@selector(hook_nativeScale)];
255+
[objc_getClass("UIScreen") swizzleInstanceMethod:@selector(scale) withMethod:@selector(hook_scale)];
256+
}
257+
else if ([[PlaySettings shared] adaptiveDisplay]) {
244258
// This is an experimental fix
245259
if ([[PlaySettings shared] inverseScreenValues]) {
246260
// This lines set External Scene settings and other IOS10 Runtime services by swizzling

PlayTools/MysticRunes/PlayShadow.m

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#import <Foundation/Foundation.h>
99
#import <objc/runtime.h>
10+
#import <UIKit/UIKit.h>
1011
#import <PlayTools/PlayTools-Swift.h>
1112

1213
__attribute__((visibility("hidden")))
@@ -116,6 +117,23 @@ - (NSDictionary *) pm_return_empty_dictionary {
116117
return @{};
117118
}
118119

120+
// Endfield UIAlertController hook
121+
- (void)pm_endfield_presentViewController:(UIViewController *)viewControllerToPresent
122+
animated:(BOOL)flag
123+
completion:(void (^)(void))completion {
124+
// If it's a UIAlertController, silently ignore it
125+
if ([viewControllerToPresent isKindOfClass:[UIAlertController class]]) {
126+
NSLog(@"PC-DEBUG: [PlayShadow] Blocked UIAlertController for Endfield");
127+
if (completion) {
128+
completion();
129+
}
130+
return;
131+
}
132+
133+
// Otherwise, present normally
134+
[self pm_endfield_presentViewController:viewControllerToPresent animated:flag completion:completion];
135+
}
136+
119137
// Class methods
120138

121139
+ (void) pm_return_2_with_completion_handler:(void (^)(NSInteger))completionHandler {
@@ -171,6 +189,14 @@ + (void) load {
171189

172190
// canResizeToFitContent
173191
// [objc_getClass("UIWindow") swizzleInstanceMethod:@selector(canResizeToFitContent) withMethod:@selector(pm_return_true)];
192+
193+
// Block UIAlertController presentation to bypass Endfield jailbreak message
194+
NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier];
195+
if ([bundleID isEqualToString:@"com.gryphline.endfield.ios"] ||
196+
[bundleID isEqualToString:@"com.hypergryph.endfield"]) {
197+
[self debugLogger:@"loading UIAlertController bypass"];
198+
[objc_getClass("UIViewController") swizzleInstanceMethod:@selector(presentViewController:animated:completion:) withMethod:@selector(pm_endfield_presentViewController:animated:completion:)];
199+
}
174200
}
175201

176202
+ (void) loadJailbreakBypass {

0 commit comments

Comments
 (0)