11#include <QtCore/qscopedvaluerollback.h>
13#include <QtGui/qevent.h>
14#include <QtGui/qtextformat.h>
15#include <QtGui/private/qguiapplication_p.h>
16#include <QtGui/qpa/qplatformwindow.h>
20@interface QUITextPosition : UITextPosition
22@property (nonatomic) NSUInteger index;
23+ (instancetype)positionWithIndex:(NSUInteger)index;
27@implementation QUITextPosition
29+ (instancetype)positionWithIndex:(NSUInteger)index
31 QUITextPosition *pos = [[QUITextPosition alloc] init];
33 return [pos autorelease];
40@interface QUITextRange : UITextRange
42@property (nonatomic) NSRange range;
43+ (instancetype)rangeWithNSRange:(NSRange)range;
47@implementation QUITextRange
49+ (instancetype)rangeWithNSRange:(NSRange)nsrange
51 QUITextRange *range = [[self alloc] init];
52 range.range = nsrange;
53 return [range autorelease];
56- (UITextPosition *)start
58 return [QUITextPosition positionWithIndex:self.range.location];
61- (UITextPosition *)end
63 return [QUITextPosition positionWithIndex:(self.range.location + self.range.length)];
73 return (self.range.length == 0);
80@interface WrapperView : UIView
83@implementation WrapperView
85- (instancetype)initWithView:(UIView *)view
87 if (self = [self init]) {
88 [self addSubview:view];
90 self.autoresizingMask = view.autoresizingMask;
100 UIView *view = [self.subviews firstObject];
101 view.frame = self.bounds;
108- (CGSize)sizeThatFits:(CGSize)size
110 return [[self.subviews firstObject] sizeThatFits:size];
117- (
void)willMoveToWindow:(UIWindow *)window
120 [[self nextResponder] retain];
122 [[self nextResponder] autorelease];
129@implementation QIOSTextResponder {
131 QT_PREPEND_NAMESPACE(QIOSInputContext) *m_inputContext;
132 QT_PREPEND_NAMESPACE(QInputMethodQueryEvent) *m_configuredImeState;
133 BOOL m_inSendEventToFocusObject;
136- (instancetype)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)inputContext
138 if (!(self = [self init]))
141 m_inputContext = inputContext;
142 m_configuredImeState =
static_cast<QInputMethodQueryEvent*>(m_inputContext->imeState().currentState.clone());
143 m_inSendEventToFocusObject = NO;
150 delete m_configuredImeState;
154- (
QVariant)currentImeState:(Qt::InputMethodQuery)query
156 return m_inputContext->imeState().currentState.value(query);
159- (BOOL)canBecomeFirstResponder
164- (BOOL)becomeFirstResponder
166 FirstResponderCandidate firstResponderCandidate(self);
168 qImDebug() <<
"self:" << self <<
"first:" << [UIResponder qt_currentFirstResponder];
170 if (![super becomeFirstResponder]) {
171 qImDebug() << self <<
"was not allowed to become first responder";
175 qImDebug() << self <<
"became first responder";
180- (BOOL)resignFirstResponder
182 qImDebug() <<
"self:" << self <<
"first:" << [UIResponder qt_currentFirstResponder];
186 if (FirstResponderCandidate::currentCandidate() == [self nextResponder]) {
187 qImDebug(
"not allowing parent window to steal responder");
191 if (![super resignFirstResponder])
194 qImDebug() << self <<
"resigned first responder";
200 if (![UIResponder qt_currentFirstResponder] && !FirstResponderCandidate::currentCandidate()) {
203 m_inputContext->clearCurrentFocusObject();
204 }
else if ([UIResponder qt_currentFirstResponder] == [self nextResponder]) {
206 Q_ASSERT(!FirstResponderCandidate::currentCandidate());
207 if ([self currentImeState:Qt::ImEnabled].toBool()) {
210 qImDebug(
"no keyboard available, clearing focus object");
211 m_inputContext->clearCurrentFocusObject();
218 qImDebug(
"lost first responder, but not clearing focus object");
224- (UIResponder*)nextResponder
230 return (qApp->focusWindow() && qApp->focusWindow()->handle()) ?
231 reinterpret_cast<QUIView *>(qApp->focusWindow()->handle()->winId()) : 0;
236- (
void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties
238 Q_UNUSED(updatedProperties);
241- (BOOL)needsKeyboardReconfigure:(Qt::InputMethodQueries)updatedProperties
243 if (updatedProperties & Qt::ImEnabled) {
244 qImDebug() <<
"Qt::ImEnabled has changed since text responder was configured, need reconfigure";
248 if (updatedProperties & Qt::ImReadOnly) {
249 qImDebug() <<
"Qt::ImReadOnly has changed since text responder was configured, need reconfigure";
268#ifndef QT_NO_SHORTCUT
270- (
void)sendKeyPressRelease:(Qt::Key)key modifiers:(Qt::KeyboardModifiers)modifiers
272 QScopedValueRollback<BOOL> rollback(m_inSendEventToFocusObject,
true);
273 QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyPress, key, modifiers);
274 QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyRelease, key, modifiers);
277- (
void)sendShortcut:(QKeySequence::StandardKey)standardKey
279 const QKeyCombination combination = QKeySequence(standardKey)[0];
280 [self sendKeyPressRelease:combination.key() modifiers:combination.keyboardModifiers()];
285 QInputMethodQueryEvent query(Qt::ImAnchorPosition | Qt::ImCursorPosition);
286 QGuiApplication::sendEvent(QGuiApplication::focusObject(), &query);
287 int anchorPos = query.value(Qt::ImAnchorPosition).toInt();
288 int cursorPos = query.value(Qt::ImCursorPosition).toInt();
289 return anchorPos != cursorPos;
292- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
294 const bool isSelectAction =
295 action == @selector(select:) ||
296 action == @selector(selectAll:);
298 const bool isReadAction = action == @selector(copy:);
300 if (!isSelectAction && !isReadAction)
301 return [super canPerformAction:action withSender:sender];
303 const bool hasSelection = [self hasSelection];
304 return (!hasSelection && isSelectAction) || (hasSelection && isReadAction);
307- (
void)copy:(id)sender
310 [self sendShortcut:QKeySequence::Copy];
313- (
void)select:(id)sender
316 [self sendShortcut:QKeySequence::MoveToPreviousWord];
317 [self sendShortcut:QKeySequence::SelectNextWord];
320- (
void)selectAll:(id)sender
323 [self sendShortcut:QKeySequence::SelectAll];
332@implementation QIOSTextInputResponder {
333 QString m_markedText;
334 BOOL m_inSelectionChange;
337- (instancetype)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)inputContext
339 if (!(self = [super initWithInputContext:inputContext]))
342 m_inSelectionChange = NO;
344 QVariantMap platformData = m_configuredImeState->value(Qt::ImPlatformData).toMap();
345 Qt::InputMethodHints hints = Qt::InputMethodHints(m_configuredImeState->value(Qt::ImHints).toUInt());
346 Qt::EnterKeyType enterKeyType = Qt::EnterKeyType(m_configuredImeState->value(Qt::ImEnterKeyType).toUInt());
348 switch (enterKeyType) {
349 case Qt::EnterKeyReturn:
350 self.returnKeyType = UIReturnKeyDefault;
352 case Qt::EnterKeyDone:
353 self.returnKeyType = UIReturnKeyDone;
356 self.returnKeyType = UIReturnKeyGo;
358 case Qt::EnterKeySend:
359 self.returnKeyType = UIReturnKeySend;
361 case Qt::EnterKeySearch:
362 self.returnKeyType = UIReturnKeySearch;
364 case Qt::EnterKeyNext:
365 self.returnKeyType = UIReturnKeyNext;
368 self.returnKeyType = (hints & Qt::ImhMultiLine) ? UIReturnKeyDefault : UIReturnKeyDone;
372 self.secureTextEntry = BOOL(hints & Qt::ImhHiddenText);
373 self.autocorrectionType = (hints & Qt::ImhNoPredictiveText) ?
374 UITextAutocorrectionTypeNo : UITextAutocorrectionTypeDefault;
375 self.spellCheckingType = (hints & Qt::ImhNoPredictiveText) ?
376 UITextSpellCheckingTypeNo : UITextSpellCheckingTypeDefault;
378 if (hints & Qt::ImhUppercaseOnly)
379 self.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters;
380 else if (hints & Qt::ImhNoAutoUppercase)
381 self.autocapitalizationType = UITextAutocapitalizationTypeNone;
383 self.autocapitalizationType = UITextAutocapitalizationTypeSentences;
385 if (hints & Qt::ImhUrlCharactersOnly)
386 self.keyboardType = UIKeyboardTypeURL;
387 else if (hints & Qt::ImhEmailCharactersOnly)
388 self.keyboardType = UIKeyboardTypeEmailAddress;
389 else if (hints & Qt::ImhDigitsOnly)
390 self.keyboardType = UIKeyboardTypeNumberPad;
391 else if (hints & Qt::ImhDialableCharactersOnly)
392 self.keyboardType = UIKeyboardTypePhonePad;
393 else if (hints & Qt::ImhLatinOnly)
394 self.keyboardType = UIKeyboardTypeASCIICapable;
395 else if (hints & (Qt::ImhPreferNumbers | Qt::ImhFormattedNumbersOnly))
396 self.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
398 self.keyboardType = UIKeyboardTypeDefault;
400 if (UIView *inputView =
static_cast<UIView *>(platformData.value(kImePlatformDataInputView).value<
void *>()))
401 self.inputView = [[[WrapperView alloc] initWithView:inputView] autorelease];
402 if (UIView *accessoryView =
static_cast<UIView *>(platformData.value(kImePlatformDataInputAccessoryView).value<
void *>()))
403 self.inputAccessoryView = [[[WrapperView alloc] initWithView:accessoryView] autorelease];
405#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
406 if (platformData.value(kImePlatformDataHideShortcutsBar).toBool()) {
410#pragma clang diagnostic push
411#pragma clang diagnostic ignored "-Wnonnull"
412 self.inputAssistantItem.leadingBarButtonGroups = nil;
413 self.inputAssistantItem.trailingBarButtonGroups = nil;
414#pragma clang diagnostic pop
418 self.undoManager.groupsByEvent = NO;
419 [self rebuildUndoStack];
427 self.inputAccessoryView = 0;
428 [self.undoManager removeAllActions];
433- (BOOL)needsKeyboardReconfigure:(Qt::InputMethodQueries)updatedProperties
435 Qt::InputMethodQueries relevantProperties = updatedProperties;
436 if ((relevantProperties & Qt::ImEnabled)) {
441 qImDebug(
"IM was turned on, we need to check hints and platform data as well");
442 relevantProperties |= (Qt::ImHints | Qt::ImPlatformData);
446 relevantProperties &= (Qt::ImHints | Qt::ImEnterKeyType | Qt::ImPlatformData);
448 if (!relevantProperties)
449 return [super needsKeyboardReconfigure:updatedProperties];
451 for (uint i = 0; i < (
sizeof(Qt::ImQueryAll) * CHAR_BIT); ++i) {
452 if (Qt::InputMethodQuery property = Qt::InputMethodQuery(
int(updatedProperties & (1 << i)))) {
453 if ([self currentImeState:property] != m_configuredImeState->value(property)) {
454 qImDebug() << property <<
"has changed since text responder was configured, need reconfigure";
460 return [super needsKeyboardReconfigure:updatedProperties];
465 [self setMarkedText:@
"" selectedRange:NSMakeRange(0, 0)];
466 [self notifyInputDelegate:Qt::ImSurroundingText];
472 [self notifyInputDelegate:Qt::ImSurroundingText];
477#ifndef QT_NO_SHORTCUT
479- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
481 bool isEditAction = (action == @selector(cut:)
482 || action == @selector(copy:)
483 || action == @selector(paste:)
484 || action == @selector(
delete:)
485 || action == @selector(toggleBoldface:)
486 || action == @selector(toggleItalics:)
487 || action == @selector(toggleUnderline:)
488 || action == @selector(undo)
489 || action == @selector(redo));
491 bool isSelectAction = (action == @selector(select:)
492 || action == @selector(selectAll:)
493 || action == @selector(paste:)
494 || action == @selector(undo)
495 || action == @selector(redo));
497 const bool unknownAction = !isEditAction && !isSelectAction;
498 const bool hasSelection = [self hasSelection];
501 return [super canPerformAction:action withSender:sender];
503 QObject *focusObject = QGuiApplication::focusObject();
504 if (focusObject && focusObject->property(
"qt_im_readonly").toBool()) {
506 if (action == @selector(cut:)
507 || action == @selector(paste:)
508 || action == @selector(
delete:))
510 if (action == @selector(copy:))
513 return (hasSelection && isEditAction) || (!hasSelection && isSelectAction);
516- (
void)cut:(id)sender
519 [self sendShortcut:QKeySequence::Cut];
522- (
void)paste:(id)sender
525 [self sendShortcut:QKeySequence::Paste];
528- (
void)
delete:(id)sender
531 [self sendShortcut:QKeySequence::Delete];
534- (
void)toggleBoldface:(id)sender
537 [self sendShortcut:QKeySequence::Bold];
540- (
void)toggleItalics:(id)sender
543 [self sendShortcut:QKeySequence::Italic];
546- (
void)toggleUnderline:(id)sender
549 [self sendShortcut:QKeySequence::Underline];
556 [self sendShortcut:QKeySequence::Undo];
557 [self rebuildUndoStack];
562 [self sendShortcut:QKeySequence::Redo];
563 [self rebuildUndoStack];
568 NSUndoManager *undoMgr = self.undoManager;
569 [undoMgr beginUndoGrouping];
570 [undoMgr registerUndoWithTarget:self selector:@selector(redo) object:nil];
571 [undoMgr endUndoGrouping];
574- (
void)rebuildUndoStack
576 dispatch_async(dispatch_get_main_queue (), ^{
581 NSUndoManager *undoMgr = self.undoManager;
582 [undoMgr removeAllActions];
584 [undoMgr beginUndoGrouping];
585 [undoMgr registerUndoWithTarget:self selector:@selector(undo) object:nil];
586 [undoMgr endUndoGrouping];
587 [undoMgr beginUndoGrouping];
588 [undoMgr registerUndoWithTarget:self selector:@selector(undo) object:nil];
589 [undoMgr endUndoGrouping];
592 [undoMgr beginUndoGrouping];
593 [undoMgr registerUndoWithTarget:self selector:@selector(registerRedo) object:nil];
594 [undoMgr endUndoGrouping];
595 [undoMgr beginUndoGrouping];
596 [undoMgr registerUndoWithTarget:self selector:@selector(registerRedo) object:nil];
597 [undoMgr endUndoGrouping];
617- (
void)keyCommandTriggered:(UIKeyCommand *)keyCommand
619 Qt::Key key = Qt::Key_unknown;
620 Qt::KeyboardModifiers modifiers = Qt::NoModifier;
622 if (keyCommand.input == UIKeyInputLeftArrow)
624 else if (keyCommand.input == UIKeyInputRightArrow)
626 else if (keyCommand.input == UIKeyInputUpArrow)
628 else if (keyCommand.input == UIKeyInputDownArrow)
633 if (keyCommand.modifierFlags & UIKeyModifierAlternate)
634 modifiers |= Qt::AltModifier;
635 if (keyCommand.modifierFlags & UIKeyModifierShift)
636 modifiers |= Qt::ShiftModifier;
637 if (keyCommand.modifierFlags & UIKeyModifierCommand)
638 modifiers |= Qt::ControlModifier;
640 [self sendKeyPressRelease:key modifiers:modifiers];
643- (
void)addKeyCommandsToArray:(NSMutableArray<UIKeyCommand *> *)array key:(NSString *)key
645 SEL s = @selector(keyCommandTriggered:);
646 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:0 action:s]];
647 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierShift action:s]];
648 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierAlternate action:s]];
649 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierAlternate|UIKeyModifierShift action:s]];
650 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierCommand action:s]];
651 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierCommand|UIKeyModifierShift action:s]];
654- (NSArray<UIKeyCommand *> *)keyCommands
658 static dispatch_once_t once;
659 static NSMutableArray<UIKeyCommand *> *array;
661 dispatch_once(&once, ^{
666 array = [NSMutableArray<UIKeyCommand *>
new];
667 [self addKeyCommandsToArray:array key:UIKeyInputUpArrow];
668 [self addKeyCommandsToArray:array key:UIKeyInputDownArrow];
669 [self addKeyCommandsToArray:array key:UIKeyInputLeftArrow];
670 [self addKeyCommandsToArray:array key:UIKeyInputRightArrow];
680- (
void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties
687 if (m_inSendEventToFocusObject)
690 if (updatedProperties & (Qt::ImCursorPosition | Qt::ImAnchorPosition)) {
691 QScopedValueRollback<BOOL> rollback(m_inSelectionChange,
true);
692 [self.inputDelegate selectionWillChange:self];
693 [self.inputDelegate selectionDidChange:self];
696 if (updatedProperties & Qt::ImSurroundingText) {
697 [self.inputDelegate textWillChange:self];
698 [self.inputDelegate textDidChange:self];
702- (
void)sendEventToFocusObject:(QEvent &)e
704 QObject *focusObject = QGuiApplication::focusObject();
711 QScopedValueRollback<BOOL> rollback(m_inSendEventToFocusObject);
712 m_inSendEventToFocusObject = YES;
713 QCoreApplication::sendEvent(focusObject, &e);
716- (id<UITextInputTokenizer>)tokenizer
718 return [[[UITextInputStringTokenizer alloc] initWithTextInput:self] autorelease];
721- (UITextPosition *)beginningOfDocument
723 return [QUITextPosition positionWithIndex:0];
726- (UITextPosition *)endOfDocument
728 QString surroundingText = [self currentImeState:Qt::ImSurroundingText].toString();
729 int endPosition = surroundingText.length() + m_markedText.length();
730 return [QUITextPosition positionWithIndex:endPosition];
733- (
void)setSelectedTextRange:(UITextRange *)range
735 if (m_inSelectionChange) {
744 QUITextRange *r =
static_cast<QUITextRange *>(range);
745 QList<QInputMethodEvent::Attribute> attrs;
746 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.range.location, r.range.length, 0);
747 QInputMethodEvent e(m_markedText, attrs);
748 [self sendEventToFocusObject:e];
751- (UITextRange *)selectedTextRange
753 int cursorPos = [self currentImeState:Qt::ImCursorPosition].toInt();
754 int anchorPos = [self currentImeState:Qt::ImAnchorPosition].toInt();
755 return [QUITextRange rangeWithNSRange:NSMakeRange(qMin(cursorPos, anchorPos), qAbs(anchorPos - cursorPos))];
758- (
NSString *)textInRange:(UITextRange *)range
760 QString text = [self currentImeState:Qt::ImSurroundingText].toString();
761 if (!m_markedText.isEmpty()) {
765 int cursorPos = [self currentImeState:Qt::ImCursorPosition].toInt();
766 text = text.left(cursorPos) + m_markedText + text.mid(cursorPos);
769 int s =
static_cast<QUITextPosition *>([range start]).index;
770 int e =
static_cast<QUITextPosition *>([range end]).index;
771 return text.mid(s, e - s).toNSString();
774- (
void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange
776 Q_UNUSED(selectedRange);
778 m_markedText = markedText ? QString::fromNSString(markedText) : QString();
780 static QTextCharFormat markedTextFormat;
781 if (markedTextFormat.isEmpty()) {
784 markedTextFormat.setBackground(QColor(206, 221, 238));
787 QList<QInputMethodEvent::Attribute> attrs;
788 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, markedText.length, markedTextFormat);
789 QInputMethodEvent e(m_markedText, attrs);
790 [self sendEventToFocusObject:e];
795 if (m_markedText.isEmpty())
799 e.setCommitString(m_markedText);
800 [self sendEventToFocusObject:e];
802 m_markedText.clear();
805- (NSComparisonResult)comparePosition:(UITextPosition *)position toPosition:(UITextPosition *)other
807 int p =
static_cast<QUITextPosition *>(position).index;
808 int o =
static_cast<QUITextPosition *>(other).index;
810 return NSOrderedAscending;
812 return NSOrderedDescending;
813 return NSOrderedSame;
816- (UITextRange *)markedTextRange
818 return m_markedText.isEmpty() ? nil : [QUITextRange rangeWithNSRange:NSMakeRange(0, m_markedText.length())];
821- (UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition
823 int f =
static_cast<QUITextPosition *>(fromPosition).index;
824 int t =
static_cast<QUITextPosition *>(toPosition).index;
825 return [QUITextRange rangeWithNSRange:NSMakeRange(f, t - f)];
828- (UITextPosition *)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset
830 int p =
static_cast<QUITextPosition *>(position).index;
831 const int posWithIndex = p + offset;
832 const int textLength = [self currentImeState:Qt::ImSurroundingText].toString().length();
833 if (posWithIndex < 0 || posWithIndex > textLength)
835 return [QUITextPosition positionWithIndex:posWithIndex];
838- (UITextPosition *)positionFromPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction offset:(NSInteger)offset
840 int p =
static_cast<QUITextPosition *>(position).index;
843 case UITextLayoutDirectionLeft:
844 return [QUITextPosition positionWithIndex:p - offset];
845 case UITextLayoutDirectionRight:
846 return [QUITextPosition positionWithIndex:p + offset];
854- (UITextPosition *)positionWithinRange:(UITextRange *)range farthestInDirection:(UITextLayoutDirection)direction
856 NSRange r =
static_cast<QUITextRange *>(range).range;
857 if (direction == UITextLayoutDirectionRight)
858 return [QUITextPosition positionWithIndex:r.location + r.length];
859 return [QUITextPosition positionWithIndex:r.location];
862- (
NSInteger)offsetFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition
864 int f =
static_cast<QUITextPosition *>(fromPosition).index;
865 int t =
static_cast<QUITextPosition *>(toPosition).index;
869- (UIView *)textInputView
871 auto *focusWindow = QGuiApplication::focusWindow();
879 Q_ASSERT(focusWindow->handle());
880 QPlatformWindow *topLevel = focusWindow->handle();
881 while (QPlatformWindow *p = topLevel->parent())
883 return reinterpret_cast<UIView *>(topLevel->winId());
886- (CGRect)firstRectForRange:(UITextRange *)range
888 QObject *focusObject = QGuiApplication::focusObject();
894 if (!m_markedText.isEmpty())
897 int cursorPos = [self currentImeState:Qt::ImCursorPosition].toInt();
898 int anchorPos = [self currentImeState:Qt::ImAnchorPosition].toInt();
900 NSRange r =
static_cast<QUITextRange*>(range).range;
901 QList<QInputMethodEvent::Attribute> attrs;
902 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.location, 0, 0);
904 QInputMethodEvent e(m_markedText, attrs);
905 [self sendEventToFocusObject:e];
907 QRectF startRect = QPlatformInputContext::cursorRectangle();
909 attrs = QList<QInputMethodEvent::Attribute>();
910 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.location + r.length, 0, 0);
912 QInputMethodEvent e(m_markedText, attrs);
913 [self sendEventToFocusObject:e];
915 QRectF endRect = QPlatformInputContext::cursorRectangle();
917 if (cursorPos !=
int(r.location + r.length) || cursorPos != anchorPos) {
918 attrs = QList<QInputMethodEvent::Attribute>();
919 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, qMin(cursorPos, anchorPos), qAbs(cursorPos - anchorPos), 0);
920 QInputMethodEvent e(m_markedText, attrs);
921 [self sendEventToFocusObject:e];
924 return startRect.united(endRect).toCGRect();
927- (NSArray<UITextSelectionRect *> *)selectionRectsForRange:(UITextRange *)range
933 return [[NSArray<UITextSelectionRect *>
new] autorelease];
936- (CGRect)caretRectForPosition:(UITextPosition *)position
941 return QPlatformInputContext::cursorRectangle().toCGRect();
944- (
void)replaceRange:(UITextRange *)range withText:(NSString *)text
946 [self setSelectedTextRange:range];
949 e.setCommitString(QString::fromNSString(text));
950 [self sendEventToFocusObject:e];
953- (
void)setBaseWritingDirection:(NSWritingDirection)writingDirection forRange:(UITextRange *)range
955 Q_UNUSED(writingDirection);
960- (NSWritingDirection)baseWritingDirectionForPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction
964 if (QLocale::system().textDirection() == Qt::RightToLeft)
965 return NSWritingDirectionRightToLeft;
966 return NSWritingDirectionLeftToRight;
969- (UITextRange *)characterRangeByExtendingPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction
971 int p =
static_cast<QUITextPosition *>(position).index;
972 if (direction == UITextLayoutDirectionLeft)
973 return [QUITextRange rangeWithNSRange:NSMakeRange(0, p)];
974 int l = [self currentImeState:Qt::ImSurroundingText].toString().length();
975 return [QUITextRange rangeWithNSRange:NSMakeRange(p, l - p)];
978- (UITextPosition *)closestPositionToPoint:(CGPoint)point
980 int textPos = QPlatformInputContext::queryFocusObject(Qt::ImCursorPosition, QPointF::fromCGPoint(point)).toInt();
981 return [QUITextPosition positionWithIndex:textPos];
984- (UITextPosition *)closestPositionToPoint:(CGPoint)point withinRange:(UITextRange *)range
989 return [QUITextPosition positionWithIndex:[self currentImeState:Qt::ImCursorPosition].toInt()];
992- (UITextRange *)characterRangeAtPoint:(CGPoint)point
996 return [QUITextRange rangeWithNSRange:NSMakeRange([self currentImeState:Qt::ImCursorPosition].toInt(), 0)];
999- (
void)setMarkedTextStyle:(NSDictionary *)style
1008- (NSDictionary *)textStylingAtPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction
1011 Q_UNUSED(direction);
1013 QObject *focusObject = QGuiApplication::focusObject();
1019 QInputMethodQueryEvent e(Qt::ImFont);
1020 QCoreApplication::sendEvent(focusObject, &e);
1021 QFont qfont = qvariant_cast<QFont>(e.value(Qt::ImFont));
1022 UIFont *uifont = [UIFont fontWithName:qfont.family().toNSString() size:qfont.pointSize()];
1025 return @{NSFontAttributeName: uifont};
1029- (NSDictionary *)markedTextStyle
1031 return [NSDictionary dictionary];
1039- (
void)insertText:(NSString *)text
1041 QObject *focusObject = QGuiApplication::focusObject();
1045 if ([text isEqualToString:@
"\n"]) {
1046 [self sendKeyPressRelease:Qt::Key_Return modifiers:Qt::NoModifier];
1051 if (focusObject != QGuiApplication::focusObject()) {
1052 qImDebug() <<
"focusObject already changed, not resigning first responder.";
1056 if (self.returnKeyType == UIReturnKeyDone || self.returnKeyType == UIReturnKeyGo
1057 || self.returnKeyType == UIReturnKeySend || self.returnKeyType == UIReturnKeySearch)
1058 [self resignFirstResponder];
1063 QInputMethodEvent e;
1064 e.setCommitString(QString::fromNSString(text));
1065 [self sendEventToFocusObject:e];
1068- (
void)deleteBackward
1072 [self sendKeyPressRelease:Qt::Key_Backspace modifiers:Qt::NoModifier];
Q_FORWARD_DECLARE_OBJC_CLASS(NSString)