diff --git a/HapticKey/Classes/HTKEventTap.h b/HapticKey/Classes/HTKEventTap.h index b4fa6c5..0fce9e6 100644 --- a/HapticKey/Classes/HTKEventTap.h +++ b/HapticKey/Classes/HTKEventTap.h @@ -16,6 +16,9 @@ NS_ASSUME_NONNULL_BEGIN @protocol HTKEventTapDelegate @optional +- (void)eventTap:(HTKEventTap *)eventTap didTapCGEvent:(CGEventRef)eventRef; +// Implement this only when the delegate needs to use `NSEvent` for all tapped event. +// In many cases, using `CGEvent` without creating `NSEvent` may be faster and cheap. - (void)eventTap:(HTKEventTap *)eventTap didTapEvent:(NSEvent *)event; - (void)eventTapDisabled:(HTKEventTap *)eventTap; diff --git a/HapticKey/Classes/HTKEventTap.m b/HapticKey/Classes/HTKEventTap.m index 23baed1..1a6b47d 100644 --- a/HapticKey/Classes/HTKEventTap.m +++ b/HapticKey/Classes/HTKEventTap.m @@ -31,12 +31,18 @@ static CGEventRef EventTapCallback(CGEventTapProxy proxy, CGEventType type, CGE break; } default: { - // `eventWithCGEvent:` returns an autoreleased `NSEvent` that retains given `CGEvent`. - // without `@autoreleasepool`, this will may leak and also `CGEvent` as well. - NSEvent * const event = [NSEvent eventWithCGEvent:eventRef]; - id const delegate = eventTap.delegate; + if ([delegate respondsToSelector:@selector(eventTap:didTapCGEvent:)]) { + [delegate eventTap:eventTap didTapCGEvent:eventRef]; + } + if ([delegate respondsToSelector:@selector(eventTap:didTapEvent:)]) { + // `eventWithCGEvent:` is relatively expensive. + // Do not implement `eventTap:didTapEvent:` if it's not needed. + // NOTE: `eventWithCGEvent:` returns an autoreleased `NSEvent` that retains given `CGEvent`. + // without `@autoreleasepool`, this will may leak and also `CGEvent` as well. + NSEvent * const event = [NSEvent eventWithCGEvent:eventRef]; + [delegate eventTap:eventTap didTapEvent:event]; } break; diff --git a/HapticKey/Classes/HTKFunctionKeyEventListener.m b/HapticKey/Classes/HTKFunctionKeyEventListener.m index 8a3b379..c6fad91 100644 --- a/HapticKey/Classes/HTKFunctionKeyEventListener.m +++ b/HapticKey/Classes/HTKFunctionKeyEventListener.m @@ -54,13 +54,18 @@ - (BOOL)isEnabled // MARK: - HTKEventTapDelegate -- (void)eventTap:(HTKEventTap *)eventTap didTapEvent:(NSEvent *)event +- (void)eventTap:(HTKEventTap *)eventTap didTapCGEvent:(CGEventRef)eventRef { - const int64_t keyboardType = CGEventGetIntegerValueField(event.CGEvent, kCGKeyboardEventKeyboardType); - if (keyboardType == kTouchbarKeyboardType && !event.ARepeat) { + const CGEventType eventType = CGEventGetType(eventRef); + + const int64_t keyboardType = CGEventGetIntegerValueField(eventRef, kCGKeyboardEventKeyboardType); + const int64_t autorepeat = CGEventGetIntegerValueField(eventRef, kCGKeyboardEventAutorepeat); + const int64_t keycode = CGEventGetIntegerValueField(eventRef, kCGKeyboardEventKeycode); + + if (keyboardType == kTouchbarKeyboardType && autorepeat == 0) { for (NSUInteger index = 0; index < kNumberOfEscAndFunctionKeycodes; index += 1) { - if (kEscAndFunctionKeycodes[index] == event.keyCode) { - switch (event.type) { + if (kEscAndFunctionKeycodes[index] == keycode) { + switch (eventType) { case NSEventTypeKeyDown: [self _htk_main_didListenEvent:[[HTKEvent alloc] initWithPhase:HTKEventPhaseBegin]]; break; diff --git a/HapticKey/Classes/HTKTapGestureEventListener.m b/HapticKey/Classes/HTKTapGestureEventListener.m index 696d0a7..3f4a97c 100644 --- a/HapticKey/Classes/HTKTapGestureEventListener.m +++ b/HapticKey/Classes/HTKTapGestureEventListener.m @@ -12,9 +12,12 @@ #import "NSTouchDevice.h" @import AppKit; +@import IOKit; NS_ASSUME_NONNULL_BEGIN +static const uint32_t kCGEventFieldTouchContextID = 0x92; + @interface HTKTapGestureEventListener () @property (nonatomic, readonly) HTKEventTap *eventTap; @@ -47,20 +50,26 @@ - (BOOL)isEnabled // MARK: - HTKEventTapDelegate -- (void)eventTap:(HTKEventTap *)eventTap didTapEvent:(NSEvent *)event +- (void)eventTap:(HTKEventTap *)eventTap didTapCGEvent:(CGEventRef)eventRef { - for (NSTouch * const touch in [event allTouches]) { - NSTouchDevice * const touchDevice = touch.device; - if (!touch.resting && touchDevice.deviceType == NSTouchDeviceTypeTouchBar) { - switch (touch.phase) { - case NSTouchPhaseBegan: - [self _htk_main_didListenEvent:[[HTKEvent alloc] initWithPhase:HTKEventPhaseBegin]]; - return; - case NSTouchPhaseEnded: - [self _htk_main_didListenEvent:[[HTKEvent alloc] initWithPhase:HTKEventPhaseEnd]]; - return; - default: - break; + // `eventWithCGEvent:` is relatively expensive. + // Check touch contextID exists or not first. All touches on TouchBar has this ID. + const int64_t contextID = CGEventGetIntegerValueField(eventRef, kCGEventFieldTouchContextID); + if (contextID != 0) { + NSEvent * const event = [NSEvent eventWithCGEvent:eventRef]; + for (NSTouch * const touch in [event allTouches]) { + NSTouchDevice * const touchDevice = touch.device; + if (!touch.resting && touchDevice.deviceType == NSTouchDeviceTypeTouchBar) { + switch (touch.phase) { + case NSTouchPhaseBegan: + [self _htk_main_didListenEvent:[[HTKEvent alloc] initWithPhase:HTKEventPhaseBegin]]; + return; + case NSTouchPhaseEnded: + [self _htk_main_didListenEvent:[[HTKEvent alloc] initWithPhase:HTKEventPhaseEnd]]; + return; + default: + break; + } } } }