KeyHandler // Swiftify: day 2.
This commit is contained in:
parent
5c8defca03
commit
43c2c1dfe4
|
@ -50,10 +50,8 @@ extern InputMode imeModeNULL;
|
|||
- (BOOL)handleInput:(keyParser *)input
|
||||
state:(InputState *)state
|
||||
stateCallback:(void (^)(InputState *))stateCallback
|
||||
errorCallback:(void (^)(void))errorCallback
|
||||
NS_SWIFT_NAME(handle(input:state:stateCallback:errorCallback:));
|
||||
errorCallback:(void (^)(void))errorCallback NS_SWIFT_NAME(handle(input:state:stateCallback:errorCallback:));
|
||||
|
||||
- (void)ensurePhoneticParser;
|
||||
- (void)fixNodeWithValue:(NSString *)value NS_SWIFT_NAME(fixNode(value:));
|
||||
- (void)clear;
|
||||
|
||||
|
@ -63,8 +61,40 @@ extern InputMode imeModeNULL;
|
|||
@property(strong, nonatomic) InputMode inputMode;
|
||||
@property(weak, nonatomic) id<KeyHandlerDelegate> delegate;
|
||||
|
||||
// The following items need to be exposed to Swift:
|
||||
- (NSString *)_popOverflowComposingTextAndWalk;
|
||||
|
||||
- (BOOL)_handleCandidateState:(InputState *)state
|
||||
input:(keyParser *)input
|
||||
stateCallback:(void (^)(InputState *))stateCallback
|
||||
errorCallback:(void (^)(void))errorCallback
|
||||
NS_SWIFT_NAME(handleCandidate(state:input:stateCallback:errorCallback:));
|
||||
- (BOOL)_handleMarkingState:(InputState *)state
|
||||
input:(keyParser *)input
|
||||
stateCallback:(void (^)(InputState *))stateCallback
|
||||
errorCallback:(void (^)(void))errorCallback
|
||||
NS_SWIFT_NAME(handleMarking(state:input:stateCallback:errorCallback:));
|
||||
|
||||
- (BOOL)checkWhetherToneMarkerConfirmsPhoneticReadingBuffer;
|
||||
- (BOOL)chkKeyValidity:(UniChar)value;
|
||||
- (BOOL)isPhoneticReadingBufferEmpty;
|
||||
- (NSString *)getCompositionFromPhoneticReadingBuffer;
|
||||
- (NSString *)getSyllableCompositionFromPhoneticReadingBuffer;
|
||||
- (void)clearPhoneticReadingBuffer;
|
||||
- (void)combinePhoneticReadingBufferKey:(UniChar)charCode;
|
||||
- (void)doBackSpaceToPhoneticReadingBuffer;
|
||||
- (void)removeBuilderAndReset:(BOOL)shouldReset;
|
||||
- (void)createNewBuilder;
|
||||
- (void)setInputModesToLM:(BOOL)isCHS;
|
||||
- (void)syncBaseLMPrefs;
|
||||
- (void)ensurePhoneticParser;
|
||||
- (BOOL)ifLangModelHasUnigramsForKey:(NSString *)reading;
|
||||
- (void)insertReadingToBuilderAtCursor:(NSString *)reading;
|
||||
- (BOOL)isPrintable:(UniChar)charCode;
|
||||
- (void)dealWithOverrideModelSuggestions;
|
||||
- (NSMutableArray *)getCandidatesArray;
|
||||
- (NSInteger)getBuilderCursorIndex;
|
||||
- (NSInteger)getBuilderLength;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -198,9 +198,9 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
|||
_walkedNodes.clear();
|
||||
}
|
||||
|
||||
- (std::string)_currentMandarinParser
|
||||
- (NSString *)_currentMandarinParser
|
||||
{
|
||||
return std::string(mgrPrefs.mandarinParserName.UTF8String) + std::string("_");
|
||||
return [mgrPrefs.mandarinParserName stringByAppendingString:@"_"];
|
||||
}
|
||||
|
||||
// MARK: - Handling Input
|
||||
|
@ -331,10 +331,10 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
|||
if (composeReading)
|
||||
{
|
||||
// combine the reading
|
||||
std::string reading = [[self getSyllableCompositionFromPhoneticReadingBuffer] UTF8String];
|
||||
NSString *reading = [self getSyllableCompositionFromPhoneticReadingBuffer];
|
||||
|
||||
// see if we have an unigram for this
|
||||
if (!_languageModel->hasUnigramsForKey(reading))
|
||||
if (![self ifLangModelHasUnigramsForKey:reading])
|
||||
{
|
||||
[IME prtDebugIntel:@"B49C0979"];
|
||||
errorCallback();
|
||||
|
@ -344,25 +344,13 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
|||
}
|
||||
|
||||
// and insert it into the lattice
|
||||
_builder->insertReadingAtCursor(reading);
|
||||
[self insertReadingToBuilderAtCursor:reading];
|
||||
|
||||
// then walk the lattice
|
||||
NSString *poppedText = [self _popOverflowComposingTextAndWalk];
|
||||
|
||||
// get user override model suggestion
|
||||
std::string overrideValue = (mgrPrefs.useSCPCTypingMode)
|
||||
? ""
|
||||
: _userOverrideModel->suggest(_walkedNodes, _builder->cursorIndex(),
|
||||
[[NSDate date] timeIntervalSince1970]);
|
||||
|
||||
if (!overrideValue.empty())
|
||||
{
|
||||
size_t cursorIndex = [self _actualCandidateCursorIndex];
|
||||
std::vector<Gramambular::NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex);
|
||||
double highestScore = FindHighestScore(nodes, kEpsilon);
|
||||
_builder->grid().overrideNodeScoreForSelectedCandidate(cursorIndex, overrideValue,
|
||||
static_cast<float>(highestScore));
|
||||
}
|
||||
[self dealWithOverrideModelSuggestions];
|
||||
|
||||
// then update the text
|
||||
[self clearPhoneticReadingBuffer];
|
||||
|
@ -420,7 +408,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
|||
// if the spacebar is NOT set to be a selection key
|
||||
if ([input isShiftHold] || !mgrPrefs.chooseCandidateUsingSpace)
|
||||
{
|
||||
if (_builder->cursorIndex() >= _builder->length())
|
||||
if ([self getBuilderCursorIndex] >= [self getBuilderLength])
|
||||
{
|
||||
NSString *composingBuffer = [(InputStateNotEmpty *)state composingBuffer];
|
||||
if (composingBuffer.length)
|
||||
|
@ -435,9 +423,9 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
|||
InputStateEmpty *empty = [[InputStateEmpty alloc] init];
|
||||
stateCallback(empty);
|
||||
}
|
||||
else if (_languageModel->hasUnigramsForKey(" "))
|
||||
else if ([self ifLangModelHasUnigramsForKey:@" "])
|
||||
{
|
||||
_builder->insertReadingAtCursor(" ");
|
||||
[self insertReadingToBuilderAtCursor:@" "];
|
||||
NSString *poppedText = [self _popOverflowComposingTextAndWalk];
|
||||
InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState];
|
||||
inputting.poppedText = poppedText;
|
||||
|
@ -508,11 +496,11 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
|||
{
|
||||
if (![input isOptionHold])
|
||||
{
|
||||
if (_languageModel->hasUnigramsForKey("_punctuation_list"))
|
||||
if ([self ifLangModelHasUnigramsForKey:@"_punctuation_list "])
|
||||
{
|
||||
if ([self isPhoneticReadingBufferEmpty])
|
||||
{
|
||||
_builder->insertReadingAtCursor(string("_punctuation_list"));
|
||||
[self insertReadingToBuilderAtCursor:@"_punctuation_list"];
|
||||
NSString *poppedText = [self _popOverflowComposingTextAndWalk];
|
||||
InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState];
|
||||
inputting.poppedText = poppedText;
|
||||
|
@ -546,19 +534,21 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
|||
// MARK: Punctuation
|
||||
// if nothing is matched, see if it's a punctuation key for current layout.
|
||||
|
||||
std::string punctuationNamePrefix;
|
||||
NSString *punctuationNamePrefix;
|
||||
|
||||
if ([input isOptionHold])
|
||||
punctuationNamePrefix = std::string("_alt_punctuation_");
|
||||
punctuationNamePrefix = @"_alt_punctuation_";
|
||||
else if ([input isControlHold])
|
||||
punctuationNamePrefix = std::string("_ctrl_punctuation_");
|
||||
punctuationNamePrefix = @"_ctrl_punctuation_";
|
||||
else if (mgrPrefs.halfWidthPunctuationEnabled)
|
||||
punctuationNamePrefix = std::string("_half_punctuation_");
|
||||
punctuationNamePrefix = @"_half_punctuation_";
|
||||
else
|
||||
punctuationNamePrefix = std::string("_punctuation_");
|
||||
punctuationNamePrefix = @"_punctuation_";
|
||||
|
||||
std::string parser = [self _currentMandarinParser];
|
||||
std::string customPunctuation = punctuationNamePrefix + parser + std::string(1, (char)charCode);
|
||||
NSString *parser = [self _currentMandarinParser];
|
||||
NSArray *arrCustomPunctuations =
|
||||
@[ punctuationNamePrefix, parser, [NSString stringWithFormat:@"%c", (char)charCode] ];
|
||||
NSString *customPunctuation = [arrCustomPunctuations componentsJoinedByString:@""];
|
||||
if ([self _handlePunctuation:customPunctuation
|
||||
state:state
|
||||
usingVerticalMode:input.useVerticalMode
|
||||
|
@ -567,7 +557,9 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
|||
return YES;
|
||||
|
||||
// if nothing is matched, see if it's a punctuation key.
|
||||
std::string punctuation = punctuationNamePrefix + std::string(1, (char)charCode);
|
||||
NSArray *arrPunctuations = @[ punctuationNamePrefix, [NSString stringWithFormat:@"%c", (char)charCode] ];
|
||||
NSString *punctuation = [arrPunctuations componentsJoinedByString:@""];
|
||||
|
||||
if ([self _handlePunctuation:punctuation
|
||||
state:state
|
||||
usingVerticalMode:input.useVerticalMode
|
||||
|
@ -575,12 +567,10 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
|||
errorCallback:errorCallback])
|
||||
return YES;
|
||||
|
||||
// Lukhnos 這裡的處理反而會使得 Apple 倚天注音動態鍵盤佈局「敲不了半形大寫英文」的缺點曝露無疑,所以注釋掉。
|
||||
// 至於他試圖用這種處理來解決的上游 UPR293
|
||||
// 的問題,其實針對詞庫檔案的排序做點手腳就可以解決。威注音本來也就是這麼做的。
|
||||
if (/*[state isKindOfClass:[InputStateNotEmpty class]] && */ [input isUpperCaseASCIILetterKey])
|
||||
// 這裡不使用小麥注音 2.2. 的組字區處理方式,而是直接由詞庫負責。
|
||||
if ([input isUpperCaseASCIILetterKey])
|
||||
{
|
||||
std::string letter = std::string("_letter_") + std::string(1, (char)charCode);
|
||||
NSString *letter = [NSString stringWithFormat:@"%@%c", @"_letter_", (char)charCode];
|
||||
if ([self _handlePunctuation:letter
|
||||
state:state
|
||||
usingVerticalMode:input.useVerticalMode
|
||||
|
@ -957,19 +947,19 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)_handlePunctuation:(std::string)customPunctuation
|
||||
- (BOOL)_handlePunctuation:(NSString *)customPunctuation
|
||||
state:(InputState *)state
|
||||
usingVerticalMode:(BOOL)useVerticalMode
|
||||
stateCallback:(void (^)(InputState *))stateCallback
|
||||
errorCallback:(void (^)(void))errorCallback
|
||||
{
|
||||
if (!_languageModel->hasUnigramsForKey(customPunctuation))
|
||||
if (![self ifLangModelHasUnigramsForKey:customPunctuation])
|
||||
return NO;
|
||||
|
||||
NSString *poppedText;
|
||||
if ([self isPhoneticReadingBufferEmpty])
|
||||
{
|
||||
_builder->insertReadingAtCursor(customPunctuation);
|
||||
[self insertReadingToBuilderAtCursor:customPunctuation];
|
||||
poppedText = [self _popOverflowComposingTextAndWalk];
|
||||
}
|
||||
else
|
||||
|
@ -1389,28 +1379,34 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
|||
|
||||
if (mgrPrefs.useSCPCTypingMode)
|
||||
{
|
||||
std::string punctuationNamePrefix;
|
||||
if ([input isOptionHold])
|
||||
punctuationNamePrefix = std::string("_alt_punctuation_");
|
||||
else if ([input isControlHold])
|
||||
punctuationNamePrefix = std::string("_ctrl_punctuation_");
|
||||
else if (mgrPrefs.halfWidthPunctuationEnabled)
|
||||
punctuationNamePrefix = std::string("_half_punctuation_");
|
||||
else
|
||||
punctuationNamePrefix = std::string("_punctuation_");
|
||||
NSString *punctuationNamePrefix;
|
||||
|
||||
std::string parser = [self _currentMandarinParser];
|
||||
std::string customPunctuation = punctuationNamePrefix + parser + std::string(1, (char)charCode);
|
||||
std::string punctuation = punctuationNamePrefix + std::string(1, (char)charCode);
|
||||
if ([input isOptionHold])
|
||||
punctuationNamePrefix = @"_alt_punctuation_";
|
||||
else if ([input isControlHold])
|
||||
punctuationNamePrefix = @"_ctrl_punctuation_";
|
||||
else if (mgrPrefs.halfWidthPunctuationEnabled)
|
||||
punctuationNamePrefix = @"_half_punctuation_";
|
||||
else
|
||||
punctuationNamePrefix = @"_punctuation_";
|
||||
|
||||
NSString *parser = [self _currentMandarinParser];
|
||||
|
||||
NSArray *arrCustomPunctuations =
|
||||
@[ punctuationNamePrefix, parser, [NSString stringWithFormat:@"%c", (char)charCode] ];
|
||||
NSString *customPunctuation = [arrCustomPunctuations componentsJoinedByString:@""];
|
||||
|
||||
NSArray *arrPunctuations = @[ punctuationNamePrefix, [NSString stringWithFormat:@"%c", (char)charCode] ];
|
||||
NSString *punctuation = [arrPunctuations componentsJoinedByString:@""];
|
||||
|
||||
BOOL shouldAutoSelectCandidate = [self chkKeyValidity:charCode] ||
|
||||
_languageModel->hasUnigramsForKey(customPunctuation) ||
|
||||
_languageModel->hasUnigramsForKey(punctuation);
|
||||
[self ifLangModelHasUnigramsForKey:customPunctuation] ||
|
||||
[self ifLangModelHasUnigramsForKey:punctuation];
|
||||
|
||||
if (!shouldAutoSelectCandidate && [input isUpperCaseASCIILetterKey])
|
||||
{
|
||||
std::string letter = std::string("_letter_") + std::string(1, (char)charCode);
|
||||
if (_languageModel->hasUnigramsForKey(letter))
|
||||
NSString *letter = [NSString stringWithFormat:@"%@%c", @"_letter_", (char)charCode];
|
||||
if ([self ifLangModelHasUnigramsForKey:letter])
|
||||
shouldAutoSelectCandidate = YES;
|
||||
}
|
||||
|
||||
|
@ -1598,34 +1594,6 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
|||
return poppedText;
|
||||
}
|
||||
|
||||
- (InputStateChoosingCandidate *)_buildCandidateState:(InputStateNotEmpty *)currentState
|
||||
useVerticalMode:(BOOL)useVerticalMode
|
||||
{
|
||||
NSMutableArray *candidatesArray = [[NSMutableArray alloc] init];
|
||||
|
||||
size_t cursorIndex = [self _actualCandidateCursorIndex];
|
||||
std::vector<Gramambular::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
|
||||
stable_sort(nodes.begin(), nodes.end(), NodeAnchorDescendingSorter());
|
||||
|
||||
// then use the C++ trick to retrieve the candidates for each node at/crossing the cursor
|
||||
for (std::vector<Gramambular::NodeAnchor>::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni)
|
||||
{
|
||||
const std::vector<Gramambular::KeyValuePair> &candidates = (*ni).node->candidates();
|
||||
for (std::vector<Gramambular::KeyValuePair>::const_iterator ci = candidates.begin(), ce = candidates.end();
|
||||
ci != ce; ++ci)
|
||||
[candidatesArray addObject:[NSString stringWithUTF8String:(*ci).value.c_str()]];
|
||||
}
|
||||
|
||||
InputStateChoosingCandidate *state =
|
||||
[[InputStateChoosingCandidate alloc] initWithComposingBuffer:currentState.composingBuffer
|
||||
cursorIndex:currentState.cursorIndex
|
||||
candidates:candidatesArray
|
||||
useVerticalMode:useVerticalMode];
|
||||
return state;
|
||||
}
|
||||
|
||||
// NON-SWIFTIFIABLE
|
||||
- (size_t)_actualCandidateCursorIndex
|
||||
{
|
||||
|
@ -1787,7 +1755,69 @@ static NSString *const kGraphVizOutputfile = @"/tmp/vChewing-visualization.dot";
|
|||
}
|
||||
}
|
||||
|
||||
#pragma mark - 威注音認為有必要單獨拿出來處理的部分。
|
||||
// ----
|
||||
|
||||
- (BOOL)ifLangModelHasUnigramsForKey:(NSString *)reading
|
||||
{
|
||||
return _languageModel->hasUnigramsForKey((std::string)[reading UTF8String]);
|
||||
}
|
||||
|
||||
- (void)insertReadingToBuilderAtCursor:(NSString *)reading
|
||||
{
|
||||
_builder->insertReadingAtCursor((std::string)[reading UTF8String]);
|
||||
}
|
||||
|
||||
- (void)dealWithOverrideModelSuggestions
|
||||
{
|
||||
// 這一整段都太 C++ 且只出現一次,就整個端過來了。
|
||||
// 拆開封裝的話,只會把問題搞得更麻煩而已。
|
||||
std::string overrideValue =
|
||||
(mgrPrefs.useSCPCTypingMode)
|
||||
? ""
|
||||
: _userOverrideModel->suggest(_walkedNodes, _builder->cursorIndex(), [[NSDate date] timeIntervalSince1970]);
|
||||
|
||||
if (!overrideValue.empty())
|
||||
{
|
||||
size_t cursorIndex = [self _actualCandidateCursorIndex];
|
||||
std::vector<Gramambular::NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex);
|
||||
double highestScore = FindHighestScore(nodes, kEpsilon);
|
||||
_builder->grid().overrideNodeScoreForSelectedCandidate(cursorIndex, overrideValue,
|
||||
static_cast<float>(highestScore));
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)getBuilderCursorIndex
|
||||
{
|
||||
return _builder->cursorIndex();
|
||||
}
|
||||
|
||||
- (NSInteger)getBuilderLength
|
||||
{
|
||||
return _builder->length();
|
||||
}
|
||||
|
||||
- (NSMutableArray *)getCandidatesArray
|
||||
{
|
||||
NSMutableArray<NSString *> *candidatesArray = [[NSMutableArray alloc] init];
|
||||
|
||||
size_t cursorIndex = [self _actualCandidateCursorIndex];
|
||||
std::vector<Gramambular::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
|
||||
stable_sort(nodes.begin(), nodes.end(), NodeAnchorDescendingSorter());
|
||||
|
||||
// then use the C++ trick to retrieve the candidates for each node at/crossing the cursor
|
||||
for (std::vector<Gramambular::NodeAnchor>::iterator ni = nodes.begin(), ne = nodes.end(); ni != ne; ++ni)
|
||||
{
|
||||
const std::vector<Gramambular::KeyValuePair> &candidates = (*ni).node->candidates();
|
||||
for (std::vector<Gramambular::KeyValuePair>::const_iterator ci = candidates.begin(), ce = candidates.end();
|
||||
ci != ce; ++ci)
|
||||
[candidatesArray addObject:[NSString stringWithUTF8String:(*ci).value.c_str()]];
|
||||
}
|
||||
return candidatesArray;
|
||||
}
|
||||
|
||||
#pragma mark - 威注音認為有必要單獨拿出來處理的部分,交給 Swift 則有些困難。
|
||||
|
||||
- (BOOL)isPrintable:(UniChar)charCode
|
||||
{
|
||||
|
|
|
@ -29,13 +29,15 @@ import Cocoa
|
|||
@objc extension KeyHandler {
|
||||
func handleInputSwift(
|
||||
input: keyParser,
|
||||
state: InputState,
|
||||
state inState: InputState,
|
||||
stateCallback: @escaping (InputState) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
let charCode: UniChar = input.charCode
|
||||
// let emacsKey: vChewingEmacsKey = input.emacsKey
|
||||
var state = inState // Turn this incoming constant to variable.
|
||||
let emacsKey: vChewingEmacsKey = input.emacsKey
|
||||
let inputText: String = input.inputText ?? ""
|
||||
let emptyState = InputState.Empty()
|
||||
|
||||
// Ignore the input if its inputText is empty.
|
||||
// Reason: such inputs may be functional key combinations.
|
||||
|
@ -62,7 +64,6 @@ import Cocoa
|
|||
} else if input.isCapsLockOn {
|
||||
// Process all possible combination, we hope.
|
||||
clear()
|
||||
let emptyState = InputState.Empty()
|
||||
stateCallback(emptyState)
|
||||
|
||||
// When shift is pressed, don't do further processing...
|
||||
|
@ -91,7 +92,6 @@ import Cocoa
|
|||
&& !input.isUp && !input.isSpace && isPrintable(charCode)
|
||||
{
|
||||
clear()
|
||||
let emptyState = InputState.Empty()
|
||||
stateCallback(emptyState)
|
||||
let committing = InputState.Committing(poppedText: inputText.lowercased())
|
||||
stateCallback(committing)
|
||||
|
@ -100,6 +100,161 @@ import Cocoa
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - Handle Candidates.
|
||||
if state is InputState.ChoosingCandidate {
|
||||
return handleCandidate(
|
||||
state: state, input: input, stateCallback: stateCallback, errorCallback: errorCallback)
|
||||
}
|
||||
|
||||
// MARK: - Handle Associated Phrases.
|
||||
if state is InputState.AssociatedPhrases {
|
||||
let result = handleCandidate(
|
||||
state: state, input: input, stateCallback: stateCallback, errorCallback: errorCallback)
|
||||
if result {
|
||||
return true
|
||||
} else {
|
||||
stateCallback(emptyState)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Handle Marking.
|
||||
if state is InputState.Marking {
|
||||
let marking = state as! InputState.Marking
|
||||
|
||||
if handleMarking(
|
||||
state: state as! InputState.Marking, input: input, stateCallback: stateCallback,
|
||||
errorCallback: errorCallback)
|
||||
{
|
||||
return true
|
||||
}
|
||||
|
||||
state = marking.convertToInputting()
|
||||
stateCallback(state)
|
||||
}
|
||||
|
||||
// MARK: - Handle BPMF Keys.
|
||||
var composeReading: Bool = false
|
||||
let skipPhoneticHandling = input.isReservedKey || input.isControlHold || input.isOptionHold
|
||||
|
||||
// See if Phonetic reading is valid.
|
||||
if !skipPhoneticHandling && chkKeyValidity(charCode) {
|
||||
combinePhoneticReadingBufferKey(charCode)
|
||||
|
||||
// If we have a tone marker, we have to insert the reading to the
|
||||
// builder in other words, if we don't have a tone marker, we just
|
||||
// update the composing buffer.
|
||||
composeReading = checkWhetherToneMarkerConfirmsPhoneticReadingBuffer()
|
||||
if !composeReading {
|
||||
let inputting = buildInputtingState() as! InputState.Inputting
|
||||
stateCallback(inputting)
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// See if we have composition if Enter/Space is hit and buffer is not empty.
|
||||
// We use "|=" conditioning so that the tone marker key is also taken into account.
|
||||
// However, Swift does not support "|=".
|
||||
composeReading = composeReading || (!isPhoneticReadingBufferEmpty() && (input.isSpace || input.isEnter))
|
||||
if composeReading {
|
||||
let reading = getSyllableCompositionFromPhoneticReadingBuffer()
|
||||
|
||||
if !ifLangModelHasUnigrams(forKey: reading) {
|
||||
IME.prtDebugIntel("B49C0979")
|
||||
errorCallback()
|
||||
let inputting = buildInputtingState() as! InputState.Inputting
|
||||
stateCallback(inputting)
|
||||
return true
|
||||
}
|
||||
|
||||
// ... and insert it into the lattice grid...
|
||||
insertReadingToBuilder(atCursor: reading)
|
||||
|
||||
// ... then walk the lattice grid...
|
||||
let poppedText = _popOverflowComposingTextAndWalk()
|
||||
|
||||
// ... get and tweak override model suggestion if possible...
|
||||
dealWithOverrideModelSuggestions()
|
||||
|
||||
// ... then update the text.
|
||||
clearPhoneticReadingBuffer()
|
||||
|
||||
let inputting = buildInputtingState() as! InputState.Inputting
|
||||
inputting.poppedText = poppedText
|
||||
stateCallback(inputting)
|
||||
|
||||
if mgrPrefs.useSCPCTypingMode {
|
||||
let choosingCandidates: InputState.ChoosingCandidate = _buildCandidateState(
|
||||
inputting,
|
||||
useVerticalMode: input.useVerticalMode)
|
||||
if choosingCandidates.candidates.count == 1 {
|
||||
clear()
|
||||
let text: String = choosingCandidates.candidates.first ?? ""
|
||||
let committing = InputState.Committing(poppedText: text)
|
||||
stateCallback(committing)
|
||||
|
||||
if !mgrPrefs.associatedPhrasesEnabled {
|
||||
stateCallback(emptyState)
|
||||
} else {
|
||||
let associatedPhrases =
|
||||
buildAssociatePhraseState(
|
||||
withKey: text,
|
||||
useVerticalMode: input.useVerticalMode) as? InputState.AssociatedPhrases
|
||||
if let associatedPhrases = associatedPhrases {
|
||||
stateCallback(associatedPhrases)
|
||||
} else {
|
||||
stateCallback(emptyState)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stateCallback(choosingCandidates)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK: - Calling candidate window using Space or Down or PageUp / PageDn.
|
||||
|
||||
if isPhoneticReadingBufferEmpty() && (state is InputState.NotEmpty)
|
||||
&& (input.isExtraChooseCandidateKey || input.isExtraChooseCandidateKeyReverse || input.isSpace
|
||||
|| input.isPageDown || input.isPageUp || input.isTab
|
||||
|| (input.useVerticalMode && (input.isVerticalModeOnlyChooseCandidateKey)))
|
||||
{
|
||||
if input.isSpace {
|
||||
// If the spacebar is NOT set to be a selection key
|
||||
if input.isShiftHold || !mgrPrefs.chooseCandidateUsingSpace {
|
||||
if getBuilderCursorIndex() >= getBuilderLength() {
|
||||
let composingBuffer = (state as! InputState.NotEmpty).composingBuffer
|
||||
if (composingBuffer.count) != 0 {
|
||||
let committing = InputState.Committing(poppedText: composingBuffer)
|
||||
stateCallback(committing)
|
||||
}
|
||||
clear()
|
||||
let committing = InputState.Committing(poppedText: " ")
|
||||
stateCallback(committing)
|
||||
let empty = InputState.Empty()
|
||||
stateCallback(empty)
|
||||
} else if ifLangModelHasUnigrams(forKey: " ") {
|
||||
insertReadingToBuilder(atCursor: " ")
|
||||
let poppedText = _popOverflowComposingTextAndWalk()
|
||||
let inputting = buildInputtingState() as! InputState.Inputting
|
||||
inputting.poppedText = poppedText
|
||||
stateCallback(inputting)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
let choosingCandidates = _buildCandidateState(
|
||||
state as! InputState.NotEmpty,
|
||||
useVerticalMode: input.useVerticalMode)
|
||||
stateCallback(choosingCandidates)
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK: - Function Keys.
|
||||
|
||||
// MARK: Esc
|
||||
|
||||
// MARK: - Still Nothing.
|
||||
// Still nothing? Then we update the composing buffer.
|
||||
// Note that some app has strange behavior if we don't do this,
|
||||
|
@ -118,3 +273,21 @@ import Cocoa
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - State managements.
|
||||
@objc extension KeyHandler {
|
||||
func _buildCandidateState(
|
||||
_ currentState: InputState.NotEmpty,
|
||||
useVerticalMode: Bool
|
||||
) -> InputState.ChoosingCandidate {
|
||||
let candidatesArray = getCandidatesArray()
|
||||
|
||||
let state = InputState.ChoosingCandidate(
|
||||
composingBuffer: currentState.composingBuffer,
|
||||
cursorIndex: currentState.cursorIndex,
|
||||
candidates: candidatesArray as! [String],
|
||||
useVerticalMode: useVerticalMode)
|
||||
return state
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue