Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 10, 2025

Replaces two boolean settings (kUseJKtoMoveCompositorCursorInCandidateState, kUseHLtoMoveCompositorCursorInCandidateState) with a single integer enum kCandidateStateJKHLBehavior offering three mutually exclusive behaviors:

  • 0: Unassigned (default) - JKHL remain as candidate selection keys
  • 1: JK moves composition buffer cursor; HL flips candidate row/column
  • 2: HL moves composition buffer cursor; JK flips candidate row/column

Changes

Core Settings Layer

  • Added kCandidateStateJKHLBehavior to UserDef enum with integer dataType
  • Updated PrefMgrProtocol and PrefMgr with new property (default: 0)
  • Added validation in fixOddPreferencesCore() to constrain values to [0,1,2]
  • Removed deprecated boolean properties from all preference layers

Input Handling

InputHandler_HandleCandidate.swift: Replaced boolean checks with enum comparisons:

let allowMovingCursorByJK = allowMovingCompositorCursor && prefs.candidateStateJKHLBehavior == 1
let allowMovingCursorByHL = allowMovingCompositorCursor && prefs.candidateStateJKHLBehavior == 2

InputSession_HandleEvent.swift: Added row-flipping key translation. When in candidate state, dynamically converts JKHL to arrow keys based on window orientation:

// Converts J→Down/Right, K→Up/Left, H→Left/Up, L→Right/Down
// Orientation-aware: adjusts based on isVerticalCandidateWindow

UI Updates

  • SwiftUI Settings: Renders as RadioGroupPickerStyle dropdown with three options
  • AppKit Settings: Added to candidate settings tab with sanity check callback
  • Updated candidate key validator to exclude JK (behavior=1) or HL (behavior=2) from selection keys

Localization

Added i18n keys for en/ja/zh-Hans/zh-Hant:

  • kCandidateStateJKHLBehavior.shortTitle: "JKHL key behavior in candidate window"
  • kCandidateStateJKHLBehavior.description: Warning about auto-exclusion from candidate keys and %quick compatibility
  • kCandidateStateJKHLBehavior.option.{0,1,2}: Per-option descriptions

Removed deprecated localization keys for the two boolean settings.

Technical Notes

The row-flipping logic sits in SessionProtocol (not InputHandlerProtocol) to maintain code independence and avoid structural similarities with external implementations per issue requirements.

Original prompt

This section details on the original issue you should resolve

<issue_title>[Feature] +UserDef.kCandidateStateJKHLBehavior and +PrefMgrProtocol.candidateStateJKHLBehavior.</issue_title>
<issue_description>

任務目標

將 UserDef 與 PrefMgr 對應的 kUseJKtoMoveCompositorCursorInCandidateStatekUseHLtoMoveCompositorCursorInCandidateState 這兩個選項的行為做整合、以 kCandidateStateJKHLBehavior 取而代之。

// SPECIAL NOTICE TO COPILOT:

ENSURE YOUR IMPLEMENTATION IS DIFFERENT FROM `https://github.com/openvanilla/McBopomofo/pull/708`.

EVERY PLAGIARISM-LEVEL SIMILARITY WILL BRING DEVASTATING RISK OF BEING DEFAMED BY BAD-INTENTION-DRIVEN INDIVIDUALS.

(This notice will be referred as `code-similarity-concerns` in the rest of this article.)

具體施工方案:

Step 1: UserDefaults & UserDef

UserDef 新增 case kCandidateStateJKHLBehavior 且 rawValue 是 CandidateStateJKHLBehavior

    case .kCandidateStateJKHLBehavior: return .init(
        userDef: self, shortTitle: "i18n:UserDef.kCandidateStateJKHLBehavior.shortTitle",
        description: "i18n:UserDef.kCandidateStateJKHLBehavior.description",
        options: [
          0: "i18n:UserDef.kCandidateStateJKHLBehavior.option.0",
          1: "i18n:UserDef.kCandidateStateJKHLBehavior.option.1",
          2: "i18n:UserDef.kCandidateStateJKHLBehavior.option.2",
        ]
      )

Data type of case kCandidateStateJKHLBehavior: Integer.

