@@ -23,6 +23,13 @@ class ParsecViewController: UIViewController, UIScrollViewDelegate {
2323 var lastLongPressPoint : CGPoint = CGPoint ( )
2424 var accumulatedDeltaX : Float = 0.0
2525 var accumulatedDeltaY : Float = 0.0
26+ var accumulatedWheelY : Float = 0.0
27+ let directScrollDivisor : Float = 3.0
28+ let directLongPressDragThreshold : CGFloat = 8.0
29+ var directLongPressActive = false
30+ var directLongPressStartPoint : CGPoint = . zero
31+ var directLongPressDidMove = false
32+ var directLongPressDragging = false
2633 var lastPanLocation : CGPoint = . zero
2734 var lastPanTranslation : CGPoint = . zero
2835
@@ -468,16 +475,8 @@ extension ParsecViewController: UIGestureRecognizerDelegate {
468475 // lock activatedPanFingerNumber in case user not releasing both finger at the same time
469476 if gestureRecognizer. numberOfTouches == 0 {
470477 if gestureRecognizer. state == . ended || gestureRecognizer. state == . cancelled {
471- activatedPanFingerNumber = 0
472- // Reset accumulators
473- accumulatedDeltaX = 0.0
474- accumulatedDeltaY = 0.0
475- lastPanTranslation = . zero
476-
477- if SettingsHandler . cursorMode == . direct {
478- let button = ParsecMouseButton . init ( rawValue: 1 )
479- CParsec . sendMouseClickMessage ( button, false )
480- }
478+ resetPanTracking ( )
479+ releaseDirectDragIfNeeded ( )
481480 }
482481 } else if activatedPanFingerNumber == 2 || ( gestureRecognizer. numberOfTouches == 2 && activatedPanFingerNumber == 0 ) {
483482 // Native UIScrollView handles 2-finger pan for scrolling.
@@ -500,52 +499,105 @@ extension ParsecViewController: UIGestureRecognizerDelegate {
500499 }
501500 } else if activatedPanFingerNumber == 1 || ( gestureRecognizer. numberOfTouches == 1 && activatedPanFingerNumber == 0 ) {
502501 activatedPanFingerNumber = 1
503- // move mouse
504502 if SettingsHandler . cursorMode == . direct {
505- // Map screen tap to content coordinates
506- let position = gestureRecognizer . location ( in : gestureRecognizer. view )
507- // Convert to content coordinates
508- let adjustedPosition = contentView . convert ( position , from : view )
509- CParsec . sendMousePosition ( Int32 ( adjustedPosition . x ) , Int32 ( adjustedPosition . y ) )
503+ if SettingsHandler . directDragMode == . scroll {
504+ handleDirectPanAsScroll ( gestureRecognizer)
505+ } else {
506+ handleDirectPanAsDrag ( gestureRecognizer )
507+ }
510508 } else {
511- // Simple translation-based movement with sub-pixel accumulation
512- let currentTranslation = gestureRecognizer . translation ( in : gestureRecognizer . view )
509+ handleTouchpadPan ( gestureRecognizer )
510+ }
513511
514- if gestureRecognizer. state == . began {
515- lastPanTranslation = . zero
516- accumulatedDeltaX = 0.0
517- accumulatedDeltaY = 0.0
518- }
512+ }
513+ }
519514
520- // Calculate delta since last update
521- let deltaX = Float ( currentTranslation. x - lastPanTranslation. x) * mouseSensitivity
522- let deltaY = Float ( currentTranslation. y - lastPanTranslation. y) * mouseSensitivity
515+ func resetPanTracking( ) {
516+ activatedPanFingerNumber = 0
517+ accumulatedDeltaX = 0.0
518+ accumulatedDeltaY = 0.0
519+ accumulatedWheelY = 0.0
520+ lastPanTranslation = . zero
521+ }
523522
524- lastPanTranslation = currentTranslation
523+ func releaseDirectDragIfNeeded( ) {
524+ guard SettingsHandler . cursorMode == . direct else { return }
525+ if SettingsHandler . directDragMode == . drag || directLongPressDragging {
526+ let button = ParsecMouseButton . init ( rawValue: 1 )
527+ CParsec . sendMouseClickMessage ( button, false )
528+ directLongPressDragging = false
529+ }
530+ }
525531
526- // Accumulate for sub-pixel precision
527- accumulatedDeltaX += deltaX
528- accumulatedDeltaY += deltaY
532+ func handleDirectPanAsDrag( _ gestureRecognizer: UIPanGestureRecognizer ) {
533+ moveDirectMouse ( to: gestureRecognizer. location ( in: gestureRecognizer. view) )
529534
530- // Send movement when we have at least 1 pixel
531- let intDeltaX = Int32 ( accumulatedDeltaX)
532- let intDeltaY = Int32 ( accumulatedDeltaY)
535+ if gestureRecognizer. state == . began {
536+ let button = ParsecMouseButton . init ( rawValue: 1 )
537+ CParsec . sendMouseClickMessage ( button, true )
538+ }
539+ }
533540
534- if intDeltaX != 0 || intDeltaY != 0 {
535- CParsec . sendMouseDelta ( intDeltaX, intDeltaY)
536- accumulatedDeltaX -= Float ( intDeltaX)
537- accumulatedDeltaY -= Float ( intDeltaY)
538- }
539- }
541+ func handleDirectPanAsScroll( _ gestureRecognizer: UIPanGestureRecognizer ) {
542+ if directLongPressActive || directLongPressDragging {
543+ return
544+ }
540545
541- if gestureRecognizer. state == . began && SettingsHandler . cursorMode == . direct {
542- let button = ParsecMouseButton . init ( rawValue: 1 )
543- CParsec . sendMouseClickMessage ( button, true )
544- }
546+ if gestureRecognizer. state == . began {
547+ moveDirectMouse ( to: gestureRecognizer. location ( in: gestureRecognizer. view) )
548+ lastPanTranslation = . zero
549+ accumulatedWheelY = 0.0
550+ }
551+
552+ let currentTranslation = gestureRecognizer. translation ( in: gestureRecognizer. view)
553+ let deltaY = Float ( currentTranslation. y - lastPanTranslation. y) * mouseSensitivity
554+ lastPanTranslation = currentTranslation
555+
556+ accumulatedWheelY += deltaY / directScrollDivisor
557+ let wheelY = Int32 ( accumulatedWheelY)
558+
559+ if wheelY != 0 {
560+ CParsec . sendWheelMsg ( x: 0 , y: wheelY)
561+ accumulatedWheelY -= Float ( wheelY)
562+ }
563+ }
564+
565+ func handleTouchpadPan( _ gestureRecognizer: UIPanGestureRecognizer ) {
566+ // Simple translation-based movement with sub-pixel accumulation
567+ let currentTranslation = gestureRecognizer. translation ( in: gestureRecognizer. view)
568+
569+ if gestureRecognizer. state == . began {
570+ lastPanTranslation = . zero
571+ accumulatedDeltaX = 0.0
572+ accumulatedDeltaY = 0.0
573+ }
574+
575+ // Calculate delta since last update
576+ let deltaX = Float ( currentTranslation. x - lastPanTranslation. x) * mouseSensitivity
577+ let deltaY = Float ( currentTranslation. y - lastPanTranslation. y) * mouseSensitivity
578+
579+ lastPanTranslation = currentTranslation
545580
581+ // Accumulate for sub-pixel precision
582+ accumulatedDeltaX += deltaX
583+ accumulatedDeltaY += deltaY
584+
585+ // Send movement when we have at least 1 pixel
586+ let intDeltaX = Int32 ( accumulatedDeltaX)
587+ let intDeltaY = Int32 ( accumulatedDeltaY)
588+
589+ if intDeltaX != 0 || intDeltaY != 0 {
590+ CParsec . sendMouseDelta ( intDeltaX, intDeltaY)
591+ accumulatedDeltaX -= Float ( intDeltaX)
592+ accumulatedDeltaY -= Float ( intDeltaY)
546593 }
547594 }
548595
596+ func moveDirectMouse( to position: CGPoint ) {
597+ let adjustedPosition = contentView. convert ( position, from: view)
598+ CParsec . sendMousePosition ( Int32 ( adjustedPosition. x) , Int32 ( adjustedPosition. y) )
599+ }
600+
549601 @objc func handleSingleFingerTap( _ gestureRecognizer: UITapGestureRecognizer ) {
550602
551603 let location = gestureRecognizer. location ( in: gestureRecognizer. view)
@@ -574,6 +626,11 @@ extension ParsecViewController: UIGestureRecognizerDelegate {
574626 }
575627
576628 @objc func handleLongPress( _ gestureRecognizer: UIGestureRecognizer ) {
629+ if SettingsHandler . cursorMode == . direct && SettingsHandler . directDragMode == . scroll {
630+ handleDirectLongPressDrag ( gestureRecognizer)
631+ return
632+ }
633+
577634 if SettingsHandler . cursorMode != . touchpad {
578635 return
579636 }
@@ -596,6 +653,49 @@ extension ParsecViewController: UIGestureRecognizerDelegate {
596653 }
597654 }
598655
656+ func handleDirectLongPressDrag( _ gestureRecognizer: UIGestureRecognizer ) {
657+ let button = ParsecMouseButton . init ( rawValue: 1 )
658+ let location = gestureRecognizer. location ( in: gestureRecognizer. view)
659+
660+ if gestureRecognizer. state == . began {
661+ directLongPressActive = true
662+ directLongPressStartPoint = location
663+ directLongPressDidMove = false
664+ directLongPressDragging = false
665+ moveDirectMouse ( to: location)
666+ } else if gestureRecognizer. state == . changed {
667+ let deltaX = location. x - directLongPressStartPoint. x
668+ let deltaY = location. y - directLongPressStartPoint. y
669+ let distance = hypot ( deltaX, deltaY)
670+
671+ if !directLongPressDragging && distance >= directLongPressDragThreshold {
672+ directLongPressDidMove = true
673+ directLongPressDragging = true
674+ moveDirectMouse ( to: directLongPressStartPoint)
675+ CParsec . sendMouseClickMessage ( button, true )
676+ }
677+
678+ if directLongPressDragging {
679+ moveDirectMouse ( to: location)
680+ }
681+ } else if gestureRecognizer. state == . ended || gestureRecognizer. state == . cancelled || gestureRecognizer. state == . failed {
682+ if directLongPressDragging {
683+ CParsec . sendMouseClickMessage ( button, false )
684+ } else if gestureRecognizer. state == . ended && !directLongPressDidMove {
685+ handleDirectLongPressRightClick ( at: location)
686+ }
687+
688+ directLongPressActive = false
689+ directLongPressDragging = false
690+ directLongPressDidMove = false
691+ }
692+ }
693+
694+ func handleDirectLongPressRightClick( at location: CGPoint ) {
695+ let adjustedLocation = contentView. convert ( location, from: view)
696+ touchController. onTap ( typeOfTap: 3 , location: adjustedLocation)
697+ }
698+
599699 // UIScrollViewDelegate
600700 func viewForZooming( in scrollView: UIScrollView ) -> UIView ? {
601701 return contentView
0 commit comments