Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions AKPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import Foundation
private struct AKAppSettingsData: Codable {
var hideTitleBar: Bool?
var floatingWindow: Bool?
var resolution: Int?
var resizableAspectRatioWidth: Int?
var resizableAspectRatioHeight: Int?
}

class AKPlugin: NSObject, Plugin {
Expand All @@ -35,6 +38,11 @@ class AKPlugin: NSObject, Plugin {
if self.floatingWindowSetting == true {
window.level = .floating
}

if let aspectRatio = self.aspectRatioSetting {
window.contentAspectRatio = aspectRatio
}

NSWindow.allowsAutomaticWindowTabbing = true
}

Expand All @@ -57,6 +65,10 @@ class AKPlugin: NSObject, Plugin {
if self.floatingWindowSetting == true {
win.level = .floating
}

if let aspectRatio = self.aspectRatioSetting {
win.contentAspectRatio = aspectRatio
}
}
}

Expand Down Expand Up @@ -278,6 +290,17 @@ class AKPlugin: NSObject, Plugin {
/// Convenience instance property that exposes the cached static preference.
private var hideTitleBarSetting: Bool { Self.akAppSettingsData?.hideTitleBar ?? false }
private var floatingWindowSetting: Bool { Self.akAppSettingsData?.floatingWindow ?? false }
private var aspectRatioSetting: NSSize? {
guard Self.akAppSettingsData?.resolution == 6 else {
return nil
}
let width = Self.akAppSettingsData?.resizableAspectRatioWidth ?? 0
let height = Self.akAppSettingsData?.resizableAspectRatioHeight ?? 0
guard width > 0 && height > 0 else {
return nil
}
return NSSize(width: width, height: height)
}

fileprivate static var akAppSettingsData: AKAppSettingsData? = {
let bundleIdentifier = Bundle.main.bundleIdentifier ?? ""
Expand Down
118 changes: 83 additions & 35 deletions PlayTools/Controls/Frontend/ControlMode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,69 +25,117 @@ public class ControlMode: Equatable {
private var keyboardAdapter: KeyboardEventAdapter!
private var mouseAdapter: MouseEventAdapter!
private var controllerAdapter: ControllerEventAdapter!
private var keyWindowObserver: NSObjectProtocol?

public func cursorHidden() -> Bool {
return mouseAdapter?.cursorHidden() ?? false
}

public func initialize() {
let centre = NotificationCenter.default
let main = OperationQueue.main
if PlaySettings.shared.noKMOnInput {
centre.addObserver(forName: UITextField.textDidEndEditingNotification, object: nil, queue: main) { _ in
ModeAutomaton.onUITextInputEndEdit()
Toucher.writeLog(logMessage: "uitextinput end edit")
}
centre.addObserver(forName: UITextField.textDidBeginEditingNotification, object: nil, queue: main) { _ in
ModeAutomaton.onUITextInputBeginEdit()
Toucher.writeLog(logMessage: "uitextinput begin edit")
}
centre.addObserver(forName: UITextView.textDidEndEditingNotification, object: nil, queue: main) { _ in
ModeAutomaton.onUITextInputEndEdit()
Toucher.writeLog(logMessage: "uitextinput end edit")
}
centre.addObserver(forName: UITextView.textDidBeginEditingNotification, object: nil, queue: main) { _ in
ModeAutomaton.onUITextInputBeginEdit()
Toucher.writeLog(logMessage: "uitextinput begin edit")
}
setupTextInputObservers()
set(.arbitraryClick)
} else {
set(.off)
}

setupGameController()
setupKeyboard()
if PlaySettings.shared.enableScrollWheel {
setupScrollWheel()
}

// Mouse polling rate as high as 1000 causes issue to some games
setupMouseMoved(maxPollingRate: 125)
setupMouseButtons()

if PlaySettings.shared.resizableWindow {
initializeResizableWindowSupport()
}

ActionDispatcher.build()
}

private func setupTextInputObservers() {
let centre = NotificationCenter.default
let main = OperationQueue.main
centre.addObserver(forName: UITextField.textDidEndEditingNotification, object: nil, queue: main) { _ in
ModeAutomaton.onUITextInputEndEdit()
Toucher.writeLog(logMessage: "uitextinput end edit")
}
centre.addObserver(forName: UITextField.textDidBeginEditingNotification, object: nil, queue: main) { _ in
ModeAutomaton.onUITextInputBeginEdit()
Toucher.writeLog(logMessage: "uitextinput begin edit")
}
centre.addObserver(forName: UITextView.textDidEndEditingNotification, object: nil, queue: main) { _ in
ModeAutomaton.onUITextInputEndEdit()
Toucher.writeLog(logMessage: "uitextinput end edit")
}
centre.addObserver(forName: UITextView.textDidBeginEditingNotification, object: nil, queue: main) { _ in
ModeAutomaton.onUITextInputBeginEdit()
Toucher.writeLog(logMessage: "uitextinput begin edit")
}
}

private func setupGameController() {
let centre = NotificationCenter.default
let main = OperationQueue.main
centre.addObserver(forName: NSNotification.Name.GCControllerDidConnect, object: nil, queue: main) { _ in
GCController.current?.extendedGamepad?.valueChangedHandler = {profile, element in
GCController.current?.extendedGamepad?.valueChangedHandler = { profile, element in
self.controllerAdapter.handleValueChanged(profile, element)
}
}
}

AKInterface.shared!.setupKeyboard(keyboard: { keycode, pressed, isRepeat, ctrlModified in
self.keyboardAdapter.handleKey(keycode: keycode, pressed: pressed,
isRepeat: isRepeat, ctrlModified: ctrlModified)},
swapMode: ModeAutomaton.onOption)

if PlaySettings.shared.enableScrollWheel {
AKInterface.shared!.setupScrollWheel({deltaX, deltaY in
self.mouseAdapter.handleScrollWheel(deltaX: deltaX, deltaY: deltaY)
})
}
private func setupKeyboard() {
AKInterface.shared!.setupKeyboard(
keyboard: { keycode, pressed, isRepeat, ctrlModified in
self.keyboardAdapter.handleKey(
keycode: keycode,
pressed: pressed,
isRepeat: isRepeat,
ctrlModified: ctrlModified
)
},
swapMode: ModeAutomaton.onOption
)
}

// Mouse polling rate as high as 1000 causes issue to some games
setupMouseMoved(maxPollingRate: 125)
private func setupScrollWheel() {
AKInterface.shared!.setupScrollWheel({ deltaX, deltaY in
self.mouseAdapter.handleScrollWheel(deltaX: deltaX, deltaY: deltaY)
})
}

AKInterface.shared!.setupMouseButton(left: true, right: false, {_, pressed in
private func setupMouseButtons() {
AKInterface.shared!.setupMouseButton(left: true, right: false, { _, pressed in
self.mouseAdapter.handleLeftButton(pressed: pressed)
})

AKInterface.shared!.setupMouseButton(left: false, right: false, {id, pressed in
AKInterface.shared!.setupMouseButton(left: false, right: false, { id, pressed in
self.mouseAdapter.handleOtherButton(id: id, pressed: pressed)
})

AKInterface.shared!.setupMouseButton(left: false, right: true, {id, pressed in
AKInterface.shared!.setupMouseButton(left: false, right: true, { id, pressed in
self.mouseAdapter.handleOtherButton(id: id, pressed: pressed)
})
}

ActionDispatcher.build()
private func initializeResizableWindowSupport() {
// Reactivate keymapping once the key window is initialized
keyWindowObserver = NotificationCenter.default.addObserver(forName: UIWindow.didBecomeKeyNotification,
object: nil, queue: .main) { _ in
ActionDispatcher.build()
if let observer = self.keyWindowObserver {
NotificationCenter.default.removeObserver(observer)
self.keyWindowObserver = nil
}
}
// Reactivate keymapping once the user finishes resizing the window
NotificationCenter.default.addObserver(forName: Notification.Name("NSWindowDidEndLiveResizeNotification"),
object: nil, queue: .main) { _ in
ActionDispatcher.build()
}
}

private func setupMouseMoved(maxPollingRate: Int) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ public class TouchscreenMouseEventAdapter: MouseEventAdapter {
if rect.width < 1 || rect.height < 1 {
return nil
}
if screen.resizable && !screen.fullscreen {
// Allow user to resize window by dragging edges
let margin = CGFloat(10)
if point.x < margin || point.x > rect.width - margin ||
point.y < margin || point.y > rect.height - margin {
return nil
}
}
let viewRect: CGRect = screen.screenRect
let widthRate = viewRect.width / rect.width
var rate = viewRect.height / rect.height
Expand Down
16 changes: 15 additions & 1 deletion PlayTools/Controls/PTFakeTouch/NSObject+Swizzle.m
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ - (double) get_default_width {

}

- (CGRect) hook_boundsResizable {
return [PlayScreen boundsResizable:[self hook_boundsResizable]];
}

- (BOOL) hook_requiresFullScreen {
return NO;
}

- (void) hook_setCurrentSubscription:(VSSubscription *)currentSubscription {
// do nothing
}
Expand Down Expand Up @@ -240,7 +248,13 @@ @implementation PTSwizzleLoader
+ (void)load {
// This might need refactor soon
if(@available(iOS 16.3, *)) {
if ([[PlaySettings shared] adaptiveDisplay]) {
if ([[PlaySettings shared] resizableWindow]) {
[objc_getClass("_UIApplicationInfoParser") swizzleInstanceMethod:NSSelectorFromString(@"requiresFullScreen") withMethod:@selector(hook_requiresFullScreen)];
[objc_getClass("UIScreen") swizzleInstanceMethod:@selector(bounds) withMethod:@selector(hook_boundsResizable)];
[objc_getClass("UIScreen") swizzleInstanceMethod:@selector(nativeScale) withMethod:@selector(hook_nativeScale)];
[objc_getClass("UIScreen") swizzleInstanceMethod:@selector(scale) withMethod:@selector(hook_scale)];
}
else if ([[PlaySettings shared] adaptiveDisplay]) {
// This is an experimental fix
if ([[PlaySettings shared] inverseScreenValues]) {
// This lines set External Scene settings and other IOS10 Runtime services by swizzling
Expand Down
1 change: 1 addition & 0 deletions PlayTools/PlayCover.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class PlayCover: NSObject {
@objc static public func launch() {
quitWhenClose()
AKInterface.initialize()
PlayScreen.shared.initialize()
PlayInput.shared.initialize()
DiscordIPC.shared.initialize()

Expand Down
25 changes: 25 additions & 0 deletions PlayTools/PlayScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,20 @@ extension UIScreen {
public class PlayScreen: NSObject {
@objc public static let shared = PlayScreen()

func initialize() {
if resizable {
// Remove default size restrictions
NotificationCenter.default.addObserver(forName: UIWindow.didBecomeKeyNotification, object: nil,
queue: .main) { notification in
if let window = notification.object as? UIWindow,
let windowScene = window.windowScene {
windowScene.sizeRestrictions?.minimumSize = CGSize(width: 0, height: 0)
windowScene.sizeRestrictions?.maximumSize = CGSize(width: .max, height: .max)
}
}
}
}

@objc public static func frame(_ rect: CGRect) -> CGRect {
return rect.toAspectRatioReversed()
}
Expand Down Expand Up @@ -113,6 +127,10 @@ public class PlayScreen: NSObject {
return AKInterface.shared!.isFullscreen
}

var resizable: Bool {
return PlaySettings.shared.resizableWindow
}

@objc public var screenRect: CGRect {
return UIScreen.main.bounds
}
Expand Down Expand Up @@ -183,6 +201,13 @@ public class PlayScreen: NSObject {
return rect.toAspectRatioDefault()
}

private static weak var cachedWindow: UIWindow?
@objc public static func boundsResizable(_ rect: CGRect) -> CGRect {
if cachedWindow == nil {
cachedWindow = PlayScreen.shared.keyWindow
}
return cachedWindow?.bounds ?? rect
}
}

extension CGFloat {
Expand Down
5 changes: 5 additions & 0 deletions PlayTools/PlaySettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ let settings = PlaySettings.shared

@objc lazy var adaptiveDisplay = settingsData.resolution == 0 ? false : true

@objc lazy var resizableWindow = settingsData.resolution == 6 ? true : false

@objc lazy var deviceModel = settingsData.iosDeviceModel as NSString

@objc lazy var oemID: NSString = {
Expand Down Expand Up @@ -120,4 +122,7 @@ struct AppSettingsData: Codable {
var checkMicPermissionSync = false
var limitMotionUpdateFrequency = false
var disableBuiltinMouse = false
var resizableAspectRatioType = 0
var resizableAspectRatioWidth = 0
var resizableAspectRatioHeight = 0
}