Since we provide 3 options for this case, the actual UI of this UserPref in Settings Window (both SwiftUI and AppKit) will be rendered as a dropdown menu.

English Localization (you may ameliorate its expression):

"i18n:UserDef.kCandidateStateJKHLBehavior.shortTitle" = "JKHL key behavior in candidate window:";
"i18n:UserDef.kCandidateStateJKHLBehavior.description" = "⚠︎ Regarding these specific composition-buffer-cursor-flipping-keys: 1) This will automatically prevent them to be used as candidate keys; 2) They won't work with ‘%quick’ candidates in cassette mode.";
"i18n:UserDef.kCandidateStateJKHLBehavior.option.0" = "Unassigned";
"i18n:UserDef.kCandidateStateJKHLBehavior.option.1" = "JK to move cursor in the composition buffer; HL to flip current row / column";
"i18n:UserDef.kCandidateStateJKHLBehavior.option.2" = "HL to move cursor in the composition buffer; JK to flip current row / column";

flip current row / column is the action in the candidate window determining which candidate is the currently-highlighted one. The JK/HL keys set for this purposes will be referred as "row-flipping-keys" in the rest of this article.

Finish all other translations in JP, zh-Hans, and zh-Hant-TW. Here's the term table (separated by TAB char):

TERM	JP	zh-Hans	zhHant-TW
Composition Buffer	入力緩衝列	組字区	組字區
Candidate Window	候補陳列ウィンドウ	选字窗	選字窗

(After Step 2 you may remove kUseJKtoMoveCompositorCursorInCandidateState & kUseHLtoMoveCompositorCursorInCandidateState from UserDef.)

Step 2: PrefMgrProtocol and PrefMgr:

  1. Remove useJKtoMoveCompositorCursorInCandidateState and useHLtoMoveCompositorCursorInCandidateState.
  2. Add candidateStateJKHLBehavior binded to kCandidateStateJKHLBehavior with default value 0.

Step 3: InputHandlerProtocol surgery -- Fix the affected bindings regarding changes in Step 2.

  • The "JK / HL to move composition-buffer-cursor" feature only needs to change their prefs bindings to the new prefs.candidateStateJKHLBehavior one.

Step 4: SessionProtocol tweaks:

  • Regarding the row-flipping-keys: In the InputSession_HandleEvent.swift file around the blank line at line 149 you add a new processing step: If state.isCandidateContainer, then use eventToDeal.reinitiate to try retranslate the row-flipping-keys to the correct arrow key (depending on whether the actual candidate window layout is line-as-row or line-as-column).

    • Regarding why we don't put this in InputHandlerProtocol.handleCandidate(: This reduces the risks of the above-mentioned code-similarity-concerns.
  • You may add unit tests of this PR against MainAssembly if you wish.

Step 4:

Fix the Settings UI (both SwiftUI and AppKit version).

(Your response language in this dialog will always be `zh-Hant-TW.)</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 5 commits December 10, 2025 19:42
Co-authored-by: ShikiSuen <3164826+ShikiSuen@users.noreply.github.com>
Co-authored-by: ShikiSuen <3164826+ShikiSuen@users.noreply.github.com>
…ursor...)

Co-authored-by: ShikiSuen <3164826+ShikiSuen@users.noreply.github.com>
Co-authored-by: ShikiSuen <3164826+ShikiSuen@users.noreply.github.com>
Co-authored-by: ShikiSuen <3164826+ShikiSuen@users.noreply.github.com>
Copilot AI changed the title [WIP] Integrate UserDef and PrefMgr for candidateStateJKHLBehavior Consolidate JKHL candidate state behavior into single enum setting Dec 10, 2025
Copilot AI requested a review from ShikiSuen December 10, 2025 19:57
@ShikiSuen ShikiSuen marked this pull request as ready for review December 11, 2025 04:42
@ShikiSuen ShikiSuen merged commit 8a17f48 into main Dec 11, 2025
1 check passed
@ShikiSuen ShikiSuen deleted the copilot/integrate-candidate-state-behavior branch December 11, 2025 04:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] +UserDef.kCandidateStateJKHLBehavior and +PrefMgrProtocol.candidateStateJKHLBehavior.

2 participants