Skip to content
84 changes: 84 additions & 0 deletions McBopomofoTests/KeyHandlerBopomofoTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2706,3 +2706,87 @@ extension KeyHandlerBopomofoTests {
}
}
}

extension KeyHandlerBopomofoTests {

func testChnagingReadingUsingToneKey1() {
Comment thread
zonble marked this conversation as resolved.
Outdated
let associatedPhrasesEnabled = Preferences.associatedPhrasesEnabled
Preferences.associatedPhrasesEnabled = false

defer {
Preferences.associatedPhrasesEnabled = associatedPhrasesEnabled
}

var state: InputState = InputState.Empty()
let keys = Array("vul3a943").map {
String($0)
}
for key in keys {
let input = KeyHandlerInput(
inputText: key, keyCode: 0, charCode: charCode(key), flags: [],
isVerticalMode: false)
handler.handle(input: input, state: state) { newState in
state = newState
} errorCallback: {
}
}
XCTAssertTrue(state is InputState.Inputting, "\(state)")
if let state = state as? InputState.Inputting {
XCTAssertEqual(state.composingBuffer, "小買")
}
}

func testChnagingReadingUsingToneKey2() {
let associatedPhrasesEnabled = Preferences.associatedPhrasesEnabled
Preferences.associatedPhrasesEnabled = false

defer {
Preferences.associatedPhrasesEnabled = associatedPhrasesEnabled
}

var state: InputState = InputState.Empty()
let keys = Array("vul3a946").map {
String($0)
}
for key in keys {
let input = KeyHandlerInput(
inputText: key, keyCode: 0, charCode: charCode(key), flags: [],
isVerticalMode: false)
handler.handle(input: input, state: state) { newState in
state = newState
} errorCallback: {
}
}
XCTAssertTrue(state is InputState.Inputting, "\(state)")
if let state = state as? InputState.Inputting {
XCTAssertEqual(state.composingBuffer, "小埋")
}
}

func testChnagingReadingUsingToneKey3() {
let associatedPhrasesEnabled = Preferences.associatedPhrasesEnabled
Preferences.associatedPhrasesEnabled = false

defer {
Preferences.associatedPhrasesEnabled = associatedPhrasesEnabled
}

var state: InputState = InputState.Empty()
let keys = Array("vul3a947").map {
String($0)
}
for key in keys {
let input = KeyHandlerInput(
inputText: key, keyCode: 0, charCode: charCode(key), flags: [],
isVerticalMode: false)
handler.handle(input: input, state: state) { newState in
state = newState
} errorCallback: {
}
}
XCTAssertTrue(state is InputState.Inputting, "\(state)")
if let state = state as? InputState.Inputting {
XCTAssertEqual(state.composingBuffer, "小麥˙")
}
}
}
Comment thread
zonble marked this conversation as resolved.
11 changes: 11 additions & 0 deletions Source/Engine/Mandarin/Mandarin.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,16 @@ class BopomofoReadingBuffer {

const BPMF syllable() const { return syllable_; }

void setSyllableRemovingTone(BPMF syllable) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

為了這個只會用到一次的 feature 而在底層程式庫加入這個 helper,似乎沒有必要。請看我下面的留言。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updates in 4edc27a

BPMF::Component masked = (syllable.consonantComponent() |
syllable.middleVowelComponent() |
syllable.vowelComponent());
syllable_ = BPMF(masked);
if (pinyin_mode_) {
pinyin_sequence_ = syllable_.HanyuPinyinString(false, false);
}
}

const std::string standardLayoutQueryString() const {
return BopomofoKeyboardLayout::StandardLayout()->keySequenceFromSyllable(
syllable_);
Expand All @@ -482,3 +492,4 @@ class BopomofoReadingBuffer {
} // namespace Formosa

#endif // SRC_ENGINE_MANDARIN_MANDARIN_H_

30 changes: 28 additions & 2 deletions Source/KeyHandler.mm
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,8 @@ - (BOOL)handleInput:(KeyHandlerInput *)input state:(InputState *)inState stateCa
// MARK: Handle BPMF Keys

// see if it's valid BPMF reading
if (!skipBpmfHandling && _bpmfReadingBuffer->isValidKey((char)charCode)) {
bool isValidKey = _bpmfReadingBuffer->isValidKey((char)charCode);
if (!skipBpmfHandling && isValidKey) {
_bpmfReadingBuffer->combineKey((char)charCode);
keyConsumedByReading = YES;

Expand All @@ -463,7 +464,32 @@ - (BOOL)handleInput:(KeyHandlerInput *)input state:(InputState *)inState stateCa
}
}

BOOL composeReading = _bpmfReadingBuffer->isValidKey((char)charCode) && _bpmfReadingBuffer->hasToneMarker() && !_bpmfReadingBuffer->hasToneMarkerOnly();
// Issue 753
//
// This allows users to use tone key to change an existing reading before
// the current cursor.
if (_bpmfReadingBuffer->hasToneMarkerOnly() && _grid->readings().size() > 0 && _grid->cursor() > 0) {
Comment thread
zonble marked this conversation as resolved.
Outdated
size_t cursor = _grid->cursor() - 1;
std::string reading = _grid->readings()[cursor];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To avoid a potentially unnecessary string copy, you can declare reading as a const reference.

Suggested change
std::string reading = _grid->readings()[cursor];
const std::string& reading = _grid->readings()[cursor];

if (!reading.empty() && reading[0] != '_') {
Formosa::Mandarin::BopomofoReadingBuffer tmpBuffer(_bpmfReadingBuffer->keyboardLayout());
Formosa::Mandarin::BopomofoSyllable syllable = Formosa::Mandarin::BopomofoSyllable::FromComposedString(reading);
tmpBuffer.setSyllableRemovingTone(syllable);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我會考慮換一個作法,這樣就不需要在 Mandarin.h 中加入那樣一個一次性、為單一 feature 設計的 helper method:

  1. 取得現在的 keyboard layout
  2. 呼叫 BopomofoKeyboardLayout::keySequenceFromSyllable()
  3. 建立新的 BopomofoReadingBuffer 物件,然後把上一步得到的 key sequence 透過 combineKey() 丟進去
  4. 再呼叫 combineKey() 把最新的聲調符號組合進去,這樣等同取代現有聲調

無論哪種作法,倚天 26 鍵、許氏跟拼音都無法支援(請看我頂層的留言),但至少上述作法可以免除在 Mandarin.h 中放入新 helper。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in 4edc27a

tmpBuffer.combineKey((char)charCode);
std::string newReading = tmpBuffer.syllable().composedString();
if (_languageModel->hasUnigrams(newReading)) {
_bpmfReadingBuffer->clear();
_grid->deleteReadingBeforeCursor();
_grid->insertReading(newReading);
[self _walk];
InputStateInputting *inputting = (InputStateInputting *)[self buildInputtingState];
stateCallback(inputting);
return YES;
}
}
}

BOOL composeReading = isValidKey && _bpmfReadingBuffer->hasToneMarker() && !_bpmfReadingBuffer->hasToneMarkerOnly();

// see if we have composition if Enter/Space is hit and buffer is not empty
// this is bit-OR'ed so that the tone marker key is also taken into account
Expand Down