Shiki #13: UserPhrases // CHS mode compatibility.

- Also remove useless menu entry.
This commit is contained in:
ShikiSuen 2022-01-11 22:59:39 +08:00
parent 1bb6cb9d82
commit ea356d6d67
6 changed files with 213 additions and 124 deletions

View File

@ -42,7 +42,8 @@
#import "frmAboutWindow.h" #import "frmAboutWindow.h"
extern void LTLoadLanguageModel(void); extern void LTLoadLanguageModel(void);
extern void LTLoadUserLanguageModelFile(void); extern void LTLoadUserLanguageModelFileCHT(void);
extern void LTLoadUserLanguageModelFileCHS(void);
static NSString *kCheckUpdateAutomatically = @"CheckUpdateAutomatically"; static NSString *kCheckUpdateAutomatically = @"CheckUpdateAutomatically";
static NSString *kNextUpdateCheckDateKey = @"NextUpdateCheckDate"; static NSString *kNextUpdateCheckDateKey = @"NextUpdateCheckDate";
@ -67,9 +68,10 @@ static const NSTimeInterval kTimeoutInterval = 60.0;
- (void)applicationDidFinishLaunching:(NSNotification *)inNotification - (void)applicationDidFinishLaunching:(NSNotification *)inNotification
{ {
LTLoadLanguageModel(); LTLoadLanguageModel();
LTLoadUserLanguageModelFile(); LTLoadUserLanguageModelFileCHT();
LTLoadUserLanguageModelFileCHS();
if (![[NSUserDefaults standardUserDefaults] objectForKey:kCheckUpdateAutomatically]) { if (![[NSUserDefaults standardUserDefaults] objectForKey:kCheckUpdateAutomatically]) {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:kCheckUpdateAutomatically]; [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kCheckUpdateAutomatically];
[[NSUserDefaults standardUserDefaults] synchronize]; [[NSUserDefaults standardUserDefaults] synchronize];
} }

View File

@ -89,4 +89,5 @@
// the shared language model object // the shared language model object
extern "C" void LTLoadLanguageModel(); extern "C" void LTLoadLanguageModel();
extern "C" void LTLoadUserLanguageModelFile(); extern "C" void LTLoadUserLanguageModelFileCHT();
extern "C" void LTLoadUserLanguageModelFileCHS();

View File

@ -141,48 +141,52 @@ static NSString *LTUserPhrasesDataPathCHT()
return [LTUserDataFolderPath() stringByAppendingPathComponent:@"userdata-cht.txt"]; return [LTUserDataFolderPath() stringByAppendingPathComponent:@"userdata-cht.txt"];
} }
// static NSString *LTUserPhrasesDataPathCHS() static NSString *LTUserPhrasesDataPathCHS()
// { {
// return [LTUserDataFolderPath() stringByAppendingPathComponent:@"userdata-chs.txt"]; return [LTUserDataFolderPath() stringByAppendingPathComponent:@"userdata-chs.txt"];
// } }
static BOOL LTCheckIfUserLanguageModelFileExists() { static BOOL LTCheckIfUserLanguageModelFileExists() {
NSString *folderPath = LTUserDataFolderPath(); NSString *folderPath = LTUserDataFolderPath();
BOOL isFolder = NO; BOOL isFolder = NO;
BOOL folderExist = [[NSFileManager defaultManager] fileExistsAtPath:folderPath isDirectory:&isFolder]; BOOL folderExist = [[NSFileManager defaultManager] fileExistsAtPath:folderPath isDirectory:&isFolder];
if (folderExist && !isFolder) { if (folderExist && !isFolder) {
NSError *error = nil; NSError *error = nil;
[[NSFileManager defaultManager] removeItemAtPath:folderPath error:&error]; [[NSFileManager defaultManager] removeItemAtPath:folderPath error:&error];
if (error) { if (error) {
NSLog(@"Failed to remove folder %@", error); NSLog(@"Failed to remove folder %@", error);
return NO; return NO;
} }
folderExist = NO; folderExist = NO;
} }
if (!folderExist) { if (!folderExist) {
NSError *error = nil; NSError *error = nil;
[[NSFileManager defaultManager] createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:&error]; [[NSFileManager defaultManager] createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:&error];
if (error) { if (error) {
NSLog(@"Failed to create folder %@", error); NSLog(@"Failed to create folder %@", error);
return NO; return NO;
} }
} }
NSString *filePathCHS = LTUserPhrasesDataPathCHS();
NSString *filePath = LTUserPhrasesDataPathCHT(); if (![[NSFileManager defaultManager] fileExistsAtPath:filePathCHS]) {
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) { BOOL result = [[@"" dataUsingEncoding:NSUTF8StringEncoding] writeToFile:filePathCHS atomically:YES];
BOOL result = [[@"" dataUsingEncoding:NSUTF8StringEncoding] writeToFile:filePath atomically:YES]; if (!result) {
if (!result) { NSLog(@"Failed to write userdict CHS file");
NSLog(@"Failed to write file"); return NO;
return NO; }
} }
} NSString *filePathCHT = LTUserPhrasesDataPathCHT();
return YES; 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 // https://clang-analyzer.llvm.org/faq.html
__attribute__((annotate("returns_localized_nsstring"))) __attribute__((annotate("returns_localized_nsstring")))
static inline NSString *LocalizationNotNeeded(NSString *s) { static inline NSString *LocalizationNotNeeded(NSString *s) {
@ -260,7 +264,13 @@ static double FindHighestScore(const vector<NodeAnchor>& nodes, double epsilon)
_languageModel = &gLanguageModelCHT; _languageModel = &gLanguageModelCHT;
_userPhrasesModel = &gUserPhraseLanguageModelCHT; _userPhrasesModel = &gUserPhraseLanguageModelCHT;
_builder = new BlockReadingBuilder(_languageModel, _userPhrasesModel); _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 // each Mandarin syllable is separated by a hyphen
_builder->setJoinSeparator("-"); _builder->setJoinSeparator("-");
@ -291,28 +301,26 @@ static double FindHighestScore(const vector<NodeAnchor>& nodes, double epsilon)
chineseConversionMenuItem.state = _chineseConversionEnabled ? NSControlStateValueOn : NSControlStateValueOff; chineseConversionMenuItem.state = _chineseConversionEnabled ? NSControlStateValueOn : NSControlStateValueOff;
[menu addItem:chineseConversionMenuItem]; [menu addItem:chineseConversionMenuItem];
// Needs improvement for Simplified Chinese Input [menu addItem:[NSMenuItem separatorItem]]; // -----------------------
if (_inputMode != kSimpBopomofoModeIdentifier) {
[menu addItem:[NSMenuItem separatorItem]]; NSMenuItem *editUserPheaseItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Edit User Phrases", @"") action:@selector(openUserPhrases:) keyEquivalent:@""];
[menu addItemWithTitle:NSLocalizedString(@"User Phrases", @"") action:NULL keyEquivalent:@""]; [editUserPheaseItem setIndentationLevel:2];
NSMenuItem *editUserPheaseItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Edit User Phrases", @"") action:@selector(openUserPhrases:) keyEquivalent:@""]; [menu addItem:editUserPheaseItem];
[editUserPheaseItem setIndentationLevel:2];
[menu addItem:editUserPheaseItem];
NSMenuItem *reloadUserPheaseItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Reload User Phrases", @"") action:@selector(reloadUserPhrases:) keyEquivalent:@""]; NSMenuItem *reloadUserPheaseItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Reload User Phrases", @"") action:@selector(reloadUserPhrases:) keyEquivalent:@""];
[reloadUserPheaseItem setIndentationLevel:2]; [reloadUserPheaseItem setIndentationLevel:2];
[menu addItem:reloadUserPheaseItem]; [menu addItem:reloadUserPheaseItem];
[menu addItem:[NSMenuItem separatorItem]];
} [menu addItem:[NSMenuItem separatorItem]]; // -----------------------
NSMenuItem *updateCheckItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Check for Updates…", @"") action:@selector(checkForUpdate:) keyEquivalent:@""]; NSMenuItem *updateCheckItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Check for Updates…", @"") action:@selector(checkForUpdate:) keyEquivalent:@""];
[menu addItem:updateCheckItem]; [menu addItem:updateCheckItem];
NSMenuItem *aboutMenuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"About vChewing…", @"") action:@selector(showAbout:) keyEquivalent:@""]; NSMenuItem *aboutMenuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"About vChewing…", @"") action:@selector(showAbout:) keyEquivalent:@""];
[menu addItem:aboutMenuItem]; [menu addItem:aboutMenuItem];
// Menu Debug Purposes... // Menu Debug Purposes...
NSLog(@"menu %@", menu); NSLog(@"menu %@", menu);
return menu; return menu;
} }
@ -410,46 +418,85 @@ static double FindHighestScore(const vector<NodeAnchor>& nodes, double epsilon)
NSString *newInputMode; NSString *newInputMode;
Formosa::Gramambular::FastLM *newLanguageModel; Formosa::Gramambular::FastLM *newLanguageModel;
Formosa::Gramambular::FastLM *userPhraseModel; Formosa::Gramambular::FastLM *userPhraseModel;
vChewing::UserOverrideModel *newUom;
if ([value isKindOfClass:[NSString class]] && [value isEqual:kSimpBopomofoModeIdentifier]) { if ([value isKindOfClass:[NSString class]]) {
newInputMode = kSimpBopomofoModeIdentifier;
newLanguageModel = &gLanguageModelCHS; if ([value isEqual:kSimpBopomofoModeIdentifier]) {
userPhraseModel = &gUserPhraseLanguageModelCHS;
} newInputMode = kSimpBopomofoModeIdentifier;
else { newLanguageModel = &gLanguageModelCHS;
newInputMode = kBopomofoModeIdentifier; newUom = &gUserOverrideModelCHS;
newLanguageModel = &gLanguageModelCHT; userPhraseModel = &gUserPhraseLanguageModelCHS;
userPhraseModel = &gUserPhraseLanguageModelCHT;
}
// Only apply the changes if the value is changed if (![_inputMode isEqualToString:newInputMode]) {
if (![_inputMode isEqualToString:newInputMode]) { [[NSUserDefaults standardUserDefaults] synchronize];
[[NSUserDefaults standardUserDefaults] synchronize];
// Remember to override the keyboard layout again -- treat this as an activate event // Remember to override the keyboard layout again -- treat this as an activate event
NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey]; NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey];
if (!basisKeyboardLayoutID) { if (!basisKeyboardLayoutID) {
basisKeyboardLayoutID = @"com.apple.keylayout.US"; basisKeyboardLayoutID = @"com.apple.keylayout.US";
} }
[sender overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID]; [sender overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID];
_inputMode = newInputMode; _inputMode = newInputMode;
_languageModel = newLanguageModel; _languageModel = newLanguageModel;
_userPhrasesModel = userPhraseModel; _userPhrasesModel = userPhraseModel;
if (!_bpmfReadingBuffer->isEmpty()) { if (!_bpmfReadingBuffer->isEmpty()) {
_bpmfReadingBuffer->clear(); _bpmfReadingBuffer->clear();
[self updateClientComposingBuffer:sender]; [self updateClientComposingBuffer:sender];
} }
if ([_composingBuffer length] > 0) { if ([_composingBuffer length] > 0) {
[self commitComposition:sender]; [self commitComposition:sender];
} }
if (_builder) { if (_builder) {
delete _builder; delete _builder;
_builder = new BlockReadingBuilder(_languageModel, _userPhrasesModel); _builder = new BlockReadingBuilder(_languageModel, _userPhrasesModel);
_builder->setJoinSeparator("-"); _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 - (BOOL)_writeUserPhrase
{ {
if (!LTCheckIfUserLanguageModelFileExists()) { if (!LTCheckIfUserLanguageModelFileExists()) {
return NO; return NO;
} }
NSString *currentMarkedPhrase = [self _currentMarkedText]; NSString *currentMarkedPhrase = [self _currentMarkedText];
if (![currentMarkedPhrase length]) { if (![currentMarkedPhrase length]) {
return NO; return NO;
} }
currentMarkedPhrase = [currentMarkedPhrase stringByAppendingString:@"\n"]; currentMarkedPhrase = [currentMarkedPhrase stringByAppendingString:@"\n"];
NSString *path = LTUserPhrasesDataPathCHT();
NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:path]; if (_inputMode == kSimpBopomofoModeIdentifier) {
if (!file) { NSString *path = LTUserPhrasesDataPathCHS();
return NO; 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 - (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 - (void)openUserPhrases:(id)sender
{ {
NSLog(@"openUserPhrases called"); NSLog(@"openUserPhrases called");
if (!LTCheckIfUserLanguageModelFileExists()) { if (!LTCheckIfUserLanguageModelFileExists()) {
NSString *content = [NSString stringWithFormat:NSLocalizedString(@"Please check the permission of at \"%@\".", @""), LTUserDataFolderPath()]; 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]; [[OVNonModalAlertWindowController sharedInstance] showWithTitle:NSLocalizedString(@"Unable to create the user phrase file.", @"") content:content confirmButtonTitle:NSLocalizedString(@"OK", @"") cancelButtonTitle:nil cancelAsDefault:NO delegate:nil];
return; return;
}
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]; 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 - (void)reloadUserPhrases:(id)sender
{ {
NSLog(@"reloadUserPhrases called"); if (_inputMode == kSimpBopomofoModeIdentifier) {
LTLoadUserLanguageModelFile(); NSLog(@"reloadUserPhrases CHS called");
LTLoadUserLanguageModelFileCHS();
} else {
NSLog(@"reloadUserPhrases CHT called");
LTLoadUserLanguageModelFileCHT();
}
} }
- (void)showAbout:(id)sender - (void)showAbout:(id)sender
@ -1655,7 +1735,7 @@ void LTLoadLanguageModel()
LTLoadLanguageModelFile(@"data-chs", gLanguageModelCHS); LTLoadLanguageModelFile(@"data-chs", gLanguageModelCHS);
} }
void LTLoadUserLanguageModelFile() void LTLoadUserLanguageModelFileCHT()
{ {
gUserPhraseLanguageModelCHT.close(); gUserPhraseLanguageModelCHT.close();
bool result = gUserPhraseLanguageModelCHT.open([LTUserPhrasesDataPathCHT() UTF8String]); bool result = gUserPhraseLanguageModelCHT.open([LTUserPhrasesDataPathCHT() UTF8String]);
@ -1663,3 +1743,12 @@ void LTLoadUserLanguageModelFile()
NSLog(@"Failed opening language model for CHT user phrases."); 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.");
}
}

View File

@ -19,7 +19,6 @@
"Chinese Conversion" = "Convert zh-TW Kanji to KangXi Variants"; "Chinese Conversion" = "Convert zh-TW Kanji to KangXi Variants";
"NotificationSwitchON" = " ON"; "NotificationSwitchON" = " ON";
"NotificationSwitchOFF" = " OFF"; "NotificationSwitchOFF" = " OFF";
"User Phrases" = "User Phrases";
"Edit User Phrases" = "Edit User Phrases"; "Edit User Phrases" = "Edit User Phrases";
"Reload User Phrases" = "Reload User Phrases"; "Reload User Phrases" = "Reload User Phrases";
"Unable to create the user phrase file." = "Unable to create the user phrase file."; "Unable to create the user phrase file." = "Unable to create the user phrase file.";

View File

@ -19,7 +19,6 @@
"Chinese Conversion" = "优先使用康熙繁体字"; "Chinese Conversion" = "优先使用康熙繁体字";
"NotificationSwitchON" = " 已启用"; "NotificationSwitchON" = " 已启用";
"NotificationSwitchOFF" = " 已停用"; "NotificationSwitchOFF" = " 已停用";
"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." = "无法创建自订语汇档案。";

View File

@ -19,7 +19,6 @@
"Chinese Conversion" = "優先使用康熙繁體字"; "Chinese Conversion" = "優先使用康熙繁體字";
"NotificationSwitchON" = " 已啟用"; "NotificationSwitchON" = " 已啟用";
"NotificationSwitchOFF" = " 已停用"; "NotificationSwitchOFF" = " 已停用";
"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." = "無法創建自訂語彙檔案。";