diff --git a/Sources/OpenKey/engine/DataType.h b/Sources/OpenKey/engine/DataType.h index 1393e09f..d66413a6 100644 --- a/Sources/OpenKey/engine/DataType.h +++ b/Sources/OpenKey/engine/DataType.h @@ -130,6 +130,8 @@ struct vKeyHookState { #define IS_CONSONANT(keyCode) !(keyCode == KEY_A || keyCode == KEY_E || keyCode == KEY_U || keyCode == KEY_Y || keyCode == KEY_I || keyCode == KEY_O) //#define IS_MARK_KEY(keyCode) (keyCode == KEY_S || keyCode == KEY_F || keyCode == KEY_R || keyCode == KEY_J || keyCode == KEY_X) #define CHR(index) (Uint16)TypingWord[index] +// Safer version with bounds checking +#define CHR_SAFE(index) ((index >= 0 && index < MAX_BUFF) ? (Uint16)TypingWord[index] : 0) #define IS_SPECIALKEY(keyCode) \ (vInputType == vTelex ? \ keyCode == KEY_W || keyCode == KEY_E || keyCode == KEY_R || keyCode == KEY_O || keyCode == KEY_LEFT_BRACKET || \ diff --git a/Sources/OpenKey/engine/Engine.cpp b/Sources/OpenKey/engine/Engine.cpp index 2a895f47..aa70e484 100644 --- a/Sources/OpenKey/engine/Engine.cpp +++ b/Sources/OpenKey/engine/Engine.cpp @@ -93,30 +93,30 @@ static Uint32 KeyStates[MAX_BUFF]; static Byte _stateIndex = 0; static bool tempDisableKey = false; -static int capsElem; -static int key; -static int markElem; +static int capsElem = 0; +static int key = 0; +static int markElem = 0; static bool isCorect = false; static bool isChanged = false; static Byte vowelCount = 0; static Byte vowelStartIndex = 0; static Byte vowelEndIndex = 0; static Byte vowelWillSetMark = 0; -static int i, ii, iii; -static int j; -static int k, kk; -static int l; -static bool isRestoredW; -static Uint16 keyForAEO; -static bool isCheckedGrammar; +static int i = 0, ii = 0, iii = 0; +static int j = 0; +static int k = 0, kk = 0; +static int l = 0; +static bool isRestoredW = false; +static Uint16 keyForAEO = 0; +static bool isCheckedGrammar = false; static bool _isCaps = false; static int _spaceCount = 0; //add: July 30th, 2019 static bool _hasHandledMacro = false; //for macro flag August 9th, 2019 static Byte _upperCaseStatus = 0; //for Write upper case for the first letter; 2: will upper case -static bool _isCharKeyCode; +static bool _isCharKeyCode = false; static vector _specialChar; -static bool _useSpellCheckingBefore; -static bool _hasHandleQuickConsonant; +static bool _useSpellCheckingBefore = false; +static bool _hasHandleQuickConsonant = false; static bool _willTempOffEngine = false; //function prototype @@ -353,7 +353,10 @@ void insertKey(const Uint16& keyCode, const bool& isCaps, const bool& isCheckSpe for (iii = 0; iii < MAX_BUFF - 1; iii++) { TypingWord[iii] = TypingWord[iii + 1]; } - setKeyData(_index-1, keyCode, isCaps); + // Fix: Ensure we don't write beyond array bounds + if (_index - 1 < MAX_BUFF) { + setKeyData(_index-1, keyCode, isCaps); + } } else { setKeyData(_index++, keyCode, isCaps); } @@ -372,7 +375,10 @@ void insertState(const Uint16& keyCode, const bool& isCaps) { for (iii = 0; iii < MAX_BUFF - 1; iii++) { KeyStates[iii] = KeyStates[iii + 1]; } - KeyStates[_stateIndex-1] = keyCode | (isCaps ? CAPS_MASK : 0); + // Fix: Ensure we don't write beyond array bounds + if (_stateIndex - 1 < MAX_BUFF) { + KeyStates[_stateIndex-1] = keyCode | (isCaps ? CAPS_MASK : 0); + } } else { KeyStates[_stateIndex++] = keyCode | (isCaps ? CAPS_MASK : 0); } @@ -442,13 +448,16 @@ void restoreLastTypingState() { _index = 0; } else if (std::find(_charKeyCode.begin(), _charKeyCode.end(), (Uint16)_typingStatesData[0]) != _charKeyCode.end()) { _index = 0; - _specialChar = _typingStatesData; + // Fix: Make a proper copy to avoid potential issues + _specialChar.clear(); + _specialChar.assign(_typingStatesData.begin(), _typingStatesData.end()); checkSpelling(); } else { for (i = 0; i < _typingStatesData.size(); i++) { TypingWord[i] = _typingStatesData[i]; } - _index = (Byte)_typingStatesData.size(); + // Fix: Ensure _index doesn't exceed MAX_BUFF + _index = (Byte)min((int)_typingStatesData.size(), MAX_BUFF); } } } diff --git a/Sources/OpenKey/macOS/ModernKey/OpenKey.mm b/Sources/OpenKey/macOS/ModernKey/OpenKey.mm index 4292db2d..fd5d43e8 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 @@ -571,10 +597,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 +724,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,7 +739,7 @@ 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" return event; } CFRelease(langRef); @@ -688,6 +750,21 @@ CGEventRef OpenKeyCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef e //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, @@ -707,7 +784,6 @@ CGEventRef OpenKeyCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef e } _syncKey.pop_back(); } - } else if (pData->extCode == 3) { //normal key InsertKeyLength(1); } @@ -732,7 +808,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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +