feat: functional button "AbsTchDrag"

This commit is contained in:
TrueZhuanjia
2025-11-05 11:51:29 +08:00
parent 1ad8f51b7a
commit a23a5491ae
7 changed files with 99 additions and 27 deletions
+2
View File
@@ -11,8 +11,10 @@
NS_ASSUME_NONNULL_BEGIN
@interface AbsoluteTouchHandler : UIResponder
@property (assign,nonatomic) int mouseButtonForCursorMove;
- (id)initWithView:(StreamView*)view andSettings:(TemporarySettings*)settings;
- (void)pauseLeftButtonDrag;
@end
+54 -23
View File
@@ -34,6 +34,8 @@
UITouch* lastTouchUp;
CGPoint lastTouchUpLocation;
UITouch* capturedTouch;
CGPoint touchBeganLocation;
CGPoint movingTouchLocation;
@@ -47,6 +49,7 @@
CGFloat _edgeTolerance;
bool _delayMouseLeftClick;
bool dragButtonDown;
bool rightButtonClicked;
}
@@ -55,8 +58,10 @@
self = [self init];
self->streamView = view;
_delayMouseLeftClick = settings.delayLeftClick;
// _delayMouseLeftClick = settings.delayLeftClick;
_delayMouseLeftClick = true; // deprecate legacy absolute touch
dragButtonDown = false;
leftClickTimeThreshold = 0.15;
// upper screen check
@@ -65,13 +70,18 @@
screenWidthWithThreshold = CGRectGetWidth([[UIScreen mainScreen] bounds]) - _edgeTolerance;
self->touchPointSpawnedAtUpperScreenEdge = false;
_mouseButtonForCursorMove = BUTTON_LEFT;
return self;
}
- (void)onLongPressStart:(NSTimer*)timer {
// Raise the left click and start a right click
if([self touchDidntMoveOnScreen:movingTouchLocation]){
if(_delayMouseLeftClick) LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
if(_delayMouseLeftClick){
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
if(_mouseButtonForCursorMove!=BUTTON_LEFT) LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, _mouseButtonForCursorMove);
}
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
dispatch_time_t delayShort = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC));
dispatch_after(delayShort, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@@ -93,24 +103,28 @@
touchPointSpawnedAtUpperScreenEdge = false; // reset this flag immediately if we get a touch event passing the check above, this fixes irresponsive touch after closing the command tool menu.
// Ignore touch down events with more than one finger
/*
if ([[event allTouches] count] > 1) {
return;
}
}*/
UITouch* touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:streamView];
capturedTouch = [touches anyObject];
CGPoint touchLocation = [capturedTouch locationInView:streamView];
touchBeganTimeStamp = touch.timestamp;
touchBeganTimeStamp = capturedTouch.timestamp;
// Don't reposition for finger down events within the deadzone. This makes double-clicking easier.
if (touch.timestamp - lastTouchUp.timestamp > DOUBLE_TAP_DEAD_ZONE_DELAY ||
if (capturedTouch.timestamp - lastTouchUp.timestamp > DOUBLE_TAP_DEAD_ZONE_DELAY ||
sqrt(pow((touchLocation.x / streamView.bounds.size.width) - (lastTouchUpLocation.x / streamView.bounds.size.width), 2) +
pow((touchLocation.y / streamView.bounds.size.height) - (lastTouchUpLocation.y / streamView.bounds.size.height), 2)) > DOUBLE_TAP_DEAD_ZONE_DELTA) {
[streamView updateCursorLocation:touchLocation isMouse:NO];
}
// Press the left button down
if(!_delayMouseLeftClick) LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
if(!_delayMouseLeftClick){
// _delayMouseLeftClick will always be true.
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); //deprecated
}
// Start the long press timer
longPressTimer = [NSTimer scheduledTimerWithTimeInterval:LONG_PRESS_ACTIVATION_DELAY
@@ -119,23 +133,35 @@
userInfo:nil
repeats:NO];
lastTouchDown = touch;
lastTouchDown = capturedTouch;
lastTouchDownLocation = touchLocation;
movingTouchLocation = touchLocation;
touchBeganLocation = touchLocation;
}
- (void)pauseLeftButtonDrag{
if(dragButtonDown){
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC));
dispatch_after(delay, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, self->_mouseButtonForCursorMove);
});
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if(touchPointSpawnedAtUpperScreenEdge) return; // we're done here. this touch event will not be sent to the remote PC.
// Ignore touch move events with more than one finger
/*
if ([[event allTouches] count] > 1) {
return;
}
}*/
UITouch* touch = [touches anyObject];
movingTouchLocation = [touch locationInView:streamView];
if(![touches containsObject:capturedTouch]) return;
movingTouchLocation = [capturedTouch locationInView:streamView];
if (sqrt(pow((movingTouchLocation.x / streamView.bounds.size.width) - (lastTouchDownLocation.x / streamView.bounds.size.width), 2) +
pow((movingTouchLocation.y / streamView.bounds.size.height) - (lastTouchDownLocation.y / streamView.bounds.size.height), 2)) > LONG_PRESS_ACTIVATION_DELTA) {
@@ -143,11 +169,13 @@
[longPressTimer invalidate];
longPressTimer = nil;
if(_delayMouseLeftClick && (CACurrentMediaTime()-touchBeganTimeStamp>leftClickTimeThreshold)) LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
if(_delayMouseLeftClick && (CACurrentMediaTime()-touchBeganTimeStamp>leftClickTimeThreshold) && !dragButtonDown){
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, _mouseButtonForCursorMove);
dragButtonDown = true;
}
}
if(!rightButtonClicked) [streamView updateCursorLocation:[[touches anyObject] locationInView:streamView] isMouse:NO];
if(!rightButtonClicked) [streamView updateCursorLocation:movingTouchLocation isMouse:NO];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
@@ -155,36 +183,39 @@
if(touchPointSpawnedAtUpperScreenEdge) return; // we're done here. this touch event will not be sent to the remote PC.
// Only fire this logic if all touches have ended
if ([[event allTouches] count] == [touches count]) {
if ([touches containsObject:capturedTouch]) {
// Cancel the long press timer
[longPressTimer invalidate];
longPressTimer = nil;
// Remember this last touch for touch-down deadzoning
UITouch* touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:streamView];
CGPoint touchEndLocation = [capturedTouch locationInView:streamView];
if(_delayMouseLeftClick){
if(CACurrentMediaTime()-touchBeganTimeStamp<leftClickTimeThreshold) {
if(CACurrentMediaTime()-lastTouchUp.timestamp<0.15
&& ![self isAdjacentPoints:touchLocation from:lastTouchUpLocation tolerance:30]) [streamView updateCursorLocation:touchLocation isMouse:NO];
if([self touchDidntMoveOnScreen:touchLocation] && !rightButtonClicked) [self sendShortMouseLeftButtonClickEvent];
&& ![self isAdjacentPoints:touchEndLocation from:lastTouchUpLocation tolerance:30]) [streamView updateCursorLocation:touchEndLocation isMouse:NO];
if([self touchDidntMoveOnScreen:touchEndLocation] && !rightButtonClicked) [self sendShortMouseLeftButtonClickEvent];
}
else if(!rightButtonClicked){
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
if(_mouseButtonForCursorMove!=BUTTON_LEFT) LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, _mouseButtonForCursorMove);
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
}
else{
else{ // deprecated
/*
// Left button up on finger up
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
// Raise right button too in case we triggered a long press gesture
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT); */
}
lastTouchUp = [touches anyObject];
lastTouchUpLocation = [lastTouchUp locationInView:streamView];
dragButtonDown = false;
}
}
+1 -1
View File
@@ -122,7 +122,7 @@ import UIKit
@objc public static let nonVectorStickPads: [String] = ["LSPAD", "RSPAD"]
@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"]
@objc public static let functionalButtonCmds: [String] = ["SETTINGS", "TOOLBOX", "WIDGETTOOL", "WIDGETPROFILES", "PROFILES", "SOFTKEYBOARD", "ABSTCHDRAG"]
@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"]
+19 -1
View File
@@ -33,6 +33,7 @@ import UIKit
func openWidgetLayoutTool()
func switchWidgetProfile()
func bringUpSoftKeyboard()
func alterAbsTouchDragWith(mouseButton:Int32)
}
@objc enum WidgetTypeEnum: UInt8 {
@@ -1142,6 +1143,9 @@ import UIKit
}
private func handleButtonDown() {
if !OnScreenWidgetView.editMode, !self.functionalButtonString.isEmpty {self.handleFunctionalButtonDown()}
if !OnScreenWidgetView.editMode {self.sendComboButtonsDownEvent(comboStrings: self.comboButtonStrings)}
if !OnScreenWidgetView.editMode, !self.motionControlButtonString.isEmpty {self.handleMotionControlButtonDown()}
@@ -1351,7 +1355,7 @@ import UIKit
if CommandManager.keyboardButtonMappings.keys.contains(comboString) {
LiSendKeyboardEvent(CommandManager.keyboardButtonMappings[comboString]!,Int8(KEY_ACTION_DOWN), 0)
}
if CommandManager.mouseButtonMappings.keys.contains(comboString) {
if CommandManager.mouseButtonMappings.keys.contains(comboString), self.functionalButtonString != "ABSTCHDRAG" {
LiSendMouseButtonEvent(CChar(BUTTON_ACTION_PRESS), Int32(CommandManager.mouseButtonMappings[comboString]!))
}
if comboString != comboStrings.last {
@@ -1865,6 +1869,17 @@ import UIKit
}
}
private func handleFunctionalButtonDown(){
switch self.functionalButtonString {
case "ABSTCHDRAG":
let mouseButton = CommandManager.mouseButtonMappings[Set(self.comboButtonStrings).intersection(CommandManager.mouseButtonMappings.keys).first ?? "MLEFT"] ?? BUTTON_LEFT
print("mouseButton \(mouseButton)");
self.functionalButtonDelegate?.alterAbsTouchDragWith(mouseButton:mouseButton)
default:
break
}
}
private func handleFunctionalButtonUp(){
let longPressed = CACurrentMediaTime() - self.touchTapTimeStamp > 0.3
if longPressed, buttonMode == ButtonMode.movable.rawValue {return}
@@ -1879,6 +1894,9 @@ import UIKit
self.functionalButtonDelegate?.switchWidgetProfile()
case "SOFTKEYBOARD":
self.functionalButtonDelegate?.bringUpSoftKeyboard()
case "ABSTCHDRAG":
// self.functionalButtonDelegate?.alterAbsTouchDragWith(mouseButton:CommandManager.mouseButtonMappings[self.comboButtonStrings.first ?? "MLEFT"] ?? BUTTON_LEFT)
self.functionalButtonDelegate?.alterAbsTouchDragWith(mouseButton:BUTTON_LEFT)
default:
break
}
+4 -1
View File
@@ -44,6 +44,7 @@
config:(StreamConfiguration*)streamConfig
streamFrameTopLayerView:(UIView* )topLayerView
;
- (void) showOnScreenControls;
- (void) setOnScreenControls;
- (void) disableOnScreenControls;
@@ -61,11 +62,13 @@
- (OnScreenControlsLevel) getCurrentOscState;
-(void)readyToBringUpSoftKeyboardByToolbox;
- (void)readyToBringUpSoftKeyboardByToolbox;
- (void)keyboardWillShow:(NSNotification *)notification;
- (void)keyboardWillHide;
- (void)liftMetalVideoViewIfNeeded:(CGFloat)liftHeight;
- (void)alterAbsTouchDragWith:(int32_t)mouseButton;
#if !TARGET_OS_TV
- (void) updateCursorLocation:(CGPoint)location isMouse:(BOOL)isMouse;
#endif
+9
View File
@@ -1381,6 +1381,15 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
LiSendScrollEvent(deltaZ);
}
- (void)alterAbsTouchDragWith:(int32_t)mouseButton{
if([touchHandler isKindOfClass:[AbsoluteTouchHandler class]]){
AbsoluteTouchHandler* handler = (AbsoluteTouchHandler* )touchHandler;
handler.mouseButtonForCursorMove = mouseButton;
[handler pauseLeftButtonDrag];
}
else return;
}
#if !TARGET_OS_TV
- (BOOL)isMultipleTouchEnabled {
@@ -19,7 +19,6 @@
#import "DataManager.h"
#import "PaddedLabel.h"
#import "ImGuiRenderer.h"
#import "RelativeTouchHandler.h"
#import "MetalVideoRenderer.h"
#import "CustomEdgeSlideGestureRecognizer.h"
#import "CustomTapGestureRecognizer.h"
@@ -310,6 +309,11 @@
}
- (void)handleAbsTouchPanGesture:(UIPanGestureRecognizer* )gesture{
NSLog(@"handleAbsTouchPanGesture %f", CACurrentMediaTime());
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
}
- (void)configZoomGestureAndAddStreamView{
if (_settings.touchMode.intValue == AbsoluteTouch) {
if(!_scrollView) _scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];
@@ -317,6 +321,7 @@
[_scrollView.panGestureRecognizer setMinimumNumberOfTouches:2];
[_scrollView.panGestureRecognizer setMaximumNumberOfTouches:2]; // reduce competing with keyboardToggleRecognizer in StreamView.
#endif
[_scrollView.panGestureRecognizer addTarget:self action:@selector(handleAbsTouchPanGesture:)];
[_scrollView setShowsHorizontalScrollIndicator:NO];
[_scrollView setShowsVerticalScrollIndicator:NO];
[_scrollView setDelegate:self];
@@ -775,6 +780,10 @@
[self.pipController startPictureInPicture];
}
- (void)alterAbsTouchDragWithMouseButton:(int32_t)mouseButton{
[_streamView alterAbsTouchDragWith:mouseButton];
}
- (void)oscLayoutClosed{
// Handle the callback
_streamView.widgetToolOpened = false;