Extract the candidate handler; handle subtleties of vertical text mode.

Now both Left and Right can be used as choose-candidate key. Also the
candidate window now doesn't obscure the vertical text being typed by
moving to the right to the vertical text. Because of this, Left key
feels strange. Adding Right key should give a better mental model.
This commit is contained in:
Lukhnos D. Liu 2012-05-06 16:19:33 -07:00
parent c48d478b4e
commit ddbd94bee4
1 changed files with 175 additions and 152 deletions

View File

@ -118,6 +118,9 @@ SimpleLM gLanguageModel;
- (void)_performDeferredSaveUserCandidatesDictionary;
- (void)saveUserCandidatesDictionary;
- (void)_showCandidateWindowUsingVerticalMode:(BOOL)useVerticalMode client:(id)client;
- (void)beep;
- (BOOL)handleCandidateEventWithInputText:(NSString *)inputText charCode:(UniChar)charCode keyCode:(NSUInteger)keyCode;
@end
// sort helper
@ -457,72 +460,8 @@ public:
NSBeep();
}
- (BOOL)inputText:(NSString*)inputText key:(NSInteger)keyCode modifiers:(NSUInteger)flags client:(id)client
- (BOOL)handleCandidateEventWithInputText:(NSString *)inputText charCode:(UniChar)charCode keyCode:(NSUInteger)keyCode
{
NSRect textFrame = NSZeroRect;
NSDictionary *attributes = nil;
BOOL useVerticalMode = NO;
@try {
attributes = [client attributesForCharacterIndex:0 lineHeightRectangle:&textFrame];
useVerticalMode = [attributes objectForKey:@"IMKTextOrientation"] && [[attributes objectForKey:@"IMKTextOrientation"] integerValue] == 0;
}
@catch (NSException *e) {
// An exception may raise while using Twitter.app's search filed.
}
NSInteger cursorForwardKey = useVerticalMode ? kDownKeyCode : kRightKeyCode;
NSInteger cursorBackwardKey = useVerticalMode ? kUpKeyCode : kLeftKeyCode;
NSInteger extraChooseCandidateKey = useVerticalMode ? kLeftKeyCode : kDownKeyCode;
NSInteger absorbedArrowKey = useVerticalMode ? kRightKeyCode : kUpKeyCode;
// get the unicode character code
UniChar charCode = [inputText length] ? [inputText characterAtIndex:0] : 0;
if ([[client bundleIdentifier] isEqualToString:@"com.apple.Terminal"] && [NSStringFromClass([client class]) isEqualToString:@"IPMDServerClientWrapper"])
{
// special handling for com.apple.Terminal
_currentDeferredClient = client;
}
// if the inputText is empty, it's a function key combination, we ignore it
if (![inputText length]) {
return NO;
}
// if the composing buffer is empty and there's no reading, and there is some function key combination, we ignore it
if (![_composingBuffer length] && _bpmfReadingBuffer->isEmpty() && ((flags & NSCommandKeyMask) || (flags & NSControlKeyMask) || (flags & NSAlternateKeyMask) || (flags & NSNumericPadKeyMask))) {
return NO;
}
bool composeReading = false;
// caps lock processing : if caps is locked, temporarily disabled bopomofo.
if (charCode == 8 || charCode == 13 ||
keyCode == absorbedArrowKey || keyCode == extraChooseCandidateKey ||
keyCode == cursorForwardKey || keyCode == cursorBackwardKey) {
// Do nothing if backspace is pressed
} else if (flags & NSAlphaShiftKeyMask){
// Now process all possible combination, we hope.
if ([_composingBuffer length]) [self commitComposition:client];
// First commit everything in the buffer.
if (flags & NSShiftKeyMask) return NO;
// when shift is pressed, don't do further processing, since it outputs
// capital letter anyway.
NSString *popedText = [inputText lowercaseString];
[client insertText:popedText replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
return YES;
}
if (flags & NSNumericPadKeyMask) {
if (keyCode != kLeftKeyCode && keyCode != kRightKeyCode && keyCode != kDownKeyCode && keyCode != kUpKeyCode && charCode != 32 && isprint(charCode)) {
if ([_composingBuffer length]) [self commitComposition:client];
NSString *popedText = [inputText lowercaseString];
[client insertText:popedText replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
return YES;
}
}
if ([_candidates count]) {
if (charCode == 27) {
gCurrentCandidateController.visible = NO;
[_candidates removeAllObjects];
@ -647,7 +586,85 @@ public:
[self beep];
return YES;
}
}
- (BOOL)inputText:(NSString*)inputText key:(NSInteger)keyCode modifiers:(NSUInteger)flags client:(id)client
{
NSRect textFrame = NSZeroRect;
NSDictionary *attributes = nil;
bool composeReading = false;
BOOL useVerticalMode = NO;
@try {
attributes = [client attributesForCharacterIndex:0 lineHeightRectangle:&textFrame];
useVerticalMode = [attributes objectForKey:@"IMKTextOrientation"] && [[attributes objectForKey:@"IMKTextOrientation"] integerValue] == 0;
}
@catch (NSException *e) {
// exception may raise while using Twitter.app's search filed.
}
NSInteger cursorForwardKey = useVerticalMode ? kDownKeyCode : kRightKeyCode;
NSInteger cursorBackwardKey = useVerticalMode ? kUpKeyCode : kLeftKeyCode;
NSInteger extraChooseCandidateKey = useVerticalMode ? kLeftKeyCode : kDownKeyCode;
NSInteger absorbedArrowKey = useVerticalMode ? kRightKeyCode : kUpKeyCode;
NSInteger verticalModeOnlyChooseCandidateKey = useVerticalMode ? absorbedArrowKey : 0;
// get the unicode character code
UniChar charCode = [inputText length] ? [inputText characterAtIndex:0] : 0;
if ([[client bundleIdentifier] isEqualToString:@"com.apple.Terminal"] && [NSStringFromClass([client class]) isEqualToString:@"IPMDServerClientWrapper"]) {
// special handling for com.apple.Terminal
_currentDeferredClient = client;
}
// if the inputText is empty, it's a function key combination, we ignore it
if (![inputText length]) {
return NO;
}
// if the composing buffer is empty and there's no reading, and there is some function key combination, we ignore it
if (![_composingBuffer length] && _bpmfReadingBuffer->isEmpty() && ((flags & NSCommandKeyMask) || (flags & NSControlKeyMask) || (flags & NSAlternateKeyMask) || (flags & NSNumericPadKeyMask))) {
return NO;
}
// Caps Lock processing : if Caps Lock is on, temporarily disable bopomofo.
if (charCode == 8 || charCode == 13 || keyCode == absorbedArrowKey || keyCode == extraChooseCandidateKey || keyCode == cursorForwardKey || keyCode == cursorBackwardKey) {
// do nothing if backspace is pressed -- we ignore the key
}
else if (flags & NSAlphaShiftKeyMask) {
// process all possible combination, we hope.
if ([_composingBuffer length]) {
[self commitComposition:client];
}
// first commit everything in the buffer.
if (flags & NSShiftKeyMask) {
return NO;
}
// when shift is pressed, don't do further processing, since it outputs capital letter anyway.
NSString *popedText = [inputText lowercaseString];
[client insertText:popedText replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
return YES;
}
if (flags & NSNumericPadKeyMask) {
if (keyCode != kLeftKeyCode && keyCode != kRightKeyCode && keyCode != kDownKeyCode && keyCode != kUpKeyCode && charCode != 32 && isprint(charCode)) {
if ([_composingBuffer length]) {
[self commitComposition:client];
}
NSString *popedText = [inputText lowercaseString];
[client insertText:popedText replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
return YES;
}
}
// if we have candidate, it means we need to pass the event to the candidate handler
if ([_candidates count]) {
return [self handleCandidateEventWithInputText:inputText charCode:charCode keyCode:keyCode];
}
@ -704,7 +721,7 @@ public:
}
// keyCode 125 = Down, charCode 32 = Space
if (_bpmfReadingBuffer->isEmpty() && [_composingBuffer length] > 0 && (keyCode == extraChooseCandidateKey || charCode == 32)) {
if (_bpmfReadingBuffer->isEmpty() && [_composingBuffer length] > 0 && (keyCode == extraChooseCandidateKey || charCode == 32 || (useVerticalMode && (keyCode == verticalModeOnlyChooseCandidateKey)))) {
if (charCode == 32) {
// if the spacebar is NOT set to be a selection key
if (![[NSUserDefaults standardUserDefaults] boolForKey:kChooseCandidateUsingSpaceKey]) {
@ -728,13 +745,14 @@ public:
// Esc
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 (_bpmfReadingBuffer->isEmpty()) {
// no nee to beep since the event is deliberately triggered by user
if (![_composingBuffer length]) {
return NO;
}
//[self beep];
//如果要按 ESC 的時候都已經知道要取消些啥不必beep
}
else {
_bpmfReadingBuffer->clear();
@ -742,11 +760,9 @@ public:
[self updateClientComposingBuffer:client];
return YES;
//可能的行為包括 1. 取消組字, 把字吃掉 2. 取消 candidate 選擇, 恢復原來的
//3. 取消組字,現出注音
}
// The Right key, note we use keyCode here
// handle cursor backward
if (keyCode == cursorBackwardKey) {
if (!_bpmfReadingBuffer->isEmpty()) {
[self beep];
@ -768,7 +784,7 @@ public:
return YES;
}
// The Left key, note we use keyCode here
// handle cursor forward
if (keyCode == cursorForwardKey) {
if (!_bpmfReadingBuffer->isEmpty()) {
[self beep];
@ -831,6 +847,7 @@ public:
return YES;
}
// punctuation list
if ((char)charCode == '`') {
if (gLanguageModel.hasUnigramsForKey(string("_punctuation_list"))) {
if (_bpmfReadingBuffer->isEmpty()) {
@ -1110,7 +1127,13 @@ public:
NSLog(@"%@", exception);
}
if (useVerticalMode) {
[gCurrentCandidateController setWindowTopLeftPoint:NSMakePoint(lineHeightRect.origin.x + lineHeightRect.size.width + 4.0, lineHeightRect.origin.y - 4.0) bottomOutOfScreenAdjustmentHeight:lineHeightRect.size.height + 4.0];
}
else {
[gCurrentCandidateController setWindowTopLeftPoint:NSMakePoint(lineHeightRect.origin.x, lineHeightRect.origin.y - 4.0) bottomOutOfScreenAdjustmentHeight:lineHeightRect.size.height + 4.0];
}
gCurrentCandidateController.visible = YES;
}