diff --git a/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj b/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj index 8e0b973442..46b7f70e24 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj +++ b/mac/Keyman4MacIM/Keyman4MacIM.xcodeproj/project.pbxproj @@ -72,6 +72,7 @@ 98FE10631B4DEE5600525F54 /* KMInfoWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98FE10611B4DEE5600525F54 /* KMInfoWindowController.m */; }; 9A3D6C5D221531B0008785A3 /* KMOSVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A3D6C5C221531B0008785A3 /* KMOSVersion.m */; }; B90818AF7ED302187DE0E026 /* Pods_Keyman.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B644E63217FFE54B91C71C94 /* Pods_Keyman.framework */; }; + D861B03F2C5747F70003675E /* KMSettingsRepository.m in Sources */ = {isa = PBXBuildFile; fileRef = D861B03E2C5747F70003675E /* KMSettingsRepository.m */; }; E211769D20E182DD00F8065D /* NoContextTestClient.m in Sources */ = {isa = PBXBuildFile; fileRef = E211769C20E182DD00F8065D /* NoContextTestClient.m */; }; E21176A020E18C5200F8065D /* AppleCompliantTestClient.m in Sources */ = {isa = PBXBuildFile; fileRef = E211769F20E18C5200F8065D /* AppleCompliantTestClient.m */; }; E211CCF620B600A500505C36 /* KeymanEngine4Mac.framework.dSYM in CopyFiles */ = {isa = PBXBuildFile; fileRef = E211CCF520B600A500505C36 /* KeymanEngine4Mac.framework.dSYM */; }; @@ -350,6 +351,8 @@ CEFFECDB2A417FEC00D58C36 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/KMKeyboardHelpWindowController.strings; sourceTree = ""; }; CEFFECDC2A417FEC00D58C36 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/MainMenu.strings; sourceTree = ""; }; CEFFECDD2A4180FD00D58C36 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; + D861B03D2C5747F70003675E /* KMSettingsRepository.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KMSettingsRepository.h; sourceTree = ""; }; + D861B03E2C5747F70003675E /* KMSettingsRepository.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = KMSettingsRepository.m; sourceTree = ""; tabWidth = 2; }; E211769B20E1826800F8065D /* NoContextTestClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NoContextTestClient.h; sourceTree = ""; }; E211769C20E182DD00F8065D /* NoContextTestClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NoContextTestClient.m; sourceTree = ""; }; E211769E20E18C0B00F8065D /* AppleCompliantTestClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppleCompliantTestClient.h; sourceTree = ""; }; @@ -548,6 +551,8 @@ 29B4A0D32BF7675A00682049 /* KMLogs.m */, 299ABD6F29ECE75B00AA5948 /* KeySender.m */, 299ABD7029ECE75B00AA5948 /* KeySender.h */, + D861B03D2C5747F70003675E /* KMSettingsRepository.h */, + D861B03E2C5747F70003675E /* KMSettingsRepository.m */, 297A501128DF4D360074EB1B /* Privacy */, 98FE105B1B4DE86300525F54 /* Categories */, 98D6DA791A799EE700B09822 /* Frameworks */, @@ -974,6 +979,7 @@ 29B4A0D52BF7675A00682049 /* KMLogs.m in Sources */, 98BF924F1BF02DC20002126A /* KMBarView.m in Sources */, E240F599202DED740000067D /* KMPackage.m in Sources */, + D861B03F2C5747F70003675E /* KMSettingsRepository.m in Sources */, 984B8F441AF1C3D900E096A8 /* OSKWindowController.m in Sources */, 9836B3711AE5F11D00780482 /* mztools.c in Sources */, 9836B3701AE5F11D00780482 /* ioapi.c in Sources */, diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m index 0675a78ade..b7acec58e8 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m @@ -16,6 +16,7 @@ // Keyman4MacIM[6245]: IMK Stall detected, *please Report* your user scenario in - (sessionFinished) block performed very slowly (0.00 secs) #import "KMInputMethodAppDelegate.h" +#import "KMSettingsRepository.h" #import "KMConfigurationWindowController.h" #import "KMDownloadKBWindowController.h" #import "ZipArchive.h" @@ -509,7 +510,9 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef if(_keymanDataPath == nil) { NSString *documentDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; _keymanDataPath = [documentDirPath stringByAppendingPathComponent:@"Keyman-Keyboards"]; - + + os_log_debug([KMLogs dataLog], "creating keymanDataPath, %{public}@", _keymanDataPath); + NSFileManager *fm = [NSFileManager defaultManager]; if (![fm fileExistsAtPath:_keymanDataPath]) { [fm createDirectoryAtPath:_keymanDataPath withIntermediateDirectories:YES attributes:nil error:nil]; @@ -531,6 +534,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (NSArray *)kmxFileList { + os_log_debug([KMLogs dataLog], "kmxFileList"); if (_kmxFileList == nil) { NSArray *kmxFiles = [self KMXFiles]; _kmxFileList = [[NSMutableArray alloc] initWithCapacity:0]; @@ -650,6 +654,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (NSArray *)keyboardNamesFromFolder:(NSString *)packageFolder { + os_log_debug([KMLogs dataLog], "keyboardNamesFromFolder, folder = %{public}@", packageFolder); NSMutableArray *kbNames = [[NSMutableArray alloc] initWithCapacity:0];; for (NSString *kmxFile in [self KMXFilesAtPath:packageFolder]) { NSDictionary * infoDict = [KMXFile keyboardInfoFromKmxFile:kmxFile]; @@ -756,6 +761,12 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (void)awakeFromNib { + if ([KMSettingsRepository.shared keyboardsMigrationNeeded]) { + os_log_info([KMLogs startupLog], "keyboards migration needed"); + } else { + os_log_info([KMLogs startupLog], "keyboards migration not needed"); + } + [self setDefaultKeymanMenuItems]; [self updateKeyboardMenuItems]; } @@ -928,13 +939,16 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (NSArray *)KMXFilesAtPath:(NSString *)path { + os_log_debug([KMLogs dataLog], "Reading KMXFiles at path %{public}@", path); NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:path]; NSMutableArray *kmxFiles = [[NSMutableArray alloc] initWithCapacity:0]; NSString *filePath; while (filePath = (NSString *)[dirEnum nextObject]) { NSString *extension = [[filePath pathExtension] lowercaseString]; - if ([extension isEqualToString:@"kmx"]) + if ([extension isEqualToString:@"kmx"]) { [kmxFiles addObject:[path stringByAppendingPathComponent:filePath]]; + os_log_debug([KMLogs dataLog], "file = %{public}@", filePath); + } } return kmxFiles; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m index fa912ca67d..cf9eea0702 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m @@ -10,6 +10,7 @@ #import /* For kVK_ constants. */ #import "KeySender.h" #import "TextApiCompliance.h" +#import "KMSettingsRepository.h" #import "KMLogs.h" @import Sentry; @@ -238,6 +239,17 @@ NSString* const kEasterEggKmxName = @"EnglishSpanish.kmx"; // return NO to pass through to client app return NO; } + + // TODO: remove test code + /* + if (event.keyCode == kVK_ANSI_Slash) { + if ([KMSettingsRepository.shared keyboardsMigrationNeeded]) { + os_log_info([KMLogs startupLog], "keyboards migration needed"); + } else { + os_log_info([KMLogs startupLog], "keyboards migration not needed"); + } + } + */ } if (event.type == NSEventTypeFlagsChanged) { @@ -412,11 +424,11 @@ NSString* const kEasterEggKmxName = @"EnglishSpanish.kmx"; for(NSString *key in options) { NSString *value = [options objectForKey:key]; if(key && value) { - os_log_debug([KMLogs keyLog], "applyNonTextualOutput calling writePersistedOptions, key: %{public}@, value: %{public}@", key, value); + os_log_debug([KMLogs keyLog], "persistOptions, key: %{public}@, value: %{public}@", key, value); [self.appDelegate writePersistedOptions:key withValue:value]; } else { - os_log_debug([KMLogs keyLog], "applyNonTextualOutput, invalid values in optionsToPersist, not writing to UserDefaults, key: %{public}@, value: %{public}@", key, value); + os_log_debug([KMLogs keyLog], "invalid values in persistOptions, not writing to UserDefaults, key: %{public}@, value: %{public}@", key, value); } } } diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h new file mode 100644 index 0000000000..e4b9f1c158 --- /dev/null +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h @@ -0,0 +1,20 @@ +/** + * Keyman is copyright (C) SIL International. MIT License. + * + * KMSettingsRepository.h + * Keyman + * + * Created by Shawn Schantz on 2024-07-29. + * + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface KMSettingsRepository : NSObject ++ (KMSettingsRepository *)shared; +- (BOOL)keyboardsMigrationNeeded; +@end + +NS_ASSUME_NONNULL_END diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m new file mode 100644 index 0000000000..d5a26cccac --- /dev/null +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m @@ -0,0 +1,57 @@ +/** + * Keyman is copyright (C) SIL International. MIT License. + * + * KMSettingsRepository.h + * Keyman + * + * Created by Shawn Schantz on 2024-07-29. + * + * Singleton object for reading and writing Keyman application settings. + * Serves as an abstraction to StandardUserDefaults which is currently used to persist application settings. + */ + +#import "KMSettingsRepository.h" +#import "KMLogs.h" + +NSString *const kStoreKeyboardsInLibraryKey = @"KMStoreKeyboardsInLibraryKey"; +NSString *const kActiveKeyboardsKey = @"KMActiveKeyboardsKey"; + +@implementation KMSettingsRepository + ++ (KMSettingsRepository *)shared +{ + static KMSettingsRepository *shared = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + shared = [[KMSettingsRepository alloc] init]; + }); + return shared; +} + +- (BOOL)settingsExist +{ + return [[NSUserDefaults standardUserDefaults] objectForKey:kActiveKeyboardsKey] != nil; +} + +- (BOOL)keyboardsStoredInLibraryFolder +{ + return [[NSUserDefaults standardUserDefaults] boolForKey:kStoreKeyboardsInLibraryKey]; +} + +/** + * Determines whether the keyboards data needs to be moved from the old location in the Documents folder to the new location under /username/Library... + * This is true if + * 1) the UserDefaults exist (indicating that this is not a new installation of Keyman) and + * 2) the value for KMStoreKeyboardsInLibraryKey is not set to true + */ +- (BOOL)keyboardsMigrationNeeded { + BOOL keyboardSettingsExist = [self settingsExist]; + os_log([KMLogs startupLog], " keyboard settings exist: %@", keyboardSettingsExist ? @"YES" : @"NO" ); + + BOOL keyboardsInLibrary = [self keyboardsStoredInLibraryFolder]; + os_log([KMLogs startupLog], " keyboards stored in Library: %@", keyboardsInLibrary ? @"YES" : @"NO" ); + + return !(keyboardSettingsExist && keyboardsInLibrary); +} + +@end