From 2b11f12763de2f7b35d0943a685f48be02580fd5 Mon Sep 17 00:00:00 2001 From: TrueZhuanjia Date: Sun, 10 Aug 2025 16:19:26 +0800 Subject: [PATCH] DS4Touch on-screen widget --- VoidLink/Input/CommandManager.swift | 3 +- VoidLink/Input/OnScreenWidgetView.swift | 78 ++++++++++++++++++++----- 2 files changed, 64 insertions(+), 17 deletions(-) diff --git a/VoidLink/Input/CommandManager.swift b/VoidLink/Input/CommandManager.swift index d07cc750..2266a801 100644 --- a/VoidLink/Input/CommandManager.swift +++ b/VoidLink/Input/CommandManager.swift @@ -90,6 +90,7 @@ import UIKit "OSCDOWN" : DOWN_FLAG, "OSCLEFT" : LEFT_FLAG, "OSCRIGHT" : RIGHT_FLAG, + "DS4TOUCH" : TOUCHPAD_FLAG, "OSCL2" : 0, "L2" : 0, "LT" : 0, @@ -109,7 +110,7 @@ import UIKit "OSCBACK" ] - @objc public static let touchPadCmds: [String] = ["LSVPAD", "RSVPAD", "LSPAD", "RSPAD", "MOUSEPAD", "DPAD", "TRACKBALL", "WASDPAD", "ARROWPAD"] + @objc public static let touchPadCmds: [String] = ["LSVPAD", "RSVPAD", "LSPAD", "RSPAD", "DS4TOUCH", "MOUSEPAD", "DPAD", "TRACKBALL", "WASDPAD", "ARROWPAD"] @objc public static let stickTouchPads: [String] = ["LSVPAD", "RSVPAD", "LSPAD", "RSPAD"] @objc public static let nonVectorStickPads: [String] = ["LSPAD", "RSPAD"] @objc public static let specialOverlayButtonCmds: [String] = ["SETTINGS"] diff --git a/VoidLink/Input/OnScreenWidgetView.swift b/VoidLink/Input/OnScreenWidgetView.swift index 2b10547c..d802b1f3 100644 --- a/VoidLink/Input/OnScreenWidgetView.swift +++ b/VoidLink/Input/OnScreenWidgetView.swift @@ -141,7 +141,11 @@ import UIKit //slide buttons private var capturedTouches: NSMutableSet private let noTouch: UITouch = UITouch() - + + //controller touch pad + private var pointerIdPool: Set + private var pointerIdDict: Dictionary + private var activePointerIds: Set // whole button press down visual effect @objc public let buttonDownVisualEffectLayer = CAShapeLayer() @@ -189,6 +193,8 @@ import UIKit self.comboButtonStrings = ["OSCL3"] case "RSPAD", "RSVPAD": self.comboButtonStrings = ["OSCR3"] + case "DS4TOUCH": + self.comboButtonStrings = ["DS4TOUCH"] default: break } } @@ -233,6 +239,12 @@ import UIKit self.sensitivityFactorX = 1.0 self.sensitivityFactorY = 1.0 self.capturedTouches = NSMutableSet() + self.pointerIdDict = [:] + self.pointerIdPool = [] + for i in 0...10 { // iPadOS supports up to 11 finger touches + self.pointerIdPool.insert(UInt32(i)) + } + self.activePointerIds = [] super.init(frame: .zero) upIndicator = createLrudDirectionLayer() @@ -1125,6 +1137,11 @@ import UIKit self.sendComboButtonsUpEvent(comboStrings: self.comboButtonStrings) } } + case "DS4TOUCH": + if quickDoubleTapDetected { + self.l3r3Indicator = self.createAndShowl3r3Indicator() + self.sendComboButtonsDownEvent(comboStrings: self.comboButtonStrings) + } default: break } @@ -1145,21 +1162,10 @@ import UIKit } } - /* - if !self.buttonString.isEmpty { - // if there's no "+" in the keystring, treat it as a regular button: - if CommandManager.oscButtonMappings.keys.contains(self.cmdString) { - self.sendOscButtonDownEvent(keyString: self.cmdString) - } - if CommandManager.keyboardButtonMappings.keys.contains(self.cmdString) { - LiSendLiSendKeyboardEvent(CommandManager.keyboardButtonMappings[self.cmdString]!,Int8(KEY_ACTION_DOWN), 0) - } - if CommandManager.mouseButtonMappings.keys.contains(self.cmdString) { - LiSendMouseButtonEvent(CChar(BUTTON_ACTION_PRESS), Int32(CommandManager.mouseButtonMappings[self.cmdString]!)) - } + if self.widgetType == WidgetTypeEnum.touchPad && self.touchPadString == "DS4TOUCH" { + self.handleControllerTouchesDown(touches: touches) } - */ - + // this will also deal with button events if self.widgetType == WidgetTypeEnum.button && !self.comboButtonStrings.isEmpty { self.handleButtonDown() @@ -1204,6 +1210,42 @@ import UIKit } } + private func handleControllerTouchesDown(touches: Set) { + for touch in touches{ + let availablePointerIds = pointerIdPool.subtracting(activePointerIds) + if let pointerId = availablePointerIds.first { + pointerIdDict[ObjectIdentifier(touch)] = pointerId + let coordX = touch.location(in: self).x/self.bounds.width + let coordY = touch.location(in: self).y/self.bounds.height + LiSendControllerTouchEvent(0, UInt8(LI_TOUCH_EVENT_DOWN), pointerId, Float(coordX), Float(coordY), 1) + activePointerIds.insert(pointerId) + } + } + } + + private func handleControllerTouchesMove(touches: Set) { + for touch in touches{ + if let pointerId = pointerIdDict[ObjectIdentifier(touch)] { + let coordX = touch.location(in: self).x/self.bounds.width + let coordY = touch.location(in: self).y/self.bounds.height + LiSendControllerTouchEvent(0, UInt8(LI_TOUCH_EVENT_MOVE), pointerId, Float(coordX), Float(coordY), 1) + } + } + } + + private func handleControllerTouchesUp(touches: Set) { + for touch in touches{ + if let pointerId = pointerIdDict[ObjectIdentifier(touch)] { + let coordX = touch.location(in: self).x/self.bounds.width + let coordY = touch.location(in: self).y/self.bounds.height + LiSendControllerTouchEvent(0, UInt8(LI_TOUCH_EVENT_UP), pointerId, Float(coordX), Float(coordY), 1) + activePointerIds.remove(pointerId) + pointerIdDict.removeValue(forKey: ObjectIdentifier(touch)) + } + } + } + + private func handleButtonSlidingUp(touches: Set) { for touch in touches { for subview in self.superview?.subviews ?? [] { @@ -1296,7 +1338,6 @@ import UIKit private func handleTouchPadMoveEvent (_ touches: Set, with event: UIEvent?){ if touches.count == 1{ // don't use event.alltouches.count here, it will counts all touches - switch self.touchPadString{ case "MOUSEPAD": DispatchQueue.global(qos: .userInteractive).async { @@ -1341,6 +1382,9 @@ import UIKit break } } + if self.widgetType == WidgetTypeEnum.touchPad && self.touchPadString == "DS4TOUCH" { + self.handleControllerTouchesMove(touches: touches) + } } override func touchesEnded(_ touches: Set, with event: UIEvent?) { @@ -1421,6 +1465,8 @@ import UIKit self.onScreenControls.releaseControllerButton(RIGHT_FLAG) self.onScreenControls.releaseControllerButton(UP_FLAG) self.onScreenControls.releaseControllerButton(DOWN_FLAG) + case "DS4TOUCH": + self.handleControllerTouchesUp(touches: touches) default: break }