-
-
Save wearhere/f46ab9d837acaeaabfa86a813c44ad25 to your computer and use it in GitHub Desktop.
// | |
// documentProxy.swift | |
// KeyboardKitDemoKeyboard | |
// | |
// Created by Jeffrey Wear on 4/28/20. | |
// | |
import UIKit | |
class TextDocumentProxy<TextDocument: UIResponder & UITextInput>: NSObject, UITextDocumentProxy { | |
init(document: TextDocument) { | |
self.document = document | |
super.init() | |
} | |
private unowned let document: TextDocument | |
// MARK: - UITextDocumentProxy | |
var documentInputMode: UITextInputMode? { | |
document.textInputMode | |
} | |
var documentContextAfterInput: String? { | |
guard let selectedTextRange = document.selectedTextRange else { | |
return nil | |
} | |
guard let rangeAfterInput = document.textRange(from: selectedTextRange.end, to: document.endOfDocument) else { | |
return nil | |
} | |
return document.text(in: rangeAfterInput) | |
} | |
var documentContextBeforeInput: String? { | |
guard let selectedTextRange = document.selectedTextRange else { | |
return nil | |
} | |
guard let rangeBeforeInput = document.textRange(from: document.beginningOfDocument, to: selectedTextRange.start) else { | |
return nil | |
} | |
return document.text(in: rangeBeforeInput) | |
} | |
// https://stackoverflow.com/a/41023439/495611 suggests adjusting the text | |
// position (i.e. moving the cursor) by adjusting the selected text range. | |
func adjustTextPosition(byCharacterOffset offset: Int) { | |
guard let selectedTextRange = document.selectedTextRange else { return } | |
// Not sure what's supposed to happen if the range is non-empty. Let's | |
// abort if it is. | |
guard selectedTextRange.isEmpty else { return } | |
// Now that it's empty, the start and end should be the same. Move that position. | |
// The guard is a bounds check. | |
guard let newPosition = document.position(from: selectedTextRange.start, offset: offset) else { return } | |
document.selectedTextRange = document.textRange(from: newPosition, to: newPosition) | |
} | |
var selectedText: String? { | |
guard let selectedTextRange = document.selectedTextRange else { | |
return nil | |
} | |
return document.text(in: selectedTextRange) | |
} | |
let documentIdentifier: UUID = UUID() | |
func setMarkedText(_ markedText: String, selectedRange: NSRange) { | |
document.setMarkedText(markedText, selectedRange: selectedRange) | |
} | |
func unmarkText() { | |
document.unmarkText() | |
} | |
// MARK: - UIKeyInput | |
func insertText(_ text: String) { | |
document.insertText(text) | |
} | |
func deleteBackward() { | |
document.deleteBackward() | |
} | |
var hasText: Bool { | |
document.hasText | |
} | |
} | |
Thanks @danielsaidi for Reply
No, I didn't use KeyboardKit Pro.
I just tested your demo code.
In my custom keyboard, I used textDocumentProxy.documentContextBeforeInput, but it can't read more than 300 characters — unlike your fullDocumentContext, which reads all the text.
How can I handle large text like that? without using KeyboardKit Pro?
I see, yes the native text document proxy APIs have always been very lacking.
The full document context implementation is a Pro feature with a lot of time and effort put into it. You need a Silver license to use it. Without KeyboardKit Pro, you have to implement the logic yourself.
Best,
Daniel
@danielsaidi I respect your effort and time.
However, I am a student and don't have the budget to purchase a Silver license.
I only need this one feature to implement in my code, as it's currently blocking my app's progress.
If you could offer some support, I would be very grateful.
Hi @saqlainjamil5
Are you trying to use KeyboardKit Pro's
fullDocumentContext
feature?