diff --git a/appendix/GamePadViewer/src/EventObserver.swift b/appendix/GamePadViewer/src/EventObserver.swift index 9aea1d56d..85b890b51 100644 --- a/appendix/GamePadViewer/src/EventObserver.swift +++ b/appendix/GamePadViewer/src/EventObserver.swift @@ -16,7 +16,6 @@ private func callback( public class EventObserver: ObservableObject { public static let shared = EventObserver() - @ObservedObject var stickManager = StickManager.shared @Published var counter = 0 // We register the callback in the `start` method rather than in `init`. @@ -51,10 +50,8 @@ public class EventObserver: ObservableObject { if usagePage == 0x1, usage == 0x30 { counter += 1 Task { @MainActor in - stickManager.leftStick.horizontal.add(logicalMax, logicalMin, integerValue) - stickManager.leftStick.update() - - stickManager.converter.convert() + StickManager.shared.leftStick.horizontal.add(logicalMax, logicalMin, integerValue) + StickManager.shared.leftStick.update() } } @@ -62,10 +59,8 @@ public class EventObserver: ObservableObject { if usagePage == 0x1, usage == 0x31 { counter += 1 Task { @MainActor in - stickManager.leftStick.vertical.add(logicalMax, logicalMin, integerValue) - stickManager.leftStick.update() - - stickManager.converter.convert() + StickManager.shared.leftStick.vertical.add(logicalMax, logicalMin, integerValue) + StickManager.shared.leftStick.update() } } @@ -77,10 +72,8 @@ public class EventObserver: ObservableObject { if usagePage == 0x1, usage == 0x32 { counter += 1 Task { @MainActor in - stickManager.rightStick.horizontal.add(logicalMax, logicalMin, integerValue) - stickManager.rightStick.update() - - stickManager.converter.convert() + StickManager.shared.rightStick.horizontal.add(logicalMax, logicalMin, integerValue) + StickManager.shared.rightStick.update() } } @@ -88,10 +81,8 @@ public class EventObserver: ObservableObject { if usagePage == 0x1, usage == 0x35 { counter += 1 Task { @MainActor in - stickManager.rightStick.vertical.add(logicalMax, logicalMin, integerValue) - stickManager.rightStick.update() - - stickManager.converter.convert() + StickManager.shared.rightStick.vertical.add(logicalMax, logicalMin, integerValue) + StickManager.shared.rightStick.update() } } } diff --git a/appendix/GamePadViewer/src/StickManager.swift b/appendix/GamePadViewer/src/StickManager.swift index cd740f3e4..9d77a1adb 100644 --- a/appendix/GamePadViewer/src/StickManager.swift +++ b/appendix/GamePadViewer/src/StickManager.swift @@ -1,7 +1,7 @@ import Combine import SwiftUI -public class StickManager: ObservableObject { +public class StickManager { public static let shared = StickManager() class StickSensor: ObservableObject { @@ -21,63 +21,21 @@ public class StickManager: ObservableObject { } } - struct HistoryEntry { - let time = Date() - let horizontalStickSensorValue: Double - let verticalStickSensorValue: Double - } - class Stick: ObservableObject, Equatable { public let id = UUID() @Published var horizontal = StickSensor() @Published var vertical = StickSensor() - @Published var history: [HistoryEntry] = [] @Published var radian = 0.0 @Published var magnitude = 0.0 - @Published var deltaMagnitude = 0.0 - - var previousMagnitude = 0.0 @MainActor public func update() { - let now = Date() - radian = atan2(vertical.lastDoubleValue, horizontal.lastDoubleValue) magnitude = min( 1.0, sqrt(pow(vertical.lastDoubleValue, 2) + pow(horizontal.lastDoubleValue, 2))) - - deltaMagnitude = max(0.0, magnitude - previousMagnitude) - - history.append( - HistoryEntry( - horizontalStickSensorValue: horizontal.lastDoubleValue, - verticalStickSensorValue: vertical.lastDoubleValue)) - history.removeAll(where: { now.timeIntervalSince($0.time) > 0.1 }) - } - - @MainActor - public func getMaxDistanceInHistory() -> Double { - var distance = 0.0 - - history.forEach { h1 in - history.forEach { h2 in - let h = h1.horizontalStickSensorValue - h2.horizontalStickSensorValue - let v = h1.verticalStickSensorValue - h2.verticalStickSensorValue - let d = sqrt(h * h + v * v) - if d > distance { - distance = d - } - } - } - - return min(1.0, distance) - } - - @MainActor func updatePreviousMagnitude() { - previousMagnitude = magnitude } public static func == (lhs: Stick, rhs: Stick) -> Bool { @@ -85,128 +43,6 @@ public class StickManager: ObservableObject { } } - class Converter: ObservableObject { - @Published var pointerX = 0.5 // 0.0 ... 1.0 - @Published var pointerY = 0.5 // 0.0 ... 1.0 - @Published var continuedMovementMagnitude = 0.0 - - let continuedMovementThreshold = 1.0 - let deltaMagnitudeThreshold = 0.01 - - var continuedMovementPrimaryStick: Stick? - var continuedMovementSecondaryStick: Stick? - var continuedMovementTimer: Cancellable? - var continuedMovementCalled = false - - @MainActor - public func convert() { - - if let s = continuedMovementPrimaryStick { - if s.magnitude < continuedMovementThreshold { - continuedMovementPrimaryStick = nil - } - } - - if continuedMovementPrimaryStick == nil { - if StickManager.shared.leftStick.magnitude >= continuedMovementThreshold { - continuedMovementPrimaryStick = StickManager.shared.leftStick - } else if StickManager.shared.rightStick.magnitude >= continuedMovementThreshold { - continuedMovementPrimaryStick = StickManager.shared.rightStick - } - } - - if let continuedMovementPrimaryStick = continuedMovementPrimaryStick { - continuedMovementSecondaryStick = - continuedMovementPrimaryStick == StickManager.shared.leftStick - ? StickManager.shared.rightStick - : StickManager.shared.leftStick - - if continuedMovementTimer == nil { - continuedMovementMagnitude = continuedMovementPrimaryStick.getMaxDistanceInHistory() - - continuedMovementTimer = Timer.publish( - every: 0.3, // 300 ms - on: .main, in: .default - ).autoconnect() - .sink { _ in - self.updatePointerXY( - magnitude: self.getAdjustedContinuedMovementMagnitude(), - radian: self.getAdjustedContinuedMovementRadian()) - - if !self.continuedMovementCalled { - self.continuedMovementTimer = Timer.publish( - every: 0.02, // 20 ms - on: .main, in: .default - ) - .autoconnect().sink { _ in - - self.updatePointerXY( - magnitude: self.getAdjustedContinuedMovementMagnitude(), - radian: self.getAdjustedContinuedMovementRadian()) - } - self.continuedMovementCalled = true - } - } - - continuedMovementCalled = false - } - } else { - continuedMovementSecondaryStick = nil - continuedMovementTimer = nil - - var keepPreviousMagnitude = false - if 0 < StickManager.shared.rightStick.deltaMagnitude { - if StickManager.shared.rightStick.deltaMagnitude < deltaMagnitudeThreshold { - keepPreviousMagnitude = true - } else { - updatePointerXY( - magnitude: StickManager.shared.rightStick.deltaMagnitude, - radian: StickManager.shared.rightStick.radian) - } - } - - if !keepPreviousMagnitude { - StickManager.shared.rightStick.updatePreviousMagnitude() - } - } - } - - @MainActor - private func getAdjustedContinuedMovementMagnitude() -> Double { - let m2 = continuedMovementSecondaryStick?.magnitude ?? 0.0 - - if m2 < deltaMagnitudeThreshold { - return continuedMovementMagnitude - } else { - return continuedMovementMagnitude + m2 - } - } - - @MainActor - private func getAdjustedContinuedMovementRadian() -> Double { - let r1 = continuedMovementPrimaryStick?.radian ?? 0.0 - let m2 = continuedMovementSecondaryStick?.magnitude ?? 0.0 - let r2 = continuedMovementSecondaryStick?.radian ?? 0.0 - - if m2 < deltaMagnitudeThreshold { - return r1 - } else { - return (r1 + r2) / 2 - } - } - - @MainActor - private func updatePointerXY(magnitude: Double, radian: Double) { - let scale = 1.0 / 16 - - pointerX += magnitude * cos(radian) * scale - pointerX = max(0.0, min(1.0, pointerX)) - pointerY -= magnitude * sin(radian) * scale - pointerY = max(0.0, min(1.0, pointerY)) - } - } - @Published var leftStick = Stick() @Published var rightStick = Stick() - @Published var converter = Converter() } diff --git a/appendix/GamePadViewer/src/View/ContentView.swift b/appendix/GamePadViewer/src/View/ContentView.swift index 4f59e0c87..6b40715d6 100644 --- a/appendix/GamePadViewer/src/View/ContentView.swift +++ b/appendix/GamePadViewer/src/View/ContentView.swift @@ -6,9 +6,8 @@ struct ContentView: View { var body: some View { ZStack { HStack { - InformationView() - StickView() - PointerView() + StickView(stick: StickManager.shared.leftStick) + StickView(stick: StickManager.shared.rightStick) } if inputMonitoringAlertData.showing { @@ -25,128 +24,63 @@ struct ContentView: View { } } -struct InformationView: View { - @ObservedObject private var eventObserver = EventObserver.shared - @ObservedObject private var rightStick = StickManager.shared.rightStick - @ObservedObject private var converter = StickManager.shared.converter - - var body: some View { - VStack(alignment: .leading) { - Group { - Text("counter: \(eventObserver.counter)") - Text("horizontal: \(rightStick.horizontal.lastDoubleValue)") - Text("vertical: \(rightStick.vertical.lastDoubleValue)") - } - Divider() - Group { - Text("radian: \(rightStick.radian)") - Text("magnitude: \(rightStick.magnitude)") - } - Divider() - Group { - Text("deltaMagnitude: \(rightStick.deltaMagnitude)") - Text("history.count: \(rightStick.history.count)") - } - Divider() - Group { - Text("continuedMovementMagnitude: \(converter.continuedMovementMagnitude)") - } - - Divider() - Group { - Text("pointerX \(converter.pointerX)") - Text("pointerY \(converter.pointerY)") - } - } - .frame(width: 350) - } -} - struct StickView: View { - @ObservedObject private var rightStick = StickManager.shared.rightStick + @ObservedObject var stick: StickManager.Stick private let circleSize = 100.0 private let indicatorSize = 10.0 var body: some View { - ZStack(alignment: .topLeading) { - Circle() - .stroke(.gray, lineWidth: 2) - .frame(width: circleSize, height: circleSize) - - Circle() - .fill(.blue) - .frame(width: indicatorSize, height: indicatorSize) - .padding( - .leading, - circleSize / 2.0 + cos(rightStick.radian) - * rightStick.magnitude * circleSize / 2.0 - indicatorSize / 2.0 - ) - .padding( - .top, - circleSize / 2.0 - sin(rightStick.radian) - * rightStick.magnitude * circleSize / 2.0 - indicatorSize / 2.0 - ) - } - .frame( - width: circleSize + indicatorSize * 2, - height: circleSize + indicatorSize * 2) - } -} - -struct PointerView: View { - @ObservedObject private var rightStick = StickManager.shared.rightStick - @ObservedObject private var converter = StickManager.shared.converter - - private let boxWidth = 400.0 - private let boxHeight = 225.0 - private let indicatorSize = 10.0 - private let gridCount = 10 - - var body: some View { - ZStack(alignment: .topLeading) { - Rectangle() - .stroke(.gray, lineWidth: 2) - .frame(width: boxWidth, height: boxHeight) + HStack { + Grid { + GridRow { + Text("horizontal:") + .gridColumnAlignment(.trailing) + Text("\(stick.horizontal.lastDoubleValue)") + } + GridRow { + Text("vertical:") - Path { path in - for i in 1..