Skip to content

Commit

Permalink
Merge pull request #146 from XuYicong/debug-overlay
Browse files Browse the repository at this point in the history
Add a touch point visualization mechanism to help debugging
  • Loading branch information
Depal1 authored Jun 28, 2024
2 parents 476ca6e + e93fea1 commit e3a0c1f
Show file tree
Hide file tree
Showing 8 changed files with 303 additions and 34 deletions.
18 changes: 18 additions & 0 deletions PlayTools.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
6E84A14528D0F94E00BF7495 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA818CBA287ABFD5000BEE9D /* UIKit.framework */; };
6E84A15028D0F97500BF7495 /* AKInterface.bundle in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6E84A14C28D0F96D00BF7495 /* AKInterface.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
951D8275299D097C00D35B20 /* Playtools.strings in Resources */ = {isa = PBXBuildFile; fileRef = 951D8277299D097C00D35B20 /* Playtools.strings */; };
9555ED2F2C058E08006E469C /* DebugView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9555ED2E2C058E08006E469C /* DebugView.swift */; };
9555ED312C058E28006E469C /* DebugModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9555ED302C058E28006E469C /* DebugModel.swift */; };
9555ED332C058E36006E469C /* DebugController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9555ED322C058E36006E469C /* DebugController.swift */; };
954389C22B38922400B063BB /* MouseArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954389C12B38922400B063BB /* MouseArea.swift */; };
954389C42B38968C00B063BB /* Joystick.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954389C32B38968C00B063BB /* Joystick.swift */; };
954389C62B3896E600B063BB /* ChildButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954389C52B3896E600B063BB /* ChildButton.swift */; };
Expand Down Expand Up @@ -104,6 +107,9 @@
6E84A14C28D0F96D00BF7495 /* AKInterface.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AKInterface.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
951D8276299D097C00D35B20 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Playtools.strings; sourceTree = "<group>"; };
951D8278299D098000D35B20 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Playtools.strings"; sourceTree = "<group>"; };
9555ED2E2C058E08006E469C /* DebugView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugView.swift; sourceTree = "<group>"; };
9555ED302C058E28006E469C /* DebugModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugModel.swift; sourceTree = "<group>"; };
9555ED322C058E36006E469C /* DebugController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugController.swift; sourceTree = "<group>"; };
954389C12B38922400B063BB /* MouseArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MouseArea.swift; sourceTree = "<group>"; };
954389C32B38968C00B063BB /* Joystick.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Joystick.swift; sourceTree = "<group>"; };
954389C52B3896E600B063BB /* ChildButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChildButton.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -204,6 +210,14 @@
name = AKInterface;
sourceTree = "<group>";
};
9555ED2D2C058DE3006E469C /* DebugOverlay */ = {
isa = PBXGroup;
children = (
9555ED2E2C058E08006E469C /* DebugView.swift */,
9555ED302C058E28006E469C /* DebugModel.swift */,
9555ED322C058E36006E469C /* DebugController.swift */,
);
path = DebugOverlay;
954389BE2B37C75C00B063BB /* Models */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -362,6 +376,7 @@
9562D1712AB51B57002C329D /* Backend */ = {
isa = PBXGroup;
children = (
9555ED2D2C058DE3006E469C /* DebugOverlay */,
9562D17A2AB6E5ED002C329D /* Action */,
AA719724287A480C00623C15 /* Toucher.swift */,
);
Expand Down Expand Up @@ -713,15 +728,18 @@
AA7197AA287A481500623C15 /* Toast.swift in Sources */,
AA719789287A480D00623C15 /* PlayInput.swift in Sources */,
AA71970B287A44D200623C15 /* PlayLoader.m in Sources */,
9555ED332C058E36006E469C /* DebugController.swift in Sources */,
9562D1512AB484C7002C329D /* EventAdapters.swift in Sources */,
AA7197AF287A481500623C15 /* KeyCodeNames.swift in Sources */,
9555ED2F2C058E08006E469C /* DebugView.swift in Sources */,
AA71978A287A480D00623C15 /* ControlMode.swift in Sources */,
AA7197AD287A481500623C15 /* EditorController.swift in Sources */,
9562D16B2AB505AD002C329D /* MouseEventAdapter.swift in Sources */,
9562D15C2AB4FC79002C329D /* TransparentMouseEventAdapter.swift in Sources */,
9562D1772AB52550002C329D /* EditorControllerEventAdapter.swift in Sources */,
AA7197A3287A481500623C15 /* CircleMenuButton.swift in Sources */,
9562D1582AB4FB9B002C329D /* TouchscreenKeyboardEventAdapter.swift in Sources */,
9555ED312C058E28006E469C /* DebugModel.swift in Sources */,
AA7197A9287A481500623C15 /* PlayInfo.swift in Sources */,
AA71986A287A81A000623C15 /* PTFakeMetaTouch.m in Sources */,
9562D15E2AB4FCB8002C329D /* TouchscreenControllerEventAdapter.swift in Sources */,
Expand Down
84 changes: 55 additions & 29 deletions PlayTools/Controls/Backend/Action/PlayAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ protocol Action {

class ButtonAction: Action {
func invalidate() {
Toucher.touchcam(point: point, phase: UITouch.Phase.ended, tid: &id)
Toucher.touchcam(point: point, phase: UITouch.Phase.ended, tid: &id,
actionName: "Button", keyName: keyName)
}

let keyCode: Int
Expand Down Expand Up @@ -42,9 +43,11 @@ class ButtonAction: Action {

func update(pressed: Bool) {
if pressed {
Toucher.touchcam(point: point, phase: UITouch.Phase.began, tid: &id)
Toucher.touchcam(point: point, phase: UITouch.Phase.began, tid: &id,
actionName: "Button", keyName: keyName)
} else {
Toucher.touchcam(point: point, phase: UITouch.Phase.ended, tid: &id)
Toucher.touchcam(point: point, phase: UITouch.Phase.ended, tid: &id,
actionName: "Button", keyName: keyName)
}
}
}
Expand All @@ -59,7 +62,8 @@ class DraggableButtonAction: ButtonAction {

override func update(pressed: Bool) {
if pressed {
Toucher.touchcam(point: point, phase: UITouch.Phase.began, tid: &id)
Toucher.touchcam(point: point, phase: UITouch.Phase.began, tid: &id,
actionName: "DraggableButton", keyName: keyName)
self.releasePoint = point
ActionDispatcher.register(key: KeyCodeNames.mouseMove,
handler: self.onMouseMoved,
Expand All @@ -68,7 +72,8 @@ class DraggableButtonAction: ButtonAction {
AKInterface.shared!.hideCursor()
}
} else {
Toucher.touchcam(point: releasePoint, phase: UITouch.Phase.ended, tid: &id)
Toucher.touchcam(point: releasePoint, phase: UITouch.Phase.ended, tid: &id,
actionName: "DraggableButton", keyName: keyName)
if id == nil {
ActionDispatcher.unregister(key: KeyCodeNames.mouseMove)
if !mode.cursorHidden() {
Expand All @@ -86,7 +91,8 @@ class DraggableButtonAction: ButtonAction {
func onMouseMoved(deltaX: CGFloat, deltaY: CGFloat) {
self.releasePoint.x += deltaX
self.releasePoint.y -= deltaY
Toucher.touchcam(point: self.releasePoint, phase: UITouch.Phase.moved, tid: &id)
Toucher.touchcam(point: self.releasePoint, phase: UITouch.Phase.moved, tid: &id,
actionName: "DraggableButton", keyName: keyName)
}
}

Expand Down Expand Up @@ -117,13 +123,16 @@ class ContinuousJoystickAction: Action {
if dis < 16 {
if begun {
begun = false
Toucher.touchcam(point: point, phase: UITouch.Phase.ended, tid: &id)
Toucher.touchcam(point: point, phase: UITouch.Phase.ended, tid: &id,
actionName: "ControllerJoystick", keyName: key)
}
} else if !begun {
begun = true
Toucher.touchcam(point: point, phase: UITouch.Phase.began, tid: &id)
Toucher.touchcam(point: point, phase: UITouch.Phase.began, tid: &id,
actionName: "ControllerJoystick", keyName: key)
} else {
Toucher.touchcam(point: point, phase: UITouch.Phase.moved, tid: &id)
Toucher.touchcam(point: point, phase: UITouch.Phase.moved, tid: &id,
actionName: "ControllerJoystick", keyName: key)
}
}

Expand All @@ -140,7 +149,8 @@ class ContinuousJoystickAction: Action {
}

func invalidate() {
Toucher.touchcam(point: CGPoint(x: 10, y: 10), phase: UITouch.Phase.ended, tid: &id)
Toucher.touchcam(point: CGPoint(x: 10, y: 10), phase: UITouch.Phase.ended, tid: &id,
actionName: "ControllerJoystick", keyName: key)
}
}

Expand Down Expand Up @@ -178,7 +188,8 @@ class JoystickAction: Action {
}

func invalidate() {
Toucher.touchcam(point: center, phase: UITouch.Phase.ended, tid: &id)
Toucher.touchcam(point: center, phase: UITouch.Phase.ended, tid: &id,
actionName: "KeyboardJoystick", keyName: "Keyboard")
}

func getPressedHandler(index: Int) -> (Bool) -> Void {
Expand Down Expand Up @@ -228,11 +239,13 @@ class JoystickAction: Action {
let moving = id != nil
if atCenter() {
if moving {
Toucher.touchcam(point: touch, phase: UITouch.Phase.ended, tid: &id)
Toucher.touchcam(point: touch, phase: UITouch.Phase.ended, tid: &id,
actionName: "KeyboardJoystick", keyName: "Keyboard")
}
} else {
if moving {
Toucher.touchcam(point: touch, phase: UITouch.Phase.moved, tid: &id)
Toucher.touchcam(point: touch, phase: UITouch.Phase.moved, tid: &id,
actionName: "KeyboardJoystick", keyName: "Keyboard")
} else {
begin()
}
Expand All @@ -241,26 +254,29 @@ class JoystickAction: Action {

func handleFree() {
handleCommon {
Toucher.touchcam(point: self.center, phase: UITouch.Phase.began, tid: &id)
Toucher.touchcam(point: self.center, phase: UITouch.Phase.began, tid: &id,
actionName: "KeyboardJoystick", keyName: "Keyboard")
PlayInput.touchQueue.asyncAfter(deadline: .now() + 0.04, qos: .userInitiated) {
if self.id == nil {
return
}
Toucher.touchcam(point: self.touch, phase: UITouch.Phase.moved, tid: &self.id)
Toucher.touchcam(point: self.touch, phase: UITouch.Phase.moved, tid: &self.id,
actionName: "KeyboardJoystick", keyName: "Keyboard")
} // end closure
}
}

func handleFixed() {
handleCommon {
Toucher.touchcam(point: self.touch, phase: UITouch.Phase.began, tid: &id)
Toucher.touchcam(point: self.touch, phase: UITouch.Phase.began, tid: &id,
actionName: "KeyboardJoystick", keyName: "Keyboard")
}
}
}

class CameraAction: Action {
var swipeMove, swipeScale1, swipeScale2: SwipeAction
static var swipeDrag = SwipeAction()
static var swipeDrag = SwipeAction(actionName: "Drag", keyName: "ScrollWheel")
var key: String!
var center: CGPoint

Expand All @@ -269,9 +285,9 @@ class CameraAction: Action {
let centerX = data.transform.xCoord.absoluteX
let centerY = data.transform.yCoord.absoluteY
center = CGPoint(x: centerX, y: centerY)
swipeMove = SwipeAction()
swipeScale1 = SwipeAction()
swipeScale2 = SwipeAction()
swipeMove = SwipeAction(actionName: "Camera", keyName: key)
swipeScale1 = SwipeAction(actionName: "Zoom1", keyName: "ScrollWheel")
swipeScale2 = SwipeAction(actionName: "Zoom2", keyName: "ScrollWheel")
ActionDispatcher.register(key: key, handler: self.moveUpdated,
priority: .CAMERA)
ActionDispatcher.register(key: KeyCodeNames.scrollWheelScale,
Expand Down Expand Up @@ -316,7 +332,10 @@ class SwipeAction: Action {
var location: CGPoint = CGPoint.zero
private var id: Int?
let timer = DispatchSource.makeTimerSource(flags: [], queue: PlayInput.touchQueue)
init() {
private let actionName: String, keyName: String;
init(actionName: String, keyName: String) {
self.actionName = actionName
self.keyName = keyName
timer.schedule(deadline: DispatchTime.now() + 1, repeating: 0.1, leeway: DispatchTimeInterval.milliseconds(50))
timer.setEventHandler(qos: .userInteractive, handler: self.checkEnded)
timer.activate()
Expand Down Expand Up @@ -385,7 +404,8 @@ class SwipeAction: Action {
guard let start = from() else {return}
location = start
counter = 0
Toucher.touchcam(point: location, phase: UITouch.Phase.began, tid: &id)
Toucher.touchcam(point: location, phase: UITouch.Phase.began, tid: &id,
actionName: actionName, keyName: keyName)
timer.resume()
} else {
if shouldEdgeReset {
Expand All @@ -394,7 +414,8 @@ class SwipeAction: Action {
}
// 1. Put location update after touch action, so that final `end` touch has different location
// 2. If `began` touched, do not `move` touch at the same time, otherwise the two may conflict
Toucher.touchcam(point: self.location, phase: UITouch.Phase.moved, tid: &id)
Toucher.touchcam(point: self.location, phase: UITouch.Phase.moved, tid: &id,
actionName: actionName, keyName: keyName)
}
// Scale movement down, so that an edge reset won't cause a too short touch sequence
var scaledDeltaX = deltaX
Expand Down Expand Up @@ -431,7 +452,8 @@ class SwipeAction: Action {
if id == nil {
return
}
Toucher.touchcam(point: self.location, phase: UITouch.Phase.ended, tid: &id)
Toucher.touchcam(point: self.location, phase: UITouch.Phase.ended, tid: &id,
actionName: actionName, keyName: keyName)
// Touch might somehow fail to end
if id == nil {
timer.suspend()
Expand Down Expand Up @@ -461,7 +483,8 @@ class FakeMouseAction: Action {
// DispatchQueue.main.async {
// Toast.showHint(title: "Fake mouse pressed", text: ["\(self.pos)"])
// }
Toucher.touchcam(point: pos, phase: UITouch.Phase.began, tid: &id)
Toucher.touchcam(point: pos, phase: UITouch.Phase.began, tid: &id,
actionName: "FakeMouse", keyName: "FakeMouse")
ActionDispatcher.register(key: KeyCodeNames.fakeMouse,
handler: movementHandler,
priority: .DRAGGABLE)
Expand All @@ -475,7 +498,8 @@ class FakeMouseAction: Action {
// DispatchQueue.main.async {
// Toast.showHint(title: " lift Fake mouse", text: ["\(self.pos)"])
// }
Toucher.touchcam(point: pos, phase: UITouch.Phase.ended, tid: &id)
Toucher.touchcam(point: pos, phase: UITouch.Phase.ended, tid: &id,
actionName: "FakeMouse", keyName: "FakeMouse")
if id == nil {
ActionDispatcher.unregister(key: KeyCodeNames.fakeMouse)
}
Expand All @@ -484,13 +508,15 @@ class FakeMouseAction: Action {
func movementHandler(xValue: CGFloat, yValue: CGFloat) {
pos.x = xValue
pos.y = yValue
Toucher.touchcam(point: pos, phase: UITouch.Phase.moved, tid: &id)
Toucher.touchcam(point: pos, phase: UITouch.Phase.moved, tid: &id,
actionName: "FakeMouse", keyName: "FakeMouse")
}

func invalidate() {
ActionDispatcher.unregister(key: KeyCodeNames.fakeMouse)
Toucher.touchcam(point: pos,
phase: UITouch.Phase.ended, tid: &self.id)
Toucher.touchcam(point: pos ?? CGPoint(x: 10, y: 10),
phase: UITouch.Phase.ended, tid: &self.id,
actionName: "FakeMouse", keyName: "FakeMouse")
}

}
37 changes: 37 additions & 0 deletions PlayTools/Controls/Backend/DebugOverlay/DebugController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// DebugController.swift
// PlayTools
//
// Created by 许沂聪 on 2024/5/28.
//

import Foundation

class DebugController {
static let instance = DebugController()
private init() {

}

private var debugView = DebugContainer.instance

public func toggleDebugOverlay() {
let window = screen.keyWindow
let controller = window!.rootViewController
let view = controller!.view
if debugView.superview == nil {
view!.addSubview(debugView)
view!.bringSubviewToFront(debugView)
debugView.isHidden = false
debugView.isUserInteractionEnabled = false
PlayInput.touchQueue.async {
DebugModel.instance.enabled = true
}
} else {
debugView.removeFromSuperview()
PlayInput.touchQueue.async {
DebugModel.instance.enabled = false
}
}
}
}
45 changes: 45 additions & 0 deletions PlayTools/Controls/Backend/DebugOverlay/DebugModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// DebugModel.swift
// PlayTools
//
// Created by 许沂聪 on 2024/5/28.
//

import Foundation

class DebugModel {
static let instance = DebugModel()
private init() {
touches = []
}
struct TouchPoint {
var point: CGPoint
var phase: UITouch.Phase
var description: String
}

public var touches: [TouchPoint]
public var enabled = false
public func record(point: CGPoint, phase: UITouch.Phase, tid: Int, description: String) {
// If debug screen not enabled, do not record
if !enabled {
return
}
// Run in main thread, because `touches` is not thread safe
DispatchQueue.main.async {
while self.touches.count < tid {
// report error
self.touches.append(TouchPoint(
point: CGPoint(x: 100, y: 100),
phase: UITouch.Phase.cancelled,
description: "Error recording debug info: point id exceeds record array"
))
}
if self.touches.count == tid {
self.touches.append(TouchPoint(point: point, phase: phase, description: description))
} else {
self.touches[tid] = TouchPoint(point: point, phase: phase, description: description)
}
}
}
}
Loading

0 comments on commit e3a0c1f

Please sign in to comment.