Willeke указал мне на NSTextInputClient, который до сих пор является лучшим решением. Единственный пример Apple находится в Objective C, запутан и слишком сложен для того, что я пытался сделать, поэтому я воспроизводю здесь свой код.
Предостережение: это не полная реализация NSTextInputClient, достаточно для захвата ввода смайликов
Я создал подкласс NSButton:
class TextReceiverButton: NSButton, NSTextInputClient {
//specific methods
func setButtonTitle(_ string: String?){
self.title = string ?? ?
}
//NSTextInputClient methods
func insertText(_ string: Any, replacementRange: NSRange) {
let receivedText = string as? String
setButtonTitle(receivedText)
}
func validAttributesForMarkedText() -> [NSAttributedString.Key] {
return [.font, .paragraphStyle, .writingDirection]
}
//Omitted: For anything else that wants a value, I return NSMakeRange(0, 0)/NSRect.zero or 0 as well as false for marked text and nil for attributed substring
}
(если вы добавите протокол в свой класс, он будет предлагают заглушки для других методов)
Полный набор для NSAttributedString.Key:
[.font, .foregroundColor, .glyphInfo, .kern, .ligature, .link, .markedClauseSegment, .obliqueness, .paragraphStyle, .shadow, .spellingState, .strikethroughColor, .strikethroughStyle, .strokeColor, .strokeWidth, .superscript, .textAlternatives, .textEffect, .toolTip, .underlineColor, .underlineStyle, .verticalGlyphForm, .writingDirection]
(я тестировал короткую форму с простыми и составными смайликами, и больше ничего не нужно.)
Действие кнопки:
@IBAction func displayEmojiInButton(_ sender: Any) {
NSApp.orderFrontCharacterPalette(self)
view.window?.makeFirstResponder(textReceiverButton)
}
Проблемы / Ошибки
В документе NSTextInputClient говорится, что «вы можете создать подкласс NSView», а код Apple превращает NSView в полнофункциональный класс текстового представления (получение и рисование) (я не могу его создать, но полагаю, что он работал). Так что теоретически вы должны иметь возможность использовать тот же код для NSTextField, который также в конечном итоге наследуется от NSView.
Однако оказывается, что NSTextField отображает ошибку «CharacterPalette якобы открывается, но никогда не отображает», о которой я говорил ранее. ; хотя он работает с NSView. (Я не проверял это дальше). Более того, NSTextInputClient не является полной заменой NSTextView: он не получает ввод от средства просмотра с клавиатуры. (См. Ответ / комментарий Willecke для объяснения / решения этих вопросов).
Verdict
NSApp.orderFrontCharacterPalette (self) не работает 95% времени при вызове из представления в непосредственной близости от представления вкладок (в splitView рядом с TabViewController, встроенным в TabViewController), поэтому, хотя этот код может быть правильным, он также часто бесполезен, по крайней мере, до 10.13.