Skip to content

Fixes navigation between word boundaries #348

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

Merged
merged 5 commits into from
Feb 23, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import UIKit
final class TextInputStringTokenizer: UITextInputStringTokenizer {
var lineManager: LineManager
var stringView: StringView
// Used to ensure we can workaround bug where multi-stage input, like when entering Korean text
// does not work properly. If we do not treat navigation between word boundies as a special case then
// navigating with Shift + Option + Arrow Keys followed by Shift + Arrow Keys will not work correctly.
var didCallPositionFromPositionToWordBoundary = false

private let lineControllerStorage: LineControllerStorage
private var newlineCharacters: [Character] {
Expand Down Expand Up @@ -206,6 +210,7 @@ private extension TextInputStringTokenizer {
guard let indexedPosition = position as? IndexedPosition else {
return nil
}
didCallPositionFromPositionToWordBoundary = true
let location = indexedPosition.index
let alphanumerics = CharacterSet.alphanumerics
if direction.isForward {
Expand Down
12 changes: 12 additions & 0 deletions Sources/Runestone/TextView/Core/TextInputView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ final class TextInputView: UIView, UITextInput {
shouldNotifyInputDelegate = true
didCallPositionFromPositionInDirectionWithOffset = false
}
// This is a consequence of our workaround that ensures multi-stage input, such as when entering Korean,
// works correctly. The workaround causes bugs when selecting words using Shift + Option + Arrow Keys
// followed by Shift + Arrow Keys if we do not treat it as a special case.
// The consequence of not having this workaround is that Shift + Arrow Keys may adjust the wrong end of
// the selected text when followed by navigating between word boundaries usign Shift + Option + Arrow Keys.
if customTokenizer.didCallPositionFromPositionToWordBoundary && !didCallDeleteBackward {
shouldNotifyInputDelegate = true
customTokenizer.didCallPositionFromPositionToWordBoundary = false
}
didCallDeleteBackward = false
notifyInputDelegateAboutSelectionChangeInLayoutSubviews = !shouldNotifyInputDelegate
if shouldNotifyInputDelegate {
inputDelegate?.selectionWillChange(self)
Expand Down Expand Up @@ -594,6 +604,7 @@ final class TextInputView: UIView, UITextInput {
private var notifyInputDelegateAboutSelectionChangeInLayoutSubviews = false
private var notifyDelegateAboutSelectionChangeInLayoutSubviews = false
private var didCallPositionFromPositionInDirectionWithOffset = false
private var didCallDeleteBackward = false
private var hasDeletedTextWithPendingLayoutSubviews = false
private var preserveUndoStackWhenSettingString = false
private var cancellables: [AnyCancellable] = []
Expand Down Expand Up @@ -1116,6 +1127,7 @@ extension TextInputView {
}

func deleteBackward() {
didCallDeleteBackward = true
guard let selectedRange = markedRange ?? selectedRange, selectedRange.length > 0 else {
return
}
Expand Down