| | |
| | | static volatile double g_lastDownAt[128]; |
| | | static volatile int g_monitorStarted = 0; |
| | | static volatile int g_monitorLaunching = 0; |
| | | static volatile int g_monitorStopping = 0; |
| | | static CFMachPortRef g_eventTap = NULL; |
| | | static CFRunLoopSourceRef g_eventTapSource = NULL; |
| | | static CFRunLoopRef g_eventTapRunLoop = NULL; |
| | | static volatile unsigned long long g_monitorStartAttempts = 0; |
| | | static volatile unsigned long long g_eventTapCreateFailures = 0; |
| | | static volatile unsigned long long g_eventTapDisabledCount = 0; |
| | |
| | | CGEventTapEnable(g_eventTap, true); |
| | | g_monitorStarted = 1; |
| | | g_monitorLaunching = 0; |
| | | g_eventTapRunLoop = CFRunLoopGetCurrent(); |
| | | if (g_eventTapRunLoop != NULL) CFRetain(g_eventTapRunLoop); |
| | | CFRunLoopRun(); |
| | | |
| | | if (g_eventTap != NULL) CGEventTapEnable(g_eventTap, false); |
| | | if (g_eventTapSource != NULL) { |
| | | CFRunLoopRemoveSource(CFRunLoopGetCurrent(), g_eventTapSource, kCFRunLoopCommonModes); |
| | | CFRelease(g_eventTapSource); |
| | | g_eventTapSource = NULL; |
| | | } |
| | | if (g_eventTap != NULL) { |
| | | CFRelease(g_eventTap); |
| | | g_eventTap = NULL; |
| | | } |
| | | if (g_eventTapRunLoop != NULL) { |
| | | CFRelease(g_eventTapRunLoop); |
| | | g_eventTapRunLoop = NULL; |
| | | } |
| | | g_monitorStarted = 0; |
| | | g_monitorStopping = 0; |
| | | } |
| | | |
| | | static int ensureAccessibility(void) { |
| | |
| | | reason:@"PrivateVoice Dictation global hotkey listener"]; |
| | | } |
| | | |
| | | static void endHotkeyActivity(void) { |
| | | if (g_activityToken == nil) return; |
| | | [[NSProcessInfo processInfo] endActivity:g_activityToken]; |
| | | g_activityToken = nil; |
| | | } |
| | | |
| | | static void* eventTapThreadMain(void* arg) { |
| | | (void)arg; |
| | | @autoreleasepool { |
| | |
| | | } |
| | | |
| | | static void startKeyMonitor(void) { |
| | | if (g_monitorStarted || g_monitorLaunching) return; |
| | | if (g_monitorStarted || g_monitorLaunching || g_monitorStopping) return; |
| | | g_monitorLaunching = 1; |
| | | pthread_t thread; |
| | | int err = pthread_create(&thread, NULL, eventTapThreadMain, NULL); |
| | |
| | | return; |
| | | } |
| | | pthread_detach(thread); |
| | | } |
| | | |
| | | static void stopKeyMonitor(void) { |
| | | g_monitorStopping = 1; |
| | | if (g_eventTap != NULL) CGEventTapEnable(g_eventTap, false); |
| | | if (g_eventTapRunLoop != NULL) { |
| | | CFRunLoopStop(g_eventTapRunLoop); |
| | | } |
| | | endHotkeyActivity(); |
| | | } |
| | | |
| | | // isModifierDown polls the current system modifier flags via CGEventSource. |
| | |
| | | return false |
| | | } |
| | | |
| | | func (l *darwinListener) Close() { |
| | | C.stopKeyMonitor() |
| | | } |
| | | |
| | | func (l *darwinListener) wasPressedSince(vk int, since time.Time) bool { |
| | | if since.IsZero() { |
| | | return l.IsKeyDown(vk) |