From 064b2fbe7deed171debac9418e61b904806a26e9 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Thu, 27 Oct 2022 17:35:18 +0800 Subject: [PATCH] InputHandler // Fix wrong conditioning of composeReading(), etc. (#206) - Stop calling candidate window when the compositor is empty. - Stop handling the simple input case of the intonation "tone1". --- Packages/vChewing_Tekkon/README.md | 87 +------------------ .../InputHandler_HandleComposition.swift | 24 ++--- Source/Modules/InputHandler_HandleInput.swift | 3 +- 3 files changed, 16 insertions(+), 98 deletions(-) diff --git a/Packages/vChewing_Tekkon/README.md b/Packages/vChewing_Tekkon/README.md index 0f373ffb..96ee7349 100644 --- a/Packages/vChewing_Tekkon/README.md +++ b/Packages/vChewing_Tekkon/README.md @@ -179,97 +179,12 @@ extension InputHandler { 但對注拼槽的處理都是一樣的。 -這裡分享一下威注音輸入法在 InputHandler 內對 _composer 的用法。 +有關於威注音輸入法在 InputHandler 內對 _composer 的用法,請洽其倉庫內的 InputHandler_HandleComposition.swift 檔案。 如果收到的按鍵訊號是 BackSpace 的話,可以用 _composer.doBackSpace() 來移除注拼槽內最前方的元素。 鐵恨引擎的注拼槽 Composer 型別內的函式都有對應的詳細註解說明。這裡不再贅述。 - - -> (這裡的範例取自威注音,只用作演示用途。威注音實際的 codebase 可能會有出入。請留意這一段內的漢語註解。) -> -> (不是所有輸入法都有狀態管理引擎,請根據各自專案的實際情況來結合理解這段程式碼。) - -```swift -// MARK: Handle BPMF Keys. - -var keyConsumedByReading = false -let skipPhoneticHandling = input.isReservedKey || input.isControlHold || input.isOptionHold - -// See if Phonetic reading is valid. -// 這裡 inputValidityCheck() 是讓 _composer 檢查 charCode 這個 UniChar 是否是合法的注音輸入。 -// 如果是的話,就將這次傳入的這個按鍵訊號塞入 _composer 內且標記為「keyConsumedByReading」。 -// 函式 _composer.receiveKey() 可以既接收 String 又接收 UniChar。 -if !skipPhoneticHandling && _composer.inputValidityCheck(key: charCode) { - _composer.receiveKey(fromCharCode: charCode) - keyConsumedByReading = true - - // If we have a tone marker, we have to insert the reading to the - // compositor in other words, if we don't have a tone marker, we just - // update the composing buffer. - // 沒有調號的話,只需要 updateClientComposingBuffer() 且終止處理(return true)即可。 - // 有調號的話,則不需要這樣處理,轉而繼續在此之後的處理。 - let composeReading = _composer.hasIntonation() - if !composeReading { - delegate.switchState(generateStateOfInputting()) - return true - } -} - -// 這裡不需要做排他性判斷。 -var composeReading = _composer.hasIntonation() - -// 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 "|=". -// 如果當前的按鍵是 Enter 或 Space 的話,這時就可以取出 _composer 內的注音來做檢查了。 -// 來看看詞庫內到底有沒有對應的讀音索引。這裡用了類似「|=」的判斷處理方式。 -composeReading = composeReading || (!_composer.isEmpty && (input.isSpace || input.isEnter)) -if composeReading { // 符合按鍵組合條件 - if input.isSpace && !_composer.hasIntonation() { - _composer.receiveKey(fromString: " ") // 補上空格,否則倚天忘形與許氏排列某些音無法響應不了陰平聲調。 - // 某些輸入法使用 OVMandarin 而不是鐵恨引擎,所以不需要這樣補。但鐵恨引擎對所有聲調一視同仁。 - } - let reading = _composer.getComposition() // 拿取用來進行索引檢索用的注音 - // 如果輸入法的辭典索引是漢語拼音的話,要注意上一行拿到的內容得是漢語拼音。 - - // See whether we have a unigram for this... - // 向語言模型詢問是否有對應的記錄 - if !ifLangModelHasUnigrams(forKey: reading) { // 如果沒有的話 - vCLog("B49C0979:語彙庫內無「\(reading)」的匹配記錄。") - delegate.callError("114514") // 向狀態管理引擎回呼一個錯誤狀態 - _composer.clear() // 清空注拼槽的內容 - // 根據「天權星引擎 (威注音) 或 Gramambular (小麥) 的組字器是否為空」來判定回呼哪一種狀態 - delegate.switchState( - (getCompositorLength() == 0) ? InputState.EmptyIgnoringPreviousState() : generateStateOfInputting()) - return true // 向 IMK 報告說這個按鍵訊號已經被輸入法攔截處理了 - } - - // ... and insert it into the grid... - // 將該讀音插入至天權星(或 Gramambular)組字器內的軌格當中 - insertReadingToCompositorAtCursor(reading: reading) - - // ... then walk the grid... - // 讓組字器反爬軌格 - let poppedText = popOverflowComposingTextAndWalk() - - // ... get and tweak override model suggestion if possible... - // 看看半衰記憶模組是否會對目前的狀態給出自動選字建議 - dealWithOverrideModelSuggestions() - - // ... then update the text. - // 之後就是更新組字區了。先清空注拼槽的內容。 - _composer.clear() - // 再以回呼組字狀態的方式來執行updateClientComposingBuffer() - let inputting = generateStateOfInputting() - inputting.poppedText = poppedText - delegate.switchState(inputting) - - return true // 向 IMK 報告說這個按鍵訊號已經被輸入法攔截處理了 -} -``` - ## 著作權 (Credits) - (c) 2022 and onwards The vChewing Project (MIT-NTL License). diff --git a/Source/Modules/InputHandler_HandleComposition.swift b/Source/Modules/InputHandler_HandleComposition.swift index 527027cb..2c9a866d 100644 --- a/Source/Modules/InputHandler_HandleComposition.swift +++ b/Source/Modules/InputHandler_HandleComposition.swift @@ -52,7 +52,7 @@ extension InputHandler { theComposer.intonation.clear() // 檢查新的漢字字音是否在庫。 let temporaryReadingKey = theComposer.getComposition() - if currentLM.hasUnigramsFor(key: theComposer.getComposition()) { + if currentLM.hasUnigramsFor(key: temporaryReadingKey) { compositor.dropKey(direction: .rear) walk() // 這裡必須 Walk 一次、來更新目前被 walk 的內容。 composer = theComposer @@ -63,7 +63,8 @@ extension InputHandler { } } - composer.receiveKey(fromString: input.text) + // 鐵恨引擎並不具備對 Enter (CR / LF) 鍵的具體判斷能力,所以在這裡單獨處理。 + composer.receiveKey(fromString: input.isEnter ? " " : input.text) keyConsumedByReading = true // 沒有調號的話,只需要 setInlineDisplayWithCursor() 且終止處理(return true)即可。 @@ -74,20 +75,16 @@ extension InputHandler { } } + let readingKey = composer.getComposition() // 拿取用來進行索引檢索用的注音。 + // 如果輸入法的辭典索引是漢語拼音的話,要注意上一行拿到的內容得是漢語拼音。 var composeReading = composer.hasIntonation() && composer.inputValidityCheck(key: input.charCode) // 這裡不需要做排他性判斷。 - // 如果當前的按鍵是 Enter 或 Space 的話,這時就可以取出 composer 內的注音來做檢查了。 // 來看看詞庫內到底有沒有對應的讀音索引。這裡用了類似「|=」的判斷處理方式。 + // 這裡必須使用 composer.value.isEmpty,因為只有這樣才能真正檢測 composer 是否已經有陰平聲調了。 composeReading = composeReading || (!composer.isEmpty && (input.isSpace || input.isEnter)) + // readingKey 不能為空。 + composeReading = composeReading && !readingKey.isEmpty if composeReading { - if input.isSpace, !composer.hasIntonation() { - // 補上空格,否則倚天忘形與許氏排列某些音無法響應不了陰平聲調。 - // 小麥注音因為使用 OVMandarin,所以不需要這樣補。但鐵恨引擎對所有聲調一視同仁。 - composer.receiveKey(fromString: " ") - } - let readingKey = composer.getComposition() // 拿取用來進行索引檢索用的注音。 - // 如果輸入法的辭典索引是漢語拼音的話,要注意上一行拿到的內容得是漢語拼音。 - // 向語言模型詢問是否有對應的記錄。 if !currentLM.hasUnigramsFor(key: readingKey) { delegate.callError("B49C0979:語彙庫內無「\(readingKey)」的匹配記錄。") @@ -155,7 +152,12 @@ extension InputHandler { } /// 是說此時注拼槽並非為空、卻還沒組音。這種情況下只可能是「注拼槽內只有聲調」。 + /// 但這裡不處理陰平聲調。 if keyConsumedByReading { + if readingKey.isEmpty { + composer.clear() + return nil + } // 以回呼組字狀態的方式來執行 setInlineDisplayWithCursor()。 delegate.switchState(generateStateOfInputting()) return true diff --git a/Source/Modules/InputHandler_HandleInput.swift b/Source/Modules/InputHandler_HandleInput.swift index 48e34bb7..50836800 100644 --- a/Source/Modules/InputHandler_HandleInput.swift +++ b/Source/Modules/InputHandler_HandleInput.swift @@ -114,7 +114,7 @@ extension InputHandler { // MARK: 用上下左右鍵呼叫選字窗 (Calling candidate window using Up / Down or PageUp / PageDn.) - if state.hasComposition, isComposerOrCalligrapherEmpty, !input.isOptionHold, + candidateWindowProcessing: if state.hasComposition, isComposerOrCalligrapherEmpty, !input.isOptionHold, input.isCursorClockLeft || input.isCursorClockRight || input.isSpace || input.isPageDown || input.isPageUp || (input.isTab && prefs.specifyShiftTabKeyBehavior) { @@ -140,6 +140,7 @@ extension InputHandler { return rotateCandidate(reverseOrder: input.isCommandHold) } } + if compositor.isEmpty { break candidateWindowProcessing } // 開始決定是否切換至選字狀態。 let candidateState: IMEStateProtocol = generateStateOfCandidates() _ = candidateState.candidates.isEmpty ? delegate.callError("3572F238") : delegate.switchState(candidateState)