From 11530ef1806b5fd396968430f94a4b986eba4237 Mon Sep 17 00:00:00 2001 From: bobrosoft Date: Thu, 1 Aug 2019 12:25:59 +0200 Subject: [PATCH] CustomButtonTouchBarItem: recognise longPress in more expected manner without long wait and requirement to release the button --- MTMR/CustomButtonTouchBarItem.swift | 69 +++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/MTMR/CustomButtonTouchBarItem.swift b/MTMR/CustomButtonTouchBarItem.swift index a61a508..d218451 100644 --- a/MTMR/CustomButtonTouchBarItem.swift +++ b/MTMR/CustomButtonTouchBarItem.swift @@ -10,11 +10,15 @@ import Cocoa class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate { var tapClosure: (() -> Void)? - var longTapClosure: (() -> Void)? + var longTapClosure: (() -> Void)? { + didSet { + longClick.isEnabled = longTapClosure != nil + } + } private var button: NSButton! private var singleClick: HapticClickGestureRecognizer! - private var longClick: NSPressGestureRecognizer! + private var longClick: LongPressGestureRecognizer! init(identifier: NSTouchBarItem.Identifier, title: String) { attributedTitle = title.defaultTouchbarAttributedString @@ -22,7 +26,8 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat super.init(identifier: identifier) button = CustomHeightButton(title: title, target: nil, action: nil) - longClick = NSPressGestureRecognizer(target: self, action: #selector(handleGestureLong)) + longClick = LongPressGestureRecognizer(target: self, action: #selector(handleGestureLong)) + longClick.isEnabled = false longClick.allowedTouchTypes = .direct longClick.delegate = self @@ -97,7 +102,9 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat } func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: NSGestureRecognizer) -> Bool { - if gestureRecognizer == singleClick && otherGestureRecognizer == longClick { + if gestureRecognizer == singleClick && otherGestureRecognizer == longClick + || gestureRecognizer == longClick && otherGestureRecognizer == singleClick // need it + { return false } return true @@ -115,15 +122,8 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem, NSGestureRecognizerDelegat @objc func handleGestureLong(gr: NSPressGestureRecognizer) { switch gr.state { - case .began: - if let closure = self.longTapClosure { - HapticFeedback.shared.tap(strong: 2) - closure() - } else if let closure = self.tapClosure { - HapticFeedback.shared.tap(strong: 6) - closure() - print("long click") - } + case .possible: // tiny hack because we're calling action manually + (self.longTapClosure ?? self.tapClosure)?() break default: break @@ -181,6 +181,49 @@ class HapticClickGestureRecognizer: NSClickGestureRecognizer { } } +class LongPressGestureRecognizer: NSPressGestureRecognizer { + private let recognizeTimeout = 0.4 + private var timer: Timer? + + override func touchesBegan(with event: NSEvent) { + timerInvalidate() + + let touches = event.touches(for: self.view!) + if touches.count == 1 { // to prevent it for built-in two/three-finger gestures + timer = Timer.scheduledTimer(withTimeInterval: recognizeTimeout, repeats: false) { _ in + if let target = self.target, let action = self.action { + target.performSelector(inBackground: action, with: self) + HapticFeedback.shared.tap(strong: 6) + } + } + } + + super.touchesBegan(with: event) + } + + override func touchesMoved(with event: NSEvent) { + timerInvalidate() // to prevent it for built-in two/three-finger gestures + super.touchesMoved(with: event) + } + + override func touchesCancelled(with event: NSEvent) { + timerInvalidate() + super.touchesCancelled(with: event) + } + + override func touchesEnded(with event: NSEvent) { + timerInvalidate() + super.touchesEnded(with: event) + } + + private func timerInvalidate() { + if let timer = timer { + timer.invalidate() + self.timer = nil + } + } +} + extension String { var defaultTouchbarAttributedString: NSAttributedString { let attrTitle = NSMutableAttributedString(string: self, attributes: [.foregroundColor: NSColor.white, .font: NSFont.systemFont(ofSize: 15, weight: .regular), .baselineOffset: 1])