Fix Plain Bopomofo regression (#71)

This is caused by a missing method. Our implementation for
-[NSObject(IMKServerInput) inputText🔑modifiers:client:] was changed
to handleEvent: in 0.9.5.

Interestingly, calling -inputText🔑modifiers:client: somehow worked
when we linked against OS X 10.7 SDK (that was the SDK the 0.9.5
distribution used). This is no longer true with OS X 10.8 SDK.
This commit is contained in:
Lukhnos Liu 2012-12-12 20:24:28 -08:00
parent fe182ba26b
commit 9448c1af48
1 changed files with 231 additions and 226 deletions

View File

@ -129,6 +129,7 @@ FastLM gLanguageModelPlainBopomofo;
- (void)_showCandidateWindowUsingVerticalMode:(BOOL)useVerticalMode client:(id)client; - (void)_showCandidateWindowUsingVerticalMode:(BOOL)useVerticalMode client:(id)client;
- (void)beep; - (void)beep;
- (BOOL)handleInputText:(NSString*)inputText key:(NSInteger)keyCode modifiers:(NSUInteger)flags client:(id)client;
- (BOOL)handleCandidateEventWithInputText:(NSString *)inputText charCode:(UniChar)charCode keyCode:(NSUInteger)keyCode; - (BOOL)handleCandidateEventWithInputText:(NSString *)inputText charCode:(UniChar)charCode keyCode:(NSUInteger)keyCode;
@end @end
@ -156,7 +157,7 @@ public:
[_composingBuffer release]; [_composingBuffer release];
[_candidates release]; [_candidates release];
// the two client pointers are weak pointers (i.e. we don't retain them) // the two client pointers are weak pointers (i.e. we don't retain them)
// therefore we don't do anything about it // therefore we don't do anything about it
@ -171,7 +172,7 @@ public:
self = [super initWithServer:server delegate:delegate client:client]; self = [super initWithServer:server delegate:delegate client:client];
if (self) { if (self) {
_candidates = [[NSMutableArray alloc] init]; _candidates = [[NSMutableArray alloc] init];
// create the reading buffer // create the reading buffer
_bpmfReadingBuffer = new BopomofoReadingBuffer(BopomofoKeyboardLayout::StandardLayout()); _bpmfReadingBuffer = new BopomofoReadingBuffer(BopomofoKeyboardLayout::StandardLayout());
@ -244,7 +245,7 @@ public:
- (void)activateServer:(id)client - (void)activateServer:(id)client
{ {
[[NSUserDefaults standardUserDefaults] synchronize]; [[NSUserDefaults standardUserDefaults] synchronize];
// reset the state // reset the state
_currentDeferredClient = nil; _currentDeferredClient = nil;
_currentCandidateClient = nil; _currentCandidateClient = nil;
@ -307,7 +308,7 @@ public:
[self commitComposition:client]; [self commitComposition:client];
_currentDeferredClient = nil; _currentDeferredClient = nil;
_currentCandidateClient = nil; _currentCandidateClient = nil;
gCurrentCandidateController.delegate = nil; gCurrentCandidateController.delegate = nil;
gCurrentCandidateController.visible = NO; gCurrentCandidateController.visible = NO;
[_candidates removeAllObjects]; [_candidates removeAllObjects];
@ -339,11 +340,11 @@ public:
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); _builder = new BlockReadingBuilder(_languageModel);
_builder->setJoinSeparator("-"); _builder->setJoinSeparator("-");
} }
} }
@ -434,7 +435,7 @@ public:
// the selection range is where the cursor is, with the length being 0 and replacement range NSNotFound, // the selection range is where the cursor is, with the length being 0 and replacement range NSNotFound,
// i.e. the client app needs to take care of where to put ths composing buffer // i.e. the client app needs to take care of where to put ths composing buffer
[client setMarkedText:attrString selectionRange:NSMakeRange(cursorIndex, 0) replacementRange:NSMakeRange(NSNotFound, NSNotFound)]; [client setMarkedText:attrString selectionRange:NSMakeRange(cursorIndex, 0) replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
_latestReadingCursor = cursorIndex; _latestReadingCursor = cursorIndex;
} }
@ -506,199 +507,14 @@ public:
NSBeep(); NSBeep();
} }
- (BOOL)handleCandidateEventWithInputText:(NSString *)inputText charCode:(UniChar)charCode keyCode:(NSUInteger)keyCode - (BOOL)handleInputText:(NSString*)inputText key:(NSInteger)keyCode modifiers:(NSUInteger)flags client:(id)client
{ {
if (_inputMode == kPlainBopomofoModeIdentifier) {
if (charCode == '<') {
keyCode = kPageUpKeyCode;
}
else if (charCode == '>') {
keyCode = kPageDownKeyCode;
}
}
if (charCode == 27) {
gCurrentCandidateController.visible = NO;
[_candidates removeAllObjects];
if (_inputMode == kPlainBopomofoModeIdentifier) {
_builder->clear();
_walkedNodes.clear();
[_composingBuffer setString:@""];
}
[self updateClientComposingBuffer:_currentCandidateClient];
return YES;
}
else if (charCode == 13 || keyCode == kEnterKeyCode) {
[self candidateController:gCurrentCandidateController didSelectCandidateAtIndex:gCurrentCandidateController.selectedCandidateIndex];
return YES;
}
else if (charCode == 32 || keyCode == kPageDownKeyCode) {
BOOL updated = [gCurrentCandidateController showNextPage];
if (!updated) {
[self beep];
}
return YES;
}
else if (keyCode == kPageUpKeyCode) {
BOOL updated = [gCurrentCandidateController showPreviousPage];
if (!updated) {
[self beep];
}
return YES;
}
else if (keyCode == kLeftKeyCode) {
if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) {
BOOL updated = [gCurrentCandidateController highlightPreviousCandidate];
if (!updated) {
[self beep];
}
return YES;
}
else {
[self beep];
return YES;
}
}
else if (keyCode == kRightKeyCode) {
if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) {
BOOL updated = [gCurrentCandidateController highlightNextCandidate];
if (!updated) {
[self beep];
}
return YES;
}
else {
[self beep];
return YES;
}
}
else if (keyCode == kUpKeyCode) {
if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) {
BOOL updated = [gCurrentCandidateController showPreviousPage];
if (!updated) {
[self beep];
}
return YES;
}
else {
BOOL updated = [gCurrentCandidateController highlightPreviousCandidate];
if (!updated) {
[self beep];
}
return YES;
}
}
else if (keyCode == kDownKeyCode) {
if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) {
BOOL updated = [gCurrentCandidateController showNextPage];
if (!updated) {
[self beep];
}
return YES;
}
else {
BOOL updated = [gCurrentCandidateController highlightNextCandidate];
if (!updated) {
[self beep];
}
return YES;
}
}
else if (keyCode == kHomeKeyCode) {
if (gCurrentCandidateController.selectedCandidateIndex == 0) {
[self beep];
}
else {
gCurrentCandidateController.selectedCandidateIndex = 0;
}
return YES;
}
else if (keyCode == kEndKeyCode && [_candidates count] > 0) {
if (gCurrentCandidateController.selectedCandidateIndex == [_candidates count] - 1) {
[self beep];
}
else {
gCurrentCandidateController.selectedCandidateIndex = [_candidates count] - 1;
}
return YES;
}
else {
NSInteger index = NSNotFound;
for (NSUInteger j = 0, c = [gCurrentCandidateController.keyLabels count]; j < c; j++) {
if ([inputText compare:[gCurrentCandidateController.keyLabels objectAtIndex:j] options:NSCaseInsensitiveSearch] == NSOrderedSame) {
index = j;
break;
}
}
[gCurrentCandidateController.keyLabels indexOfObject:inputText];
if (index != NSNotFound) {
NSUInteger candidateIndex = [gCurrentCandidateController candidateIndexAtKeyLabelIndex:index];
if (candidateIndex != NSUIntegerMax) {
[self candidateController:gCurrentCandidateController didSelectCandidateAtIndex:candidateIndex];
return YES;
}
}
if (_inputMode == kPlainBopomofoModeIdentifier) {
if (_bpmfReadingBuffer->isValidKey((char)charCode)) {
NSUInteger candidateIndex = [gCurrentCandidateController candidateIndexAtKeyLabelIndex:0];
if (candidateIndex != NSUIntegerMax) {
[self candidateController:gCurrentCandidateController didSelectCandidateAtIndex:candidateIndex];
return [self inputText:inputText key:keyCode modifiers:0 client:_currentCandidateClient];
}
}
}
[self beep];
return YES;
}
}
- (NSUInteger)recognizedEvents:(id)sender
{
return NSKeyDownMask | NSFlagsChangedMask;
}
- (BOOL)handleEvent:(NSEvent *)event client:(id)client
{
if ([event type] == NSFlagsChanged) {
// function key pressed
BOOL includeShift = [[NSUserDefaults standardUserDefaults] boolForKey:kFunctionKeyKeyboardLayoutOverrideIncludeShiftKey];
if (([event modifierFlags] & ~NSShiftKeyMask) || (([event modifierFlags] & NSShiftKeyMask) && includeShift)) {
NSString *functionKeyKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kFunctionKeyKeyboardLayoutPreferenceKey];
if (!functionKeyKeyboardLayoutID) {
functionKeyKeyboardLayoutID = @"com.apple.keylayout.US";
}
[client overrideKeyboardWithKeyboardNamed:functionKeyKeyboardLayoutID];
return NO;
}
// reset when function key is released
NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey];
if (!basisKeyboardLayoutID) {
basisKeyboardLayoutID = @"com.apple.keylayout.US";
}
[client overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID];
return NO;
}
NSString *inputText = [event characters];
NSInteger keyCode = [event keyCode];
NSUInteger flags = [event modifierFlags];
NSRect textFrame = NSZeroRect; NSRect textFrame = NSZeroRect;
NSDictionary *attributes = nil; NSDictionary *attributes = nil;
bool composeReading = false; bool composeReading = false;
BOOL useVerticalMode = NO; BOOL useVerticalMode = NO;
@try { @try {
attributes = [client attributesForCharacterIndex:0 lineHeightRectangle:&textFrame]; attributes = [client attributesForCharacterIndex:0 lineHeightRectangle:&textFrame];
useVerticalMode = [attributes objectForKey:@"IMKTextOrientation"] && [[attributes objectForKey:@"IMKTextOrientation"] integerValue] == 0; useVerticalMode = [attributes objectForKey:@"IMKTextOrientation"] && [[attributes objectForKey:@"IMKTextOrientation"] integerValue] == 0;
@ -741,24 +557,24 @@ public:
if ([_composingBuffer length]) { if ([_composingBuffer length]) {
[self commitComposition:client]; [self commitComposition:client];
} }
// first commit everything in the buffer. // first commit everything in the buffer.
if (flags & NSShiftKeyMask) { if (flags & NSShiftKeyMask) {
return NO; return NO;
} }
// when shift is pressed, don't do further processing, since it outputs capital letter anyway. // when shift is pressed, don't do further processing, since it outputs capital letter anyway.
NSString *popedText = [inputText lowercaseString]; NSString *popedText = [inputText lowercaseString];
[client insertText:popedText replacementRange:NSMakeRange(NSNotFound, NSNotFound)]; [client insertText:popedText replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
return YES; return YES;
} }
if (flags & NSNumericPadKeyMask) { if (flags & NSNumericPadKeyMask) {
if (keyCode != kLeftKeyCode && keyCode != kRightKeyCode && keyCode != kDownKeyCode && keyCode != kUpKeyCode && charCode != 32 && isprint(charCode)) { if (keyCode != kLeftKeyCode && keyCode != kRightKeyCode && keyCode != kDownKeyCode && keyCode != kUpKeyCode && charCode != 32 && isprint(charCode)) {
if ([_composingBuffer length]) { if ([_composingBuffer length]) {
[self commitComposition:client]; [self commitComposition:client];
} }
NSString *popedText = [inputText lowercaseString]; NSString *popedText = [inputText lowercaseString];
[client insertText:popedText replacementRange:NSMakeRange(NSNotFound, NSNotFound)]; [client insertText:popedText replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
return YES; return YES;
@ -769,7 +585,7 @@ public:
if ([_candidates count]) { if ([_candidates count]) {
return [self handleCandidateEventWithInputText:inputText charCode:charCode keyCode:keyCode]; return [self handleCandidateEventWithInputText:inputText charCode:charCode keyCode:keyCode];
} }
// see if it's valid BPMF reading // see if it's valid BPMF reading
if (_bpmfReadingBuffer->isValidKey((char)charCode)) { if (_bpmfReadingBuffer->isValidKey((char)charCode)) {
_bpmfReadingBuffer->combineKey((char)charCode); _bpmfReadingBuffer->combineKey((char)charCode);
@ -852,10 +668,10 @@ public:
// Esc // Esc
if (charCode == 27) { if (charCode == 27) {
// if reading is not empty, we cancel the reading; Apple's built-in Zhuyin (and the erstwhile Hanin) has a default option that Esc "cancels" the current composed character and revert it to Bopomofo reading, in odds with the expectation of users from other platforms // if reading is not empty, we cancel the reading; Apple's built-in Zhuyin (and the erstwhile Hanin) has a default option that Esc "cancels" the current composed character and revert it to Bopomofo reading, in odds with the expectation of users from other platforms
if (_bpmfReadingBuffer->isEmpty()) { if (_bpmfReadingBuffer->isEmpty()) {
// no nee to beep since the event is deliberately triggered by user // no nee to beep since the event is deliberately triggered by user
if (![_composingBuffer length]) { if (![_composingBuffer length]) {
return NO; return NO;
} }
@ -1121,6 +937,195 @@ public:
return NO; return NO;
} }
- (BOOL)handleCandidateEventWithInputText:(NSString *)inputText charCode:(UniChar)charCode keyCode:(NSUInteger)keyCode
{
if (_inputMode == kPlainBopomofoModeIdentifier) {
if (charCode == '<') {
keyCode = kPageUpKeyCode;
}
else if (charCode == '>') {
keyCode = kPageDownKeyCode;
}
}
if (charCode == 27) {
gCurrentCandidateController.visible = NO;
[_candidates removeAllObjects];
if (_inputMode == kPlainBopomofoModeIdentifier) {
_builder->clear();
_walkedNodes.clear();
[_composingBuffer setString:@""];
}
[self updateClientComposingBuffer:_currentCandidateClient];
return YES;
}
else if (charCode == 13 || keyCode == kEnterKeyCode) {
[self candidateController:gCurrentCandidateController didSelectCandidateAtIndex:gCurrentCandidateController.selectedCandidateIndex];
return YES;
}
else if (charCode == 32 || keyCode == kPageDownKeyCode) {
BOOL updated = [gCurrentCandidateController showNextPage];
if (!updated) {
[self beep];
}
return YES;
}
else if (keyCode == kPageUpKeyCode) {
BOOL updated = [gCurrentCandidateController showPreviousPage];
if (!updated) {
[self beep];
}
return YES;
}
else if (keyCode == kLeftKeyCode) {
if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) {
BOOL updated = [gCurrentCandidateController highlightPreviousCandidate];
if (!updated) {
[self beep];
}
return YES;
}
else {
[self beep];
return YES;
}
}
else if (keyCode == kRightKeyCode) {
if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) {
BOOL updated = [gCurrentCandidateController highlightNextCandidate];
if (!updated) {
[self beep];
}
return YES;
}
else {
[self beep];
return YES;
}
}
else if (keyCode == kUpKeyCode) {
if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) {
BOOL updated = [gCurrentCandidateController showPreviousPage];
if (!updated) {
[self beep];
}
return YES;
}
else {
BOOL updated = [gCurrentCandidateController highlightPreviousCandidate];
if (!updated) {
[self beep];
}
return YES;
}
}
else if (keyCode == kDownKeyCode) {
if ([gCurrentCandidateController isKindOfClass:[VTHorizontalCandidateController class]]) {
BOOL updated = [gCurrentCandidateController showNextPage];
if (!updated) {
[self beep];
}
return YES;
}
else {
BOOL updated = [gCurrentCandidateController highlightNextCandidate];
if (!updated) {
[self beep];
}
return YES;
}
}
else if (keyCode == kHomeKeyCode) {
if (gCurrentCandidateController.selectedCandidateIndex == 0) {
[self beep];
}
else {
gCurrentCandidateController.selectedCandidateIndex = 0;
}
return YES;
}
else if (keyCode == kEndKeyCode && [_candidates count] > 0) {
if (gCurrentCandidateController.selectedCandidateIndex == [_candidates count] - 1) {
[self beep];
}
else {
gCurrentCandidateController.selectedCandidateIndex = [_candidates count] - 1;
}
return YES;
}
else {
NSInteger index = NSNotFound;
for (NSUInteger j = 0, c = [gCurrentCandidateController.keyLabels count]; j < c; j++) {
if ([inputText compare:[gCurrentCandidateController.keyLabels objectAtIndex:j] options:NSCaseInsensitiveSearch] == NSOrderedSame) {
index = j;
break;
}
}
[gCurrentCandidateController.keyLabels indexOfObject:inputText];
if (index != NSNotFound) {
NSUInteger candidateIndex = [gCurrentCandidateController candidateIndexAtKeyLabelIndex:index];
if (candidateIndex != NSUIntegerMax) {
[self candidateController:gCurrentCandidateController didSelectCandidateAtIndex:candidateIndex];
return YES;
}
}
if (_inputMode == kPlainBopomofoModeIdentifier) {
if (_bpmfReadingBuffer->isValidKey((char)charCode)) {
NSUInteger candidateIndex = [gCurrentCandidateController candidateIndexAtKeyLabelIndex:0];
if (candidateIndex != NSUIntegerMax) {
[self candidateController:gCurrentCandidateController didSelectCandidateAtIndex:candidateIndex];
return [self handleInputText:inputText key:keyCode modifiers:0 client:_currentCandidateClient];
}
}
}
[self beep];
return YES;
}
}
- (NSUInteger)recognizedEvents:(id)sender
{
return NSKeyDownMask | NSFlagsChangedMask;
}
- (BOOL)handleEvent:(NSEvent *)event client:(id)client
{
if ([event type] == NSFlagsChanged) {
// function key pressed
BOOL includeShift = [[NSUserDefaults standardUserDefaults] boolForKey:kFunctionKeyKeyboardLayoutOverrideIncludeShiftKey];
if (([event modifierFlags] & ~NSShiftKeyMask) || (([event modifierFlags] & NSShiftKeyMask) && includeShift)) {
NSString *functionKeyKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kFunctionKeyKeyboardLayoutPreferenceKey];
if (!functionKeyKeyboardLayoutID) {
functionKeyKeyboardLayoutID = @"com.apple.keylayout.US";
}
[client overrideKeyboardWithKeyboardNamed:functionKeyKeyboardLayoutID];
return NO;
}
// reset when function key is released
NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey];
if (!basisKeyboardLayoutID) {
basisKeyboardLayoutID = @"com.apple.keylayout.US";
}
[client overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID];
return NO;
}
NSString *inputText = [event characters];
NSInteger keyCode = [event keyCode];
NSUInteger flags = [event modifierFlags];
return [self handleInputText:inputText key:keyCode modifiers:flags client:client];
}
#pragma mark - Private methods #pragma mark - Private methods
+ (VTHorizontalCandidateController *)horizontalCandidateController + (VTHorizontalCandidateController *)horizontalCandidateController
@ -1131,7 +1136,7 @@ public:
instance = [[VTHorizontalCandidateController alloc] init]; instance = [[VTHorizontalCandidateController alloc] init];
} }
} }
return instance; return instance;
} }
@ -1143,21 +1148,21 @@ public:
instance = [[VTVerticalCandidateController alloc] init]; instance = [[VTVerticalCandidateController alloc] init];
} }
} }
return instance; return instance;
} }
- (void)collectCandidates - (void)collectCandidates
{ {
// returns the candidate // returns the candidate
[_candidates removeAllObjects]; [_candidates removeAllObjects];
size_t cursorIndex = [self actualCandidateCursorIndex]; size_t cursorIndex = [self actualCandidateCursorIndex];
vector<NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex); vector<NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex);
// sort the nodes, so that longer nodes (representing longer phrases) are placed at the top of the candidate list // sort the nodes, so that longer nodes (representing longer phrases) are placed at the top of the candidate list
stable_sort(nodes.begin(), nodes.end(), NodeAnchorDescendingSorter()); stable_sort(nodes.begin(), nodes.end(), NodeAnchorDescendingSorter());
// then use the C++ trick to retrieve the candidates for each node at/crossing the cursor // then use the C++ trick to retrieve the candidates for each node at/crossing the cursor
for (vector<NodeAnchor>::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) { for (vector<NodeAnchor>::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) {
const vector<KeyValuePair>& candidates = (*ni).node->candidates(); const vector<KeyValuePair>& candidates = (*ni).node->candidates();
@ -1277,28 +1282,28 @@ public:
// set the attributes for the candidate panel (which uses NSAttributedString) // set the attributes for the candidate panel (which uses NSAttributedString)
NSInteger textSize = [[NSUserDefaults standardUserDefaults] integerForKey:kCandidateListTextSizeKey]; NSInteger textSize = [[NSUserDefaults standardUserDefaults] integerForKey:kCandidateListTextSizeKey];
NSInteger keyLabelSize = textSize / 2; NSInteger keyLabelSize = textSize / 2;
if (keyLabelSize < kMinKeyLabelSize) { if (keyLabelSize < kMinKeyLabelSize) {
keyLabelSize = kMinKeyLabelSize; keyLabelSize = kMinKeyLabelSize;
} }
NSString *ctFontName = [[NSUserDefaults standardUserDefaults] stringForKey:kCandidateTextFontName]; NSString *ctFontName = [[NSUserDefaults standardUserDefaults] stringForKey:kCandidateTextFontName];
NSString *klFontName = [[NSUserDefaults standardUserDefaults] stringForKey:kCandidateKeyLabelFontName]; NSString *klFontName = [[NSUserDefaults standardUserDefaults] stringForKey:kCandidateKeyLabelFontName];
NSString *ckeys = [[NSUserDefaults standardUserDefaults] stringForKey:kCandidateKeys]; NSString *ckeys = [[NSUserDefaults standardUserDefaults] stringForKey:kCandidateKeys];
gCurrentCandidateController.keyLabelFont = klFontName ? [NSFont fontWithName:klFontName size:keyLabelSize] : [NSFont systemFontOfSize:keyLabelSize]; gCurrentCandidateController.keyLabelFont = klFontName ? [NSFont fontWithName:klFontName size:keyLabelSize] : [NSFont systemFontOfSize:keyLabelSize];
gCurrentCandidateController.candidateFont = ctFontName ? [NSFont fontWithName:ctFontName size:textSize] : [NSFont systemFontOfSize:textSize]; gCurrentCandidateController.candidateFont = ctFontName ? [NSFont fontWithName:ctFontName size:textSize] : [NSFont systemFontOfSize:textSize];
NSMutableArray *keyLabels = [NSMutableArray arrayWithObjects:@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", nil]; NSMutableArray *keyLabels = [NSMutableArray arrayWithObjects:@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", nil];
if ([ckeys length] > 1) { if ([ckeys length] > 1) {
[keyLabels removeAllObjects]; [keyLabels removeAllObjects];
for (NSUInteger i = 0, c = [ckeys length]; i < c; i++) { for (NSUInteger i = 0, c = [ckeys length]; i < c; i++) {
[keyLabels addObject:[ckeys substringWithRange:NSMakeRange(i, 1)]]; [keyLabels addObject:[ckeys substringWithRange:NSMakeRange(i, 1)]];
} }
} }
gCurrentCandidateController.keyLabels = keyLabels; gCurrentCandidateController.keyLabels = keyLabels;
[self collectCandidates]; [self collectCandidates];
@ -1306,7 +1311,7 @@ public:
[self commitComposition:client]; [self commitComposition:client];
return; return;
} }
gCurrentCandidateController.delegate = self; gCurrentCandidateController.delegate = self;
[gCurrentCandidateController reloadData]; [gCurrentCandidateController reloadData];
@ -1314,13 +1319,13 @@ public:
[self updateClientComposingBuffer:client]; [self updateClientComposingBuffer:client];
_currentCandidateClient = client; _currentCandidateClient = client;
NSRect lineHeightRect = NSMakeRect(0.0, 0.0, 16.0, 16.0); NSRect lineHeightRect = NSMakeRect(0.0, 0.0, 16.0, 16.0);
NSInteger cursor = _latestReadingCursor; NSInteger cursor = _latestReadingCursor;
if (cursor == [_composingBuffer length] && cursor != 0) { if (cursor == [_composingBuffer length] && cursor != 0) {
cursor--; cursor--;
} }
// some apps (e.g. Twitter for Mac's search bar) handle this call incorrectly, hence the try-catch // some apps (e.g. Twitter for Mac's search bar) handle this call incorrectly, hence the try-catch
@try { @try {
[client attributesForCharacterIndex:cursor lineHeightRectangle:&lineHeightRect]; [client attributesForCharacterIndex:cursor lineHeightRectangle:&lineHeightRect];
@ -1335,7 +1340,7 @@ public:
else { else {
[gCurrentCandidateController setWindowTopLeftPoint:NSMakePoint(lineHeightRect.origin.x, lineHeightRect.origin.y - 4.0) bottomOutOfScreenAdjustmentHeight:lineHeightRect.size.height + 4.0]; [gCurrentCandidateController setWindowTopLeftPoint:NSMakePoint(lineHeightRect.origin.x, lineHeightRect.origin.y - 4.0) bottomOutOfScreenAdjustmentHeight:lineHeightRect.size.height + 4.0];
} }
gCurrentCandidateController.visible = YES; gCurrentCandidateController.visible = YES;
} }
@ -1385,23 +1390,23 @@ public:
- (void)candidateController:(VTCandidateController *)controller didSelectCandidateAtIndex:(NSUInteger)index - (void)candidateController:(VTCandidateController *)controller didSelectCandidateAtIndex:(NSUInteger)index
{ {
gCurrentCandidateController.visible = NO; gCurrentCandidateController.visible = NO;
// candidate selected, override the node with selection // candidate selected, override the node with selection
string selectedValue = [[_candidates objectAtIndex:index] UTF8String]; string selectedValue = [[_candidates objectAtIndex:index] UTF8String];
if (![[NSUserDefaults standardUserDefaults] boolForKey:kDisableUserCandidateSelectionLearning]) { if (![[NSUserDefaults standardUserDefaults] boolForKey:kDisableUserCandidateSelectionLearning]) {
NSString *trigram = [self neighborTrigramString]; NSString *trigram = [self neighborTrigramString];
NSString *selectedNSString = [NSString stringWithUTF8String:selectedValue.c_str()]; NSString *selectedNSString = [NSString stringWithUTF8String:selectedValue.c_str()];
[gCandidateLearningDictionary setObject:selectedNSString forKey:trigram]; [gCandidateLearningDictionary setObject:selectedNSString forKey:trigram];
[self saveUserCandidatesDictionary]; [self saveUserCandidatesDictionary];
} }
size_t cursorIndex = [self actualCandidateCursorIndex]; size_t cursorIndex = [self actualCandidateCursorIndex];
vector<NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex); vector<NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex);
for (vector<NodeAnchor>::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) { for (vector<NodeAnchor>::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni) {
const vector<KeyValuePair>& candidates = (*ni).node->candidates(); const vector<KeyValuePair>& candidates = (*ni).node->candidates();
for (size_t i = 0, c = candidates.size(); i < c; ++i) { for (size_t i = 0, c = candidates.size(); i < c; ++i) {
if (candidates[i].value == selectedValue) { if (candidates[i].value == selectedValue) {
// found our node // found our node
@ -1410,9 +1415,9 @@ public:
} }
} }
} }
[_candidates removeAllObjects]; [_candidates removeAllObjects];
[self walk]; [self walk];
[self updateClientComposingBuffer:_currentCandidateClient]; [self updateClientComposingBuffer:_currentCandidateClient];
@ -1438,7 +1443,7 @@ void LTLoadLanguageModel()
{ {
LTLoadLanguageModelFile(@"data", gLanguageModel); LTLoadLanguageModelFile(@"data", gLanguageModel);
LTLoadLanguageModelFile(@"data-plain-bpmf", gLanguageModelPlainBopomofo); LTLoadLanguageModelFile(@"data-plain-bpmf", gLanguageModelPlainBopomofo);
// initialize the singleton learning dictionary // initialize the singleton learning dictionary
// putting singleton in @synchronized is the standard way in Objective-C // putting singleton in @synchronized is the standard way in Objective-C