From ea356d6d6722c6a3715ad95f84dddfb2f10b0f1d Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Tue, 11 Jan 2022 22:59:39 +0800 Subject: [PATCH] Shiki #13: UserPhrases // CHS mode compatibility. - Also remove useless menu entry. --- Source/AppDelegate.m | 8 +- Source/InputMethodController.h | 3 +- Source/InputMethodController.mm | 323 +++++++++++++++-------- Source/en.lproj/Localizable.strings | 1 - Source/zh-Hans.lproj/Localizable.strings | 1 - Source/zh-Hant.lproj/Localizable.strings | 1 - 6 files changed, 213 insertions(+), 124 deletions(-) diff --git a/Source/AppDelegate.m b/Source/AppDelegate.m index 608ef5dc..5d9e2fa3 100644 --- a/Source/AppDelegate.m +++ b/Source/AppDelegate.m @@ -42,7 +42,8 @@ #import "frmAboutWindow.h" extern void LTLoadLanguageModel(void); -extern void LTLoadUserLanguageModelFile(void); +extern void LTLoadUserLanguageModelFileCHT(void); +extern void LTLoadUserLanguageModelFileCHS(void); static NSString *kCheckUpdateAutomatically = @"CheckUpdateAutomatically"; static NSString *kNextUpdateCheckDateKey = @"NextUpdateCheckDate"; @@ -67,9 +68,10 @@ static const NSTimeInterval kTimeoutInterval = 60.0; - (void)applicationDidFinishLaunching:(NSNotification *)inNotification { LTLoadLanguageModel(); - LTLoadUserLanguageModelFile(); + LTLoadUserLanguageModelFileCHT(); + LTLoadUserLanguageModelFileCHS(); - if (![[NSUserDefaults standardUserDefaults] objectForKey:kCheckUpdateAutomatically]) { + if (![[NSUserDefaults standardUserDefaults] objectForKey:kCheckUpdateAutomatically]) { [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kCheckUpdateAutomatically]; [[NSUserDefaults standardUserDefaults] synchronize]; } diff --git a/Source/InputMethodController.h b/Source/InputMethodController.h index c3f512d7..b02edb27 100644 --- a/Source/InputMethodController.h +++ b/Source/InputMethodController.h @@ -89,4 +89,5 @@ // the shared language model object extern "C" void LTLoadLanguageModel(); -extern "C" void LTLoadUserLanguageModelFile(); +extern "C" void LTLoadUserLanguageModelFileCHT(); +extern "C" void LTLoadUserLanguageModelFileCHS(); diff --git a/Source/InputMethodController.mm b/Source/InputMethodController.mm index 76b71fbb..6796bfdb 100644 --- a/Source/InputMethodController.mm +++ b/Source/InputMethodController.mm @@ -141,48 +141,52 @@ static NSString *LTUserPhrasesDataPathCHT() return [LTUserDataFolderPath() stringByAppendingPathComponent:@"userdata-cht.txt"]; } -// static NSString *LTUserPhrasesDataPathCHS() -// { - // return [LTUserDataFolderPath() stringByAppendingPathComponent:@"userdata-chs.txt"]; - // } +static NSString *LTUserPhrasesDataPathCHS() +{ + return [LTUserDataFolderPath() stringByAppendingPathComponent:@"userdata-chs.txt"]; +} static BOOL LTCheckIfUserLanguageModelFileExists() { - NSString *folderPath = LTUserDataFolderPath(); - BOOL isFolder = NO; - BOOL folderExist = [[NSFileManager defaultManager] fileExistsAtPath:folderPath isDirectory:&isFolder]; - if (folderExist && !isFolder) { - NSError *error = nil; - [[NSFileManager defaultManager] removeItemAtPath:folderPath error:&error]; - if (error) { - NSLog(@"Failed to remove folder %@", error); - return NO; - } - folderExist = NO; - } - if (!folderExist) { - NSError *error = nil; - [[NSFileManager defaultManager] createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:&error]; - if (error) { - NSLog(@"Failed to create folder %@", error); - return NO; - } - } - - NSString *filePath = LTUserPhrasesDataPathCHT(); - if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) { - BOOL result = [[@"" dataUsingEncoding:NSUTF8StringEncoding] writeToFile:filePath atomically:YES]; - if (!result) { - NSLog(@"Failed to write file"); - return NO; - } - } - return YES; + NSString *folderPath = LTUserDataFolderPath(); + BOOL isFolder = NO; + BOOL folderExist = [[NSFileManager defaultManager] fileExistsAtPath:folderPath isDirectory:&isFolder]; + if (folderExist && !isFolder) { + NSError *error = nil; + [[NSFileManager defaultManager] removeItemAtPath:folderPath error:&error]; + if (error) { + NSLog(@"Failed to remove folder %@", error); + return NO; + } + folderExist = NO; + } + if (!folderExist) { + NSError *error = nil; + [[NSFileManager defaultManager] createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:&error]; + if (error) { + NSLog(@"Failed to create folder %@", error); + return NO; + } + } + NSString *filePathCHS = LTUserPhrasesDataPathCHS(); + if (![[NSFileManager defaultManager] fileExistsAtPath:filePathCHS]) { + BOOL result = [[@"" dataUsingEncoding:NSUTF8StringEncoding] writeToFile:filePathCHS atomically:YES]; + if (!result) { + NSLog(@"Failed to write userdict CHS file"); + return NO; + } + } + NSString *filePathCHT = LTUserPhrasesDataPathCHT(); + if (![[NSFileManager defaultManager] fileExistsAtPath:filePathCHT]) { + BOOL result = [[@"" dataUsingEncoding:NSUTF8StringEncoding] writeToFile:filePathCHT atomically:YES]; + if (!result) { + NSLog(@"Failed to write userdict CHT file"); + return NO; + } + } + return YES; } - - - // https://clang-analyzer.llvm.org/faq.html __attribute__((annotate("returns_localized_nsstring"))) static inline NSString *LocalizationNotNeeded(NSString *s) { @@ -260,7 +264,13 @@ static double FindHighestScore(const vector& nodes, double epsilon) _languageModel = &gLanguageModelCHT; _userPhrasesModel = &gUserPhraseLanguageModelCHT; _builder = new BlockReadingBuilder(_languageModel, _userPhrasesModel); - _uom = &gUserOverrideModelCHT; + if (_inputMode == kSimpBopomofoModeIdentifier) { + NSLog(@"gUserOverrideModelCHS called"); + _uom = &gUserOverrideModelCHS; + } else { + NSLog(@"gUserOverrideModelCHT called"); + _uom = &gUserOverrideModelCHT; + } // each Mandarin syllable is separated by a hyphen _builder->setJoinSeparator("-"); @@ -291,28 +301,26 @@ static double FindHighestScore(const vector& nodes, double epsilon) chineseConversionMenuItem.state = _chineseConversionEnabled ? NSControlStateValueOn : NSControlStateValueOff; [menu addItem:chineseConversionMenuItem]; - // Needs improvement for Simplified Chinese Input - if (_inputMode != kSimpBopomofoModeIdentifier) { - [menu addItem:[NSMenuItem separatorItem]]; - [menu addItemWithTitle:NSLocalizedString(@"User Phrases", @"") action:NULL keyEquivalent:@""]; - NSMenuItem *editUserPheaseItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Edit User Phrases", @"") action:@selector(openUserPhrases:) keyEquivalent:@""]; - [editUserPheaseItem setIndentationLevel:2]; - [menu addItem:editUserPheaseItem]; + [menu addItem:[NSMenuItem separatorItem]]; // ----------------------- + + NSMenuItem *editUserPheaseItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Edit User Phrases", @"") action:@selector(openUserPhrases:) keyEquivalent:@""]; + [editUserPheaseItem setIndentationLevel:2]; + [menu addItem:editUserPheaseItem]; - NSMenuItem *reloadUserPheaseItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Reload User Phrases", @"") action:@selector(reloadUserPhrases:) keyEquivalent:@""]; - [reloadUserPheaseItem setIndentationLevel:2]; - [menu addItem:reloadUserPheaseItem]; - [menu addItem:[NSMenuItem separatorItem]]; - } + NSMenuItem *reloadUserPheaseItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Reload User Phrases", @"") action:@selector(reloadUserPhrases:) keyEquivalent:@""]; + [reloadUserPheaseItem setIndentationLevel:2]; + [menu addItem:reloadUserPheaseItem]; + + [menu addItem:[NSMenuItem separatorItem]]; // ----------------------- NSMenuItem *updateCheckItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Check for Updates…", @"") action:@selector(checkForUpdate:) keyEquivalent:@""]; [menu addItem:updateCheckItem]; NSMenuItem *aboutMenuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"About vChewing…", @"") action:@selector(showAbout:) keyEquivalent:@""]; [menu addItem:aboutMenuItem]; - - // Menu Debug Purposes... - NSLog(@"menu %@", menu); + + // Menu Debug Purposes... + NSLog(@"menu %@", menu); return menu; } @@ -410,46 +418,85 @@ static double FindHighestScore(const vector& nodes, double epsilon) NSString *newInputMode; Formosa::Gramambular::FastLM *newLanguageModel; Formosa::Gramambular::FastLM *userPhraseModel; + vChewing::UserOverrideModel *newUom; - if ([value isKindOfClass:[NSString class]] && [value isEqual:kSimpBopomofoModeIdentifier]) { - newInputMode = kSimpBopomofoModeIdentifier; - newLanguageModel = &gLanguageModelCHS; - userPhraseModel = &gUserPhraseLanguageModelCHS; - } - else { - newInputMode = kBopomofoModeIdentifier; - newLanguageModel = &gLanguageModelCHT; - userPhraseModel = &gUserPhraseLanguageModelCHT; - } + if ([value isKindOfClass:[NSString class]]) { + + if ([value isEqual:kSimpBopomofoModeIdentifier]) { + + newInputMode = kSimpBopomofoModeIdentifier; + newLanguageModel = &gLanguageModelCHS; + newUom = &gUserOverrideModelCHS; + userPhraseModel = &gUserPhraseLanguageModelCHS; - // Only apply the changes if the value is changed - if (![_inputMode isEqualToString:newInputMode]) { - [[NSUserDefaults standardUserDefaults] synchronize]; + if (![_inputMode isEqualToString:newInputMode]) { + [[NSUserDefaults standardUserDefaults] synchronize]; - // Remember to override the keyboard layout again -- treat this as an activate event - NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey]; - if (!basisKeyboardLayoutID) { - basisKeyboardLayoutID = @"com.apple.keylayout.US"; - } - [sender overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID]; + // Remember to override the keyboard layout again -- treat this as an activate event + NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey]; + if (!basisKeyboardLayoutID) { + basisKeyboardLayoutID = @"com.apple.keylayout.US"; + } + [sender overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID]; - _inputMode = newInputMode; - _languageModel = newLanguageModel; - _userPhrasesModel = userPhraseModel; + _inputMode = newInputMode; + _languageModel = newLanguageModel; + _userPhrasesModel = userPhraseModel; - if (!_bpmfReadingBuffer->isEmpty()) { - _bpmfReadingBuffer->clear(); - [self updateClientComposingBuffer:sender]; - } + if (!_bpmfReadingBuffer->isEmpty()) { + _bpmfReadingBuffer->clear(); + [self updateClientComposingBuffer:sender]; + } - if ([_composingBuffer length] > 0) { - [self commitComposition:sender]; - } + if ([_composingBuffer length] > 0) { + [self commitComposition:sender]; + } - if (_builder) { - delete _builder; - _builder = new BlockReadingBuilder(_languageModel, _userPhrasesModel); - _builder->setJoinSeparator("-"); + if (_builder) { + delete _builder; + _builder = new BlockReadingBuilder(_languageModel, _userPhrasesModel); + _builder->setJoinSeparator("-"); + } + } + _uom = newUom; + + } else if ([value isEqual:kBopomofoModeIdentifier]) { + + newInputMode = kBopomofoModeIdentifier; + newLanguageModel = &gLanguageModelCHT; + userPhraseModel = &gUserPhraseLanguageModelCHT; + newUom = &gUserOverrideModelCHT; + + if (![_inputMode isEqualToString:newInputMode]) { + [[NSUserDefaults standardUserDefaults] synchronize]; + + // Remember to override the keyboard layout again -- treat this as an activate event + NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey]; + if (!basisKeyboardLayoutID) { + basisKeyboardLayoutID = @"com.apple.keylayout.US"; + } + [sender overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID]; + + _inputMode = newInputMode; + _languageModel = newLanguageModel; + _userPhrasesModel = userPhraseModel; + + if (!_bpmfReadingBuffer->isEmpty()) { + _bpmfReadingBuffer->clear(); + [self updateClientComposingBuffer:sender]; + } + + if ([_composingBuffer length] > 0) { + [self commitComposition:sender]; + } + + if (_builder) { + delete _builder; + _builder = new BlockReadingBuilder(_languageModel, _userPhrasesModel); + _builder->setJoinSeparator("-"); + } + } + _uom = newUom; } } } @@ -710,28 +757,42 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; } - (BOOL)_writeUserPhrase { - if (!LTCheckIfUserLanguageModelFileExists()) { - return NO; - } + if (!LTCheckIfUserLanguageModelFileExists()) { + return NO; + } - NSString *currentMarkedPhrase = [self _currentMarkedText]; + NSString *currentMarkedPhrase = [self _currentMarkedText]; if (![currentMarkedPhrase length]) { return NO; } currentMarkedPhrase = [currentMarkedPhrase stringByAppendingString:@"\n"]; - NSString *path = LTUserPhrasesDataPathCHT(); - NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:path]; - if (!file) { - return NO; + + if (_inputMode == kSimpBopomofoModeIdentifier) { + NSString *path = LTUserPhrasesDataPathCHS(); + NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:path]; + if (!file) { + return NO; + } + [file seekToEndOfFile]; + NSData *data = [currentMarkedPhrase dataUsingEncoding:NSUTF8StringEncoding]; + [file writeData:data]; + [file closeFile]; + LTLoadUserLanguageModelFileCHS(); + return YES; + } else { + NSString *path = LTUserPhrasesDataPathCHT(); + NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:path]; + if (!file) { + return NO; + } + [file seekToEndOfFile]; + NSData *data = [currentMarkedPhrase dataUsingEncoding:NSUTF8StringEncoding]; + [file writeData:data]; + [file closeFile]; + LTLoadUserLanguageModelFileCHT(); + return YES; } - [file seekToEndOfFile]; - NSData *data = [currentMarkedPhrase dataUsingEncoding:NSUTF8StringEncoding]; - [file writeData:data]; - [file closeFile]; - - LTLoadUserLanguageModelFile(); - return YES; } - (BOOL)handleInputText:(NSString*)inputText key:(NSInteger)keyCode modifiers:(NSUInteger)flags client:(id)client @@ -1556,26 +1617,45 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; } - (void)openUserPhrases:(id)sender { - NSLog(@"openUserPhrases called"); - if (!LTCheckIfUserLanguageModelFileExists()) { - NSString *content = [NSString stringWithFormat:NSLocalizedString(@"Please check the permission of at \"%@\".", @""), LTUserDataFolderPath()]; - [[OVNonModalAlertWindowController sharedInstance] showWithTitle:NSLocalizedString(@"Unable to create the user phrase file.", @"") content:content confirmButtonTitle:NSLocalizedString(@"OK", @"") cancelButtonTitle:nil cancelAsDefault:NO delegate:nil]; - return; - } - - NSString *path = LTUserPhrasesDataPathCHT(); - NSLog(@"Open %@", path); - if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { - [[@"" dataUsingEncoding:NSUTF8StringEncoding] writeToFile:path atomically:YES]; + NSLog(@"openUserPhrases called"); + if (!LTCheckIfUserLanguageModelFileExists()) { + NSString *content = [NSString stringWithFormat:NSLocalizedString(@"Please check the permission of at \"%@\".", @""), LTUserDataFolderPath()]; + [[OVNonModalAlertWindowController sharedInstance] showWithTitle:NSLocalizedString(@"Unable to create the user phrase file.", @"") content:content confirmButtonTitle:NSLocalizedString(@"OK", @"") cancelButtonTitle:nil cancelAsDefault:NO delegate:nil]; + return; } - NSURL *url = [NSURL fileURLWithPath:path]; - [[NSWorkspace sharedWorkspace] openURL:url]; + + if (_inputMode == kSimpBopomofoModeIdentifier) { + NSLog(@"editUserPhrases CHS called"); + NSString *path = LTUserPhrasesDataPathCHS(); + NSLog(@"Open %@", path); + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { + [[@"" dataUsingEncoding:NSUTF8StringEncoding] writeToFile:path atomically:YES]; + } + NSURL *url = [NSURL fileURLWithPath:path]; + [[NSWorkspace sharedWorkspace] openURL:url]; + } else { + NSLog(@"editUserPhrases CHT called"); + NSString *path = LTUserPhrasesDataPathCHT(); + NSLog(@"Open %@", path); + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { + [[@"" dataUsingEncoding:NSUTF8StringEncoding] writeToFile:path atomically:YES]; + } + NSURL *url = [NSURL fileURLWithPath:path]; + [[NSWorkspace sharedWorkspace] openURL:url]; + } + + } - (void)reloadUserPhrases:(id)sender { - NSLog(@"reloadUserPhrases called"); - LTLoadUserLanguageModelFile(); + if (_inputMode == kSimpBopomofoModeIdentifier) { + NSLog(@"reloadUserPhrases CHS called"); + LTLoadUserLanguageModelFileCHS(); + } else { + NSLog(@"reloadUserPhrases CHT called"); + LTLoadUserLanguageModelFileCHT(); + } } - (void)showAbout:(id)sender @@ -1655,7 +1735,7 @@ void LTLoadLanguageModel() LTLoadLanguageModelFile(@"data-chs", gLanguageModelCHS); } -void LTLoadUserLanguageModelFile() +void LTLoadUserLanguageModelFileCHT() { gUserPhraseLanguageModelCHT.close(); bool result = gUserPhraseLanguageModelCHT.open([LTUserPhrasesDataPathCHT() UTF8String]); @@ -1663,3 +1743,12 @@ void LTLoadUserLanguageModelFile() NSLog(@"Failed opening language model for CHT user phrases."); } } + +void LTLoadUserLanguageModelFileCHS() +{ + gUserPhraseLanguageModelCHS.close(); + bool result = gUserPhraseLanguageModelCHS.open([LTUserPhrasesDataPathCHS() UTF8String]); + if (!result) { + NSLog(@"Failed opening language model for CHT user phrases."); + } +} diff --git a/Source/en.lproj/Localizable.strings b/Source/en.lproj/Localizable.strings index b3d7268d..a82c6261 100644 --- a/Source/en.lproj/Localizable.strings +++ b/Source/en.lproj/Localizable.strings @@ -19,7 +19,6 @@ "Chinese Conversion" = "Convert zh-TW Kanji to KangXi Variants"; "NotificationSwitchON" = " ON"; "NotificationSwitchOFF" = " OFF"; -"User Phrases" = "User Phrases"; "Edit User Phrases" = "Edit User Phrases"; "Reload User Phrases" = "Reload User Phrases"; "Unable to create the user phrase file." = "Unable to create the user phrase file."; diff --git a/Source/zh-Hans.lproj/Localizable.strings b/Source/zh-Hans.lproj/Localizable.strings index c2c7311c..d3f45f5a 100644 --- a/Source/zh-Hans.lproj/Localizable.strings +++ b/Source/zh-Hans.lproj/Localizable.strings @@ -19,7 +19,6 @@ "Chinese Conversion" = "优先使用康熙繁体字"; "NotificationSwitchON" = " 已启用"; "NotificationSwitchOFF" = " 已停用"; -"User Phrases" = "自订语汇"; "Edit User Phrases" = "编辑自订语汇"; "Reload User Phrases" = "重载自订语汇"; "Unable to create the user phrase file." = "无法创建自订语汇档案。"; diff --git a/Source/zh-Hant.lproj/Localizable.strings b/Source/zh-Hant.lproj/Localizable.strings index a3b24b4f..a36c50b8 100644 --- a/Source/zh-Hant.lproj/Localizable.strings +++ b/Source/zh-Hant.lproj/Localizable.strings @@ -19,7 +19,6 @@ "Chinese Conversion" = "優先使用康熙繁體字"; "NotificationSwitchON" = " 已啟用"; "NotificationSwitchOFF" = " 已停用"; -"User Phrases" = "自訂語彙"; "Edit User Phrases" = "編輯自訂語彙"; "Reload User Phrases" = "重載自訂語彙"; "Unable to create the user phrase file." = "無法創建自訂語彙檔案。";