diff --git a/Sources/OpenKey/macOS/ModernKey/OpenKey.mm b/Sources/OpenKey/macOS/ModernKey/OpenKey.mm index 4292db2d..23ad879d 100644 --- a/Sources/OpenKey/macOS/ModernKey/OpenKey.mm +++ b/Sources/OpenKey/macOS/ModernKey/OpenKey.mm @@ -3,7 +3,7 @@ // OpenKey // // Created by Tuyen on 1/18/19. -// Copyright © 2019 Tuyen Mai. All rights reserved. +// Copyright 2019 Tuyen Mai. All rights reserved. // #import #import @@ -52,6 +52,11 @@ NSArray* _niceSpaceApp = @[@"com.sublimetext.3", @"com.sublimetext.2", ]; + + // Array of bundle IDs for apps that should be ignored + static NSArray* const IGNORED_BUNDLES = @[ + @"com.apple.Spotlight" // Spotlight search + ]; //app which error with unicode Compound NSArray* _unicodeCompoundApp = @[@"com.apple.", @@ -85,6 +90,21 @@ NSString* _frontMostApp = @"UnknownApp"; + static NSString *lastFocusedAppBundleId = nil; + static pid_t lastFocusedAppPid = -1; + static bool _willUpdateFocusedApp = false; + + // Global AX variables + static AXUIElementRef g_systemWide = NULL; + + // Cleanup function for AX variables + static void cleanupAXVariables() { + if (g_systemWide) { + CFRelease(g_systemWide); + g_systemWide = NULL; + } + } + void OpenKeyInit() { //load saved data vFreeMark = 0;//(int)[[NSUserDefaults standardUserDefaults] integerForKey:@"FreeMark"]; @@ -143,6 +163,11 @@ void OpenKeyInit() { } } + void OpenKeyCleanup() { + cleanupAXVariables(); + // ... other cleanup code ... + } + void RequestNewSession() { //send event signal to Engine vKeyHandleEvent(vKeyEvent::Mouse, vKeyEventState::MouseDown, 0); @@ -182,6 +207,7 @@ void saveSmartSwitchKeyData() { } void OnActiveAppChanged() { //use for smart switch key; improved on Sep 28th, 2019 + _willUpdateFocusedApp = true; queryFrontMostApp(); _languageTemp = getAppInputMethodStatus(string(_frontMostApp.UTF8String), vLanguage | (vCodeTable << 1)); if ((_languageTemp & 0x01) != vLanguage) { //for input method @@ -230,12 +256,14 @@ void InsertKeyLength(const Uint8& len) { void SendPureCharacter(const Uint16& ch) { _newEventDown = CGEventCreateKeyboardEvent(myEventSource, 0, true); _newEventUp = CGEventCreateKeyboardEvent(myEventSource, 0, false); - CGEventKeyboardSetUnicodeString(_newEventDown, 1, &ch); - CGEventKeyboardSetUnicodeString(_newEventUp, 1, &ch); - CGEventTapPostEvent(_proxy, _newEventDown); - CGEventTapPostEvent(_proxy, _newEventUp); - CFRelease(_newEventDown); - CFRelease(_newEventUp); + if (_newEventDown && _newEventUp) { + CGEventKeyboardSetUnicodeString(_newEventDown, 1, &ch); + CGEventKeyboardSetUnicodeString(_newEventUp, 1, &ch); + CGEventTapPostEvent(_proxy, _newEventDown); + CGEventTapPostEvent(_proxy, _newEventUp); + } + if (_newEventDown) CFRelease(_newEventDown); + if (_newEventUp) CFRelease(_newEventUp); if (IS_DOUBLE_CODE(vCodeTable)) { InsertKeyLength(1); } @@ -276,21 +304,25 @@ void SendKeyCode(Uint32 data) { _newEventDown = CGEventCreateKeyboardEvent(myEventSource, 0, true); _newEventUp = CGEventCreateKeyboardEvent(myEventSource, 0, false); - CGEventKeyboardSetUnicodeString(_newEventDown, 1, &_newChar); - CGEventKeyboardSetUnicodeString(_newEventUp, 1, &_newChar); - CGEventTapPostEvent(_proxy, _newEventDown); - CGEventTapPostEvent(_proxy, _newEventUp); + if (_newEventDown && _newEventUp) { + CGEventKeyboardSetUnicodeString(_newEventDown, 1, &_newChar); + CGEventKeyboardSetUnicodeString(_newEventUp, 1, &_newChar); + CGEventTapPostEvent(_proxy, _newEventDown); + CGEventTapPostEvent(_proxy, _newEventUp); + } if (_newCharHi > 32) { if (vCodeTable == 2) //VNI InsertKeyLength(2); - CFRelease(_newEventDown); - CFRelease(_newEventUp); + if (_newEventDown) CFRelease(_newEventDown); + if (_newEventUp) CFRelease(_newEventUp); _newEventDown = CGEventCreateKeyboardEvent(myEventSource, 0, true); _newEventUp = CGEventCreateKeyboardEvent(myEventSource, 0, false); - CGEventKeyboardSetUnicodeString(_newEventDown, 1, &_newCharHi); - CGEventKeyboardSetUnicodeString(_newEventUp, 1, &_newCharHi); - CGEventTapPostEvent(_proxy, _newEventDown); - CGEventTapPostEvent(_proxy, _newEventUp); + if (_newEventDown && _newEventUp) { + CGEventKeyboardSetUnicodeString(_newEventDown, 1, &_newCharHi); + CGEventKeyboardSetUnicodeString(_newEventUp, 1, &_newCharHi); + CGEventTapPostEvent(_proxy, _newEventDown); + CGEventTapPostEvent(_proxy, _newEventUp); + } } else { if (vCodeTable == 2) //VNI InsertKeyLength(1); @@ -303,14 +335,16 @@ void SendKeyCode(Uint32 data) { InsertKeyLength(_newCharHi > 0 ? 2 : 1); _newEventDown = CGEventCreateKeyboardEvent(myEventSource, 0, true); _newEventUp = CGEventCreateKeyboardEvent(myEventSource, 0, false); - CGEventKeyboardSetUnicodeString(_newEventDown, (_newCharHi > 0 ? 2 : 1), _uniChar); - CGEventKeyboardSetUnicodeString(_newEventUp, (_newCharHi > 0 ? 2 : 1), _uniChar); - CGEventTapPostEvent(_proxy, _newEventDown); - CGEventTapPostEvent(_proxy, _newEventUp); + if (_newEventDown && _newEventUp) { + CGEventKeyboardSetUnicodeString(_newEventDown, (_newCharHi > 0 ? 2 : 1), _uniChar); + CGEventKeyboardSetUnicodeString(_newEventUp, (_newCharHi > 0 ? 2 : 1), _uniChar); + CGEventTapPostEvent(_proxy, _newEventDown); + CGEventTapPostEvent(_proxy, _newEventUp); + } } } - CFRelease(_newEventDown); - CFRelease(_newEventUp); + if (_newEventDown) CFRelease(_newEventDown); + if (_newEventUp) CFRelease(_newEventUp); } void SendEmptyCharacter() { @@ -324,77 +358,89 @@ void SendEmptyCharacter() { _newEventDown = CGEventCreateKeyboardEvent(myEventSource, 0, true); _newEventUp = CGEventCreateKeyboardEvent(myEventSource, 0, false); - CGEventKeyboardSetUnicodeString(_newEventDown, 1, &_newChar); - CGEventKeyboardSetUnicodeString(_newEventUp, 1, &_newChar); - CGEventTapPostEvent(_proxy, _newEventDown); - CGEventTapPostEvent(_proxy, _newEventUp); - CFRelease(_newEventDown); - CFRelease(_newEventUp); + if (_newEventDown && _newEventUp) { + CGEventKeyboardSetUnicodeString(_newEventDown, 1, &_newChar); + CGEventKeyboardSetUnicodeString(_newEventUp, 1, &_newChar); + CGEventTapPostEvent(_proxy, _newEventDown); + CGEventTapPostEvent(_proxy, _newEventUp); + } + if (_newEventDown) CFRelease(_newEventDown); + if (_newEventUp) CFRelease(_newEventUp); } void SendVirtualKey(const Byte& vKey) { CGEventRef eventVkeyDown = CGEventCreateKeyboardEvent (myEventSource, vKey, true); CGEventRef eventVkeyUp = CGEventCreateKeyboardEvent (myEventSource, vKey, false); - CGEventTapPostEvent(_proxy, eventVkeyDown); - CGEventTapPostEvent(_proxy, eventVkeyUp); + if (eventVkeyDown && eventVkeyUp) { + CGEventTapPostEvent(_proxy, eventVkeyDown); + CGEventTapPostEvent(_proxy, eventVkeyUp); + } - CFRelease(eventVkeyDown); - CFRelease(eventVkeyUp); + if (eventVkeyDown) CFRelease(eventVkeyDown); + if (eventVkeyUp) CFRelease(eventVkeyUp); } void SendBackspace() { - CGEventTapPostEvent(_proxy, eventBackSpaceDown); - CGEventTapPostEvent(_proxy, eventBackSpaceUp); - - if (IS_DOUBLE_CODE(vCodeTable)) { //VNI or Unicode Compound - if (_syncKey.back() > 1) { - if (!(vCodeTable == 3 && containUnicodeCompoundApp(FRONT_APP))) { - CGEventTapPostEvent(_proxy, eventBackSpaceDown); - CGEventTapPostEvent(_proxy, eventBackSpaceUp); + if (eventBackSpaceDown && eventBackSpaceUp) { + CGEventTapPostEvent(_proxy, eventBackSpaceDown); + CGEventTapPostEvent(_proxy, eventBackSpaceUp); + + if (IS_DOUBLE_CODE(vCodeTable)) { //VNI or Unicode Compound + if (_syncKey.back() > 1) { + if (!(vCodeTable == 3 && containUnicodeCompoundApp(FRONT_APP))) { + CGEventTapPostEvent(_proxy, eventBackSpaceDown); + CGEventTapPostEvent(_proxy, eventBackSpaceUp); + } } + _syncKey.pop_back(); } - _syncKey.pop_back(); } } void SendShiftAndLeftArrow() { CGEventRef eventVkeyDown = CGEventCreateKeyboardEvent (myEventSource, KEY_LEFT, true); CGEventRef eventVkeyUp = CGEventCreateKeyboardEvent (myEventSource, KEY_LEFT, false); - _privateFlag = CGEventGetFlags(eventVkeyDown); - _privateFlag |= kCGEventFlagMaskShift; - CGEventSetFlags(eventVkeyDown, _privateFlag); - CGEventSetFlags(eventVkeyUp, _privateFlag); - - CGEventTapPostEvent(_proxy, eventVkeyDown); - CGEventTapPostEvent(_proxy, eventVkeyUp); - - if (IS_DOUBLE_CODE(vCodeTable)) { //VNI or Unicode Compound - if (_syncKey.back() > 1) { - if (!(vCodeTable == 3 && containUnicodeCompoundApp(FRONT_APP))) { - CGEventTapPostEvent(_proxy, eventVkeyDown); - CGEventTapPostEvent(_proxy, eventVkeyUp); + + if (eventVkeyDown && eventVkeyUp) { + _privateFlag = CGEventGetFlags(eventVkeyDown); + _privateFlag |= kCGEventFlagMaskShift; + CGEventSetFlags(eventVkeyDown, _privateFlag); + CGEventSetFlags(eventVkeyUp, _privateFlag); + + CGEventTapPostEvent(_proxy, eventVkeyDown); + CGEventTapPostEvent(_proxy, eventVkeyUp); + + if (IS_DOUBLE_CODE(vCodeTable)) { //VNI or Unicode Compound + if (_syncKey.back() > 1) { + if (!(vCodeTable == 3 && containUnicodeCompoundApp(FRONT_APP))) { + CGEventTapPostEvent(_proxy, eventVkeyDown); + CGEventTapPostEvent(_proxy, eventVkeyUp); + } } + _syncKey.pop_back(); } - _syncKey.pop_back(); } - CFRelease(eventVkeyDown); - CFRelease(eventVkeyUp); + if (eventVkeyDown) CFRelease(eventVkeyDown); + if (eventVkeyUp) CFRelease(eventVkeyUp); } void SendCutKey() { CGEventRef eventVkeyDown = CGEventCreateKeyboardEvent (myEventSource, KEY_X, true); CGEventRef eventVkeyUp = CGEventCreateKeyboardEvent (myEventSource, KEY_X, false); - _privateFlag = CGEventGetFlags(eventVkeyDown); - _privateFlag |= NX_COMMANDMASK; - CGEventSetFlags(eventVkeyDown, _privateFlag); - CGEventSetFlags(eventVkeyUp, _privateFlag); - CGEventTapPostEvent(_proxy, eventVkeyDown); - CGEventTapPostEvent(_proxy, eventVkeyUp); + if (eventVkeyDown && eventVkeyUp) { + _privateFlag = CGEventGetFlags(eventVkeyDown); + _privateFlag |= NX_COMMANDMASK; + CGEventSetFlags(eventVkeyDown, _privateFlag); + CGEventSetFlags(eventVkeyUp, _privateFlag); + + CGEventTapPostEvent(_proxy, eventVkeyDown); + CGEventTapPostEvent(_proxy, eventVkeyUp); + } - CFRelease(eventVkeyDown); - CFRelease(eventVkeyUp); + if (eventVkeyDown) CFRelease(eventVkeyDown); + if (eventVkeyUp) CFRelease(eventVkeyUp); } void SendNewCharString(const bool& dataFromMacro=false, const Uint16& offset=0) { @@ -472,12 +518,14 @@ void SendNewCharString(const bool& dataFromMacro=false, const Uint16& offset=0) _newEventDown = CGEventCreateKeyboardEvent(myEventSource, 0, true); _newEventUp = CGEventCreateKeyboardEvent(myEventSource, 0, false); - CGEventKeyboardSetUnicodeString(_newEventDown, _willContinuteSending ? 16 : _newCharSize - offset, _newCharString); - CGEventKeyboardSetUnicodeString(_newEventUp, _willContinuteSending ? 16 : _newCharSize - offset, _newCharString); - CGEventTapPostEvent(_proxy, _newEventDown); - CGEventTapPostEvent(_proxy, _newEventUp); - CFRelease(_newEventDown); - CFRelease(_newEventUp); + if (_newEventDown && _newEventUp) { + CGEventKeyboardSetUnicodeString(_newEventDown, _willContinuteSending ? 16 : _newCharSize - offset, _newCharString); + CGEventKeyboardSetUnicodeString(_newEventUp, _willContinuteSending ? 16 : _newCharSize - offset, _newCharString); + CGEventTapPostEvent(_proxy, _newEventDown); + CGEventTapPostEvent(_proxy, _newEventUp); + } + if (_newEventDown) CFRelease(_newEventDown); + if (_newEventUp) CFRelease(_newEventUp); if (_willContinuteSending) { SendNewCharString(dataFromMacro, dataFromMacro ? _k : 16); @@ -571,10 +619,45 @@ CGKeyCode ConvertEventToKeyboadLayoutCompatKeyCode(CGEventRef keyEvent, CGKeyCod fallbackKeyCode); } + void updateFocusedAppBundleId() { + if (!g_systemWide) { + g_systemWide = AXUIElementCreateSystemWide(); + } + + AXUIElementRef focusedApp = NULL; + AXError result = AXUIElementCopyAttributeValue(g_systemWide, kAXFocusedApplicationAttribute, (CFTypeRef*)&focusedApp); + + if (result == kAXErrorSuccess && focusedApp) { + pid_t pid = 0; + AXUIElementGetPid(focusedApp, &pid); + + // Check if the focused app has changed + if (pid != lastFocusedAppPid) { + NSRunningApplication *app = [NSRunningApplication runningApplicationWithProcessIdentifier:pid]; + lastFocusedAppBundleId = app.bundleIdentifier; + lastFocusedAppPid = pid; + } + + CFRelease(focusedApp); + return; + } else { + // Fallback to NSWorkspace when AX API fails + NSRunningApplication *frontApp = [[NSWorkspace sharedWorkspace] frontmostApplication]; + if (frontApp && frontApp.processIdentifier != lastFocusedAppPid) { + lastFocusedAppBundleId = frontApp.bundleIdentifier; + lastFocusedAppPid = frontApp.processIdentifier; + } + } + + if (focusedApp) { + CFRelease(focusedApp); + } + } + /** * MAIN HOOK entry, very important function. * MAIN Callback. - */ + */ CGEventRef OpenKeyCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { //dont handle my event if (CGEventGetIntegerValueField(event, kCGEventSourceStateID) == CGEventSourceGetSourceStateID(myEventSource)) { @@ -663,6 +746,7 @@ CGEventRef OpenKeyCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef e //handle mouse if (type == kCGEventLeftMouseDown || type == kCGEventRightMouseDown || type == kCGEventLeftMouseDragged || type == kCGEventRightMouseDragged) { + _willUpdateFocusedApp = true; RequestNewSession(); return event; } @@ -677,17 +761,32 @@ CGEventRef OpenKeyCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef e if (CFArrayGetCount(languages) > 0) { CFStringRef langRef = (CFStringRef)CFArrayGetValueAtIndex(languages, 0); NSString *currentLanguage = (__bridge NSString *)langRef; - if(![currentLanguage isLike:@"en"]){ + if(![currentLanguage isLike:@"en"] && ![currentLanguage isLike:@""]){ // empty for "unicode hex input" + CFRelease(isource); return event; } - CFRelease(langRef); - CFRelease(isource); } + CFRelease(isource); } } //handle keyboard if (type == kCGEventKeyDown) { + + //update focused app + if (_willUpdateFocusedApp) { + updateFocusedAppBundleId(); + _willUpdateFocusedApp = false; + } + if (OTHER_CONTROL_KEY) { + _willUpdateFocusedApp = true; + } + + //ignore some apps + if (lastFocusedAppBundleId && [IGNORED_BUNDLES containsObject:lastFocusedAppBundleId]) { + return event; + } + //send event signal to Engine vKeyHandleEvent(vKeyEvent::Keyboard, vKeyEventState::KeyDown, @@ -700,14 +799,13 @@ CGEventRef OpenKeyCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef e _syncKey.clear(); } else if (pData->extCode == 2) { //delete key if (_syncKey.size() > 0) { - if (_syncKey.back() > 1 && (vCodeTable == 2 || !containUnicodeCompoundApp(FRONT_APP))) { + if (_syncKey.back() > 1 && (vCodeTable == 2 || !containUnicodeCompoundApp(FRONT_APP)) && eventBackSpaceDown && eventBackSpaceUp) { //send one more backspace CGEventTapPostEvent(_proxy, eventBackSpaceDown); CGEventTapPostEvent(_proxy, eventBackSpaceUp); } _syncKey.pop_back(); } - } else if (pData->extCode == 3) { //normal key InsertKeyLength(1); } @@ -732,7 +830,7 @@ CGEventRef OpenKeyCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef e //send backspace if (pData->backspaceCount > 0 && pData->backspaceCount < MAX_BUFF) { - for (_i = 0; _i < pData->backspaceCount; _i++) { + for (int i = 0; i < pData->backspaceCount; i++) { SendBackspace(); } } diff --git a/Sources/OpenKey/macOS/OpenKey.xcodeproj/project.pbxproj b/Sources/OpenKey/macOS/OpenKey.xcodeproj/project.pbxproj index 8434abed..596497d5 100644 --- a/Sources/OpenKey/macOS/OpenKey.xcodeproj/project.pbxproj +++ b/Sources/OpenKey/macOS/OpenKey.xcodeproj/project.pbxproj @@ -570,6 +570,7 @@ buildSettings = { CLANG_ENABLE_MODULES = NO; CODE_SIGN_IDENTITY = "Mac Developer"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 48; @@ -580,7 +581,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 11.5; MARKETING_VERSION = 2.0.4; OTHER_LDFLAGS = ( "-lc++\n-lc++", @@ -596,6 +597,7 @@ buildSettings = { CLANG_ENABLE_MODULES = NO; CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 48; @@ -606,7 +608,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 11.5; MARKETING_VERSION = 2.0.4; OTHER_LDFLAGS = ( "-lc++\n-lc++", diff --git a/Sources/OpenKey/macOS/OpenKey.xcodeproj/project.xcworkspace/xcuserdata/irix.xcuserdatad/UserInterfaceState.xcuserstate b/Sources/OpenKey/macOS/OpenKey.xcodeproj/project.xcworkspace/xcuserdata/irix.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 00000000..e02c4fce Binary files /dev/null and b/Sources/OpenKey/macOS/OpenKey.xcodeproj/project.xcworkspace/xcuserdata/irix.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Sources/OpenKey/macOS/OpenKey.xcodeproj/project.xcworkspace/xcuserdata/irix.xcuserdatad/xcdebugger/Expressions.xcexplist b/Sources/OpenKey/macOS/OpenKey.xcodeproj/project.xcworkspace/xcuserdata/irix.xcuserdatad/xcdebugger/Expressions.xcexplist new file mode 100644 index 00000000..b873cab8 --- /dev/null +++ b/Sources/OpenKey/macOS/OpenKey.xcodeproj/project.xcworkspace/xcuserdata/irix.xcuserdatad/xcdebugger/Expressions.xcexplist @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/Sources/OpenKey/macOS/OpenKey.xcodeproj/xcuserdata/irix.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Sources/OpenKey/macOS/OpenKey.xcodeproj/xcuserdata/irix.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 00000000..1ece9ca1 --- /dev/null +++ b/Sources/OpenKey/macOS/OpenKey.xcodeproj/xcuserdata/irix.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +