Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

変換候補選択時に右キーでページ遷移できない場合にクラッシュするバグを修正 #275

Merged
merged 2 commits into from
Jan 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 37 additions & 39 deletions macSKK/StateMachine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1054,37 +1054,7 @@ final class StateMachine {
} else {
diff = 1
}
if selecting.candidateIndex + diff < selecting.candidates.count {
let newSelectingState = selecting.addCandidateIndex(diff: diff)
state.inputMethod = .selecting(newSelectingState)
updateCandidates(selecting: newSelectingState)
} else {
if case .register(let registerState, let prev) = specialState {
state.specialState = .register(RegisterState(
prev: RegisterState.PrevState(
mode: selecting.prev.mode,
composing: selecting.prev.composing),
yomi: selecting.yomi),
prev: prev + [registerState])
} else if specialState != nil {
state.inputMethod = .normal
state.inputMode = selecting.prev.mode
} else {
state.specialState = .register(
RegisterState(
prev: RegisterState.PrevState(
mode: selecting.prev.mode,
composing: selecting.prev.composing),
yomi: selecting.yomi),
prev: [])
state.inputMethod = .normal
state.inputMode = .hiragana
inputMethodEventSubject.send(.modeChanged(.hiragana, action.cursorPosition))
}
updateCandidates(selecting: nil)
}
updateMarkedText()
return true
return handleSelectingNext(action, diff: diff, selecting: selecting, specialState: specialState)
case .backwardCandidate:
return handleSelectingPrevious(diff: -1, selecting: selecting)
case .tab:
Expand All @@ -1108,14 +1078,8 @@ final class StateMachine {
return true
}
case .right:
if selecting.candidateIndex >= inlineCandidateCount {
// 次ページの先頭
let diff = displayCandidateCount - (selecting.candidateIndex - inlineCandidateCount) % displayCandidateCount
return handleSelectingPrevious(diff: diff, selecting: selecting)
} else {
// AquaSKKと同様に何もしない (IMKCandidates表示時はそちらの移動に使われる)
return true
}
let diff = displayCandidateCount - (selecting.candidateIndex - inlineCandidateCount) % displayCandidateCount
return handleSelectingNext(action, diff: diff, selecting: selecting, specialState: specialState)
case .startOfLine:
// 現ページの先頭
let diff = -(selecting.candidateIndex - inlineCandidateCount) % displayCandidateCount
Expand Down Expand Up @@ -1206,6 +1170,40 @@ final class StateMachine {
return true
}

@MainActor private func handleSelectingNext(_ action: Action, diff: Int, selecting: SelectingState, specialState: SpecialState?) -> Bool {
if selecting.candidateIndex + diff < selecting.candidates.count {
let newSelectingState = selecting.addCandidateIndex(diff: diff)
state.inputMethod = .selecting(newSelectingState)
updateCandidates(selecting: newSelectingState)
} else {
if case .register(let registerState, let prev) = specialState {
state.specialState = .register(RegisterState(
prev: RegisterState.PrevState(
mode: selecting.prev.mode,
composing: selecting.prev.composing),
yomi: selecting.yomi),
prev: prev + [registerState])
} else if specialState != nil {
state.inputMethod = .normal
state.inputMode = selecting.prev.mode
} else {
state.specialState = .register(
RegisterState(
prev: RegisterState.PrevState(
mode: selecting.prev.mode,
composing: selecting.prev.composing),
yomi: selecting.yomi),
prev: [])
state.inputMethod = .normal
state.inputMode = .hiragana
inputMethodEventSubject.send(.modeChanged(.hiragana, action.cursorPosition))
}
updateCandidates(selecting: nil)
}
updateMarkedText()
return true
}

func setMode(_ mode: InputMode) {
state.inputMode = mode
}
Expand Down
54 changes: 54 additions & 0 deletions macSKKTests/StateMachineTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2623,6 +2623,60 @@ final class StateMachineTests: XCTestCase {
wait(for: [expectation], timeout: 1.0)
}

@MainActor func testHandleSelectingLeftRight() {
Global.dictionary.setEntries(["あ": "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".map { Word(String($0)) }])

let stateMachine = StateMachine(initialState: IMEState(inputMode: .hiragana))
let expectation = XCTestExpectation()
expectation.expectedFulfillmentCount = 2
stateMachine.inputMethodEvent.collect(12).sink { events in
XCTAssertEqual(events[0], .markedText(MarkedText([.markerCompose, .plain("あ")])))
XCTAssertEqual(events[1], .markedText(MarkedText([.markerSelect, .emphasized("1")])))
XCTAssertEqual(events[2], .markedText(MarkedText([.markerSelect, .emphasized("2")])))
XCTAssertEqual(events[3], .markedText(MarkedText([.markerSelect, .emphasized("3")])))
XCTAssertEqual(events[4], .markedText(MarkedText([.markerSelect, .emphasized("4")])), "変換候補パネルが表示開始")
XCTAssertEqual(events[5], .markedText(MarkedText([.markerSelect, .emphasized("D")])), "9個先のDを表示")
XCTAssertEqual(events[6], .markedText(MarkedText([.markerSelect, .emphasized("M")])), "9個先のMを表示")
XCTAssertEqual(events[7], .markedText(MarkedText([.markerSelect, .emphasized("N")])))
XCTAssertEqual(events[8], .markedText(MarkedText([.markerSelect, .emphasized("V")])), "Mの9個先のVを表示")
XCTAssertEqual(events[9], .markedText(MarkedText([.markerSelect, .emphasized("W")])))
XCTAssertEqual(events[10], .modeChanged(.hiragana, .zero))
XCTAssertEqual(events[11], .markedText(MarkedText([.plain("[登録:あ]")])))
expectation.fulfill()
}.store(in: &cancellables)
stateMachine.candidateEvent.collect(9).sink { events in
XCTAssertEqual(events[0]?.selected.word, "1")
XCTAssertEqual(events[1]?.selected.word, "2")
XCTAssertEqual(events[2]?.selected.word, "3")
XCTAssertEqual(events[3]?.selected.word, "4")
XCTAssertEqual(events[3]?.page?.current, 0, "0オリジン")
XCTAssertEqual(events[3]?.page?.total, 4, "35個の変換候補があり、最初3つはインライン表示して残りを4ページで表示する")
XCTAssertEqual(events[4]?.selected.word, "D")
XCTAssertEqual(events[4]?.page?.current, 1)
XCTAssertEqual(events[5]?.selected.word, "M")
XCTAssertEqual(events[5]?.page?.current, 2)
XCTAssertEqual(events[6]?.selected.word, "N")
XCTAssertEqual(events[6]?.page?.current, 2)
XCTAssertEqual(events[7]?.selected.word, "V")
XCTAssertEqual(events[7]?.page?.current, 3)
XCTAssertEqual(events[8]?.selected.word, "W")
XCTAssertEqual(events[8]?.page?.current, 3)
expectation.fulfill()
}.store(in: &cancellables)
XCTAssertTrue(stateMachine.handle(printableKeyEventAction(character: "a", withShift: true)))
XCTAssertTrue(stateMachine.handle(printableKeyEventAction(character: " ")))
XCTAssertTrue(stateMachine.handle(printableKeyEventAction(character: " ")))
XCTAssertTrue(stateMachine.handle(printableKeyEventAction(character: " ")))
XCTAssertTrue(stateMachine.handle(printableKeyEventAction(character: " ")))
XCTAssertTrue(stateMachine.handle(rightKeyAction))
XCTAssertTrue(stateMachine.handle(rightKeyAction))
XCTAssertTrue(stateMachine.handle(downKeyAction))
XCTAssertTrue(stateMachine.handle(rightKeyAction))
XCTAssertTrue(stateMachine.handle(downKeyAction))
XCTAssertTrue(stateMachine.handle(rightKeyAction))
wait(for: [expectation], timeout: 1.0)
}

@MainActor func testHandleSelectingCtrlACtrlE() {
Global.dictionary.setEntries(["と": [Word("戸"), Word("都"), Word("徒"), Word("途"), Word("斗")]])

Expand Down
Loading