From 4e83421104c96618fd1a5b2759dd728114895a10 Mon Sep 17 00:00:00 2001 From: TrueZhuanjia Date: Sat, 6 Dec 2025 11:22:19 +0800 Subject: [PATCH] on-screen button manual hover for low-end iPads --- VoidLink/Database/DataManager.h | 2 +- VoidLink/Database/DataManager.m | 4 +- VoidLink/Input/CommandManager.swift | 12 +++++- VoidLink/Input/OnScreenWidgetView.swift | 8 ++++ VoidLink/Input/PencilHandler.swift | 38 ++++++++++++++++++- VoidLink/Input/StreamView.h | 3 ++ VoidLink/Input/StreamView.m | 12 ++++++ .../ViewControllers/SettingsViewController.m | 11 ++++-- .../StreamFrameViewController.m | 8 ++++ 9 files changed, 88 insertions(+), 10 deletions(-) diff --git a/VoidLink/Database/DataManager.h b/VoidLink/Database/DataManager.h index fe1f47f7..93b57cdf 100644 --- a/VoidLink/Database/DataManager.h +++ b/VoidLink/Database/DataManager.h @@ -123,7 +123,7 @@ typedef NS_ENUM(NSInteger, PencilTickMode) { preferredCodec:(uint32_t)preferredCodec enableYUV444:(BOOL)enableYUV444 enablePIP:(BOOL)enablePIP - fullRange:(BOOL)fullRange + fullColorRange:(BOOL)fullColorRange enableHdr:(BOOL)enableHdr btMouseSupport:(BOOL)btMouseSupport // absoluteTouchMode:(BOOL)absoluteTouchMode diff --git a/VoidLink/Database/DataManager.m b/VoidLink/Database/DataManager.m index 1331e5c0..e2a84f71 100644 --- a/VoidLink/Database/DataManager.m +++ b/VoidLink/Database/DataManager.m @@ -89,7 +89,7 @@ preferredCodec:(uint32_t)preferredCodec enableYUV444:(BOOL)enableYUV444 enablePIP:(BOOL)enablePIP - fullRange:(BOOL)fullRange + fullColorRange:(BOOL)fullColorRange enableHdr:(BOOL)enableHdr btMouseSupport:(BOOL)btMouseSupport // absoluteTouchMode:(BOOL)absoluteTouchMode @@ -164,7 +164,7 @@ settingsToSave.preferredCodec = preferredCodec; settingsToSave.enableYUV444 = enableYUV444; settingsToSave.enablePIP = enablePIP; - settingsToSave.fullColorRange = fullRange; + settingsToSave.fullColorRange = fullColorRange; settingsToSave.enableHdr = enableHdr; settingsToSave.btMouseSupport = btMouseSupport; // settingsToSave.absoluteTouchMode = absoluteTouchMode; diff --git a/VoidLink/Input/CommandManager.swift b/VoidLink/Input/CommandManager.swift index 5ca6b298..c47a33a9 100644 --- a/VoidLink/Input/CommandManager.swift +++ b/VoidLink/Input/CommandManager.swift @@ -98,6 +98,7 @@ import UIKit "PADDLE3" : PADDLE3_FLAG, "PADDLE4" : PADDLE4_FLAG, "MISC" : MISC_FLAG, + "OSCHOME" : SPECIAL_FLAG, "OSCL2" : 0, "L2" : 0, "LT" : 0, @@ -126,7 +127,16 @@ import UIKit @objc public static let vectorTouchPads: [String] = ["LSVPAD", "RSVPAD", "MOUSEPAD", "TRACKBALL"] @objc public static let verticalTouchPads: [String] = ["LTPAD", "RTPAD", "MOUSEWHEEL", "WHEEL", "DISCRETEWHEEL", "DSWHEEL"] @objc public static let bidirectionalVerticalTouchPads: [String] = ["LTPAD", "RTPAD", "MOUSEWHEEL", "WHEEL", "DISCRETEWHEEL", "DSWHEEL"] - @objc public static let functionalButtonCmds: [String] = ["SETTINGS", "TOOLBOX", "WIDGETTOOL", "WIDGETPROFILES", "PROFILES", "SOFTKEYBOARD", "ABSTCHDRAG"] + @objc public static let functionalButtonCmds: [String] = [ + "SETTINGS", + "TOOLBOX", + "WIDGETTOOL", + "WIDGETPROFILES", + "PROFILES", + "SOFTKEYBOARD", + "ABSTCHDRAG", + "PENCILHOVER" + ] @objc public static let motionControlButtonCmds: [String] = ["GYRO","GYROPAUSE","ACCEL","MOTION"] // @objc public static let specialGameWidgets: [String] = ["YSRSV", "YSLT", "YSRT", "YSRB", "YSB", "YSRT2", "YSRB2", "YSB2", "YSEM", "YSML", "YSMR", "YSWASD"] diff --git a/VoidLink/Input/OnScreenWidgetView.swift b/VoidLink/Input/OnScreenWidgetView.swift index 75792524..29e5f074 100644 --- a/VoidLink/Input/OnScreenWidgetView.swift +++ b/VoidLink/Input/OnScreenWidgetView.swift @@ -34,6 +34,9 @@ import UIKit func switchWidgetProfile() func bringUpSoftKeyboard() func alterAbsTouchDragWith(mouseButton:Int32) + func switchPencilHover() + func enablePencilHover() + func disablePencilHover() } @objc enum WidgetTypeEnum: UInt8 { @@ -339,6 +342,7 @@ import UIKit } if !self.functionalButtonString.isEmpty { self.buttonMode = ButtonMode.movable.rawValue + if self.functionalButtonString == "PENCILHOVER" {self.buttonMode = ButtonMode.regular.rawValue} } } @@ -1920,6 +1924,8 @@ import UIKit let mouseButton = CommandManager.mouseButtonMappings[Set(self.comboButtonStrings).intersection(CommandManager.mouseButtonMappings.keys).first ?? "MLEFT"] ?? BUTTON_LEFT print("mouseButton \(mouseButton)"); self.functionalButtonDelegate?.alterAbsTouchDragWith(mouseButton:mouseButton) + case "PENCILHOVER": + self.functionalButtonDelegate?.enablePencilHover() default: break } @@ -1942,6 +1948,8 @@ import UIKit case "ABSTCHDRAG": // self.functionalButtonDelegate?.alterAbsTouchDragWith(mouseButton:CommandManager.mouseButtonMappings[self.comboButtonStrings.first ?? "MLEFT"] ?? BUTTON_LEFT) self.functionalButtonDelegate?.alterAbsTouchDragWith(mouseButton:BUTTON_LEFT) + case "PENCILHOVER": + self.functionalButtonDelegate?.disablePencilHover() default: break } diff --git a/VoidLink/Input/PencilHandler.swift b/VoidLink/Input/PencilHandler.swift index 6db1d510..ae9f866b 100644 --- a/VoidLink/Input/PencilHandler.swift +++ b/VoidLink/Input/PencilHandler.swift @@ -17,6 +17,8 @@ import UIKit private var streamAspectRatio: Float private var tickInterval: TimeInterval private var manualTick: Bool + private var manualhoverFlag: Bool = false + private var autoHoverFlag: Bool = false @objc init(streamView: UIView, settings: TemporarySettings) { self.streamView = streamView @@ -135,6 +137,7 @@ import UIKit let altitude = touch.altitudeAngle let location = self.adjustCoordinatesForVideoArea(point: point) let videoSize = self.getVideoAreaSize() + let normalizedLocation = CGPoint(x: location.x/videoSize.width, y: location.y/videoSize.height) let force = Float(touch.force/touch.maximumPossibleForce)/sin(Float(altitude)) let eventType:UInt8 @@ -143,7 +146,7 @@ import UIKit case .began: eventType = UInt8(LI_TOUCH_EVENT_DOWN) case .moved: - eventType = UInt8(LI_TOUCH_EVENT_MOVE) + eventType = UInt8(manualhoverFlag ? LI_TOUCH_EVENT_HOVER : LI_TOUCH_EVENT_MOVE) case .ended: eventType = UInt8(LI_TOUCH_EVENT_UP) case .cancelled: @@ -156,10 +159,41 @@ import UIKit delay = eventType == UInt8(LI_TOUCH_EVENT_UP) ? delay : 0 DispatchQueue.global().asyncAfter(deadline: dispatchMoment + tickMoment + delay) { - LiSendPenEvent(eventType, UInt8(LI_TOOL_TYPE_PEN), 0, Float(location.x/videoSize.width), Float(location.y/videoSize.height), force, 0, 0, self.getRotation(fromAzimuthAngle: Float(azimuth)), self.getTilt(fromAltitudeAngle: Float(altitude))) + LiSendPenEvent(eventType, UInt8(LI_TOOL_TYPE_PEN), 0, Float(normalizedLocation.x), Float(normalizedLocation.y), force, 0, 0, self.getRotation(fromAzimuthAngle: Float(azimuth)), self.getTilt(fromAltitudeAngle: Float(altitude))) } } return dispatchMoment + tickMoment + delay } + + @objc public func switchPencilHoever(){ + manualhoverFlag = !manualhoverFlag + } + + @objc public func enablePencilHover(){ + manualhoverFlag = true + } + + @objc public func disablePencilHover(){ + manualhoverFlag = false + } + + private func attachHoverLeave(normalizedLocation:CGPoint){ + DispatchQueue.global().asyncAfter(deadline: .now()+0.0086) { + LiSendPenEvent(UInt8(LI_TOUCH_EVENT_HOVER), UInt8(LI_TOOL_TYPE_PEN), 0, Float(normalizedLocation.x), Float(normalizedLocation.y), 0, 0, 0, 0, 0) + DispatchQueue.global().asyncAfter(deadline: .now()+0.0086) { + // LiSendPenEvent(UInt8(LI_TOUCH_EVENT_HOVER_LEAVE), UInt8(LI_TOOL_TYPE_PEN), 0, Float(normalizedLocation.x), Float(normalizedLocation.y), 0, 0, 0, 0, 0) + } + } + } + + private func preTouchHoverActionAt(normalizedLocation:CGPoint){ + DispatchQueue.global().asyncAfter(deadline: .now()+0.0086) { + LiSendPenEvent(UInt8(LI_TOUCH_EVENT_HOVER), UInt8(LI_TOOL_TYPE_PEN), 0, Float(normalizedLocation.x), Float(normalizedLocation.y), 0, 0, 0, 0, 0) + DispatchQueue.global().asyncAfter(deadline: .now()+0.0086) { + LiSendPenEvent(UInt8(LI_TOUCH_EVENT_HOVER_LEAVE), UInt8(LI_TOOL_TYPE_PEN), 0, Float(normalizedLocation.x), Float(normalizedLocation.y), 0, 0, 0, 0, 0) + } + } + } + } diff --git a/VoidLink/Input/StreamView.h b/VoidLink/Input/StreamView.h index 8bbc1abf..992facf6 100644 --- a/VoidLink/Input/StreamView.h +++ b/VoidLink/Input/StreamView.h @@ -70,6 +70,9 @@ - (void)alterAbsTouchDragWith:(int32_t)mouseButton; +- (void)enablePencilHover; +- (void)disablePencilHover; + #if !TARGET_OS_TV - (void) updateCursorLocation:(CGPoint)location isMouse:(BOOL)isMouse; #endif diff --git a/VoidLink/Input/StreamView.m b/VoidLink/Input/StreamView.m index 9c0d3774..d45bff1c 100644 --- a/VoidLink/Input/StreamView.m +++ b/VoidLink/Input/StreamView.m @@ -1420,6 +1420,18 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; else return; } +- (void)switchPencilHover{ + [pencilHandler switchPencilHoever]; +} + +- (void)enablePencilHover{ + [pencilHandler enablePencilHover]; +} + +- (void)disablePencilHover{ + [pencilHandler disablePencilHover]; +} + #if !TARGET_OS_TV - (BOOL)isMultipleTouchEnabled { diff --git a/VoidLink/ViewControllers/SettingsViewController.m b/VoidLink/ViewControllers/SettingsViewController.m index ae5b3173..9f71d5cc 100644 --- a/VoidLink/ViewControllers/SettingsViewController.m +++ b/VoidLink/ViewControllers/SettingsViewController.m @@ -759,7 +759,7 @@ BOOL isCustomResolution(int resolutionSelected) { [self addSetting:self.codecStack ofId:@"codecStack" withInfoTag:NO withDynamicLabel:NO to:videoSection]; [self addSetting:self.hdrStack ofId:@"hdrStack" withInfoTag:![self hdrSupported] withDynamicLabel:NO to:videoSection]; [self addSetting:self.yuv444Stack ofId:@"yuv444Stack" withInfoTag:YES withDynamicLabel:NO to:videoSection]; - [self addSetting:self.fullColorRangeStack ofId:@"fullRangeStack" withInfoTag:NO withDynamicLabel:NO to:videoSection]; + [self addSetting:self.fullColorRangeStack ofId:@"fullColorRangeStack" withInfoTag:NO withDynamicLabel:NO to:videoSection]; [self addSetting:self.pipStack ofId:@"pipStack" withInfoTag:YES withDynamicLabel:NO to:videoSection]; [self addSetting:self.framePacingStack ofId:@"framePacingStack" withInfoTag:YES withDynamicLabel:NO to:videoSection]; [self addSetting:self.frameQueueSizeStack ofId:@"frameQueueSizeStack" withInfoTag:NO withDynamicLabel:YES to:videoSection]; @@ -3368,7 +3368,7 @@ BOOL isCustomResolution(int resolutionSelected) { uint32_t preferredCodec = [self getChosenCodecPreference]; BOOL enableYUV444 = self.yuv444Switch.isOn; BOOL enablePIP = self.pipSwitch.isOn; - BOOL fullRange = self.fullColorRangeSwitch.isOn; + BOOL fullColorRange = self.fullColorRangeSwitch.isOn; BOOL btMouseSupport = self.citrixX1MouseSwitch.isOn; NSInteger touchMode = [self isNotNativeTouchOnly] ? self.touchModeSelector1.selectedSegmentIndex : NativeTouchOnly; NSInteger statsOverlayLevel = [self.statsOverlaySelector selectedSegmentIndex]; @@ -3441,7 +3441,7 @@ BOOL isCustomResolution(int resolutionSelected) { preferredCodec:preferredCodec enableYUV444:enableYUV444 enablePIP:enablePIP - fullRange:fullRange + fullColorRange:fullColorRange enableHdr:enableHdr btMouseSupport:btMouseSupport touchMode:touchMode @@ -3499,7 +3499,8 @@ BOOL isCustomResolution(int resolutionSelected) { uint32_t codec = [self getChosenCodecPreference]; BOOL isAV1 = (codec == CODEC_PREF_AV1); BOOL isH264 = (codec == CODEC_PREF_H264); - + BOOL isHEVC = (codec == CODEC_PREF_HEVC); + if (isAV1) { // AV1 must use limited range, so disable fullRange and turn it off [self.fullColorRangeSwitch setOn:NO animated:NO]; @@ -3512,6 +3513,8 @@ BOOL isCustomResolution(int resolutionSelected) { [self.fullColorRangeSwitch setEnabled:YES]; [self.yuv444Switch setEnabled:YES]; } + + if(isHEVC || isH264) [self.fullColorRangeSwitch setOn:YES animated:NO]; // H264 doesn't support HDR, so disable it and turn it off if (isH264) { diff --git a/VoidLink/ViewControllers/StreamFrameViewController.m b/VoidLink/ViewControllers/StreamFrameViewController.m index e2db3407..5266b650 100644 --- a/VoidLink/ViewControllers/StreamFrameViewController.m +++ b/VoidLink/ViewControllers/StreamFrameViewController.m @@ -1590,6 +1590,14 @@ [_motionHandler stopAccelUpdate]; } +- (void)enablePencilHover{ + [_streamView enablePencilHover]; +} + +- (void)disablePencilHover{ + [_streamView disablePencilHover]; +} + #if !TARGET_OS_TV // Require a confirmation when streaming to activate a system gesture - (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {