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 if (!QGuiApplication::focusObject())
288 QInputMethodQueryEvent query(Qt::ImAnchorPosition | Qt::ImCursorPosition);
289 QGuiApplication::sendEvent(QGuiApplication::focusObject(), &query);
290 int anchorPos = query.value(Qt::ImAnchorPosition).toInt();
291 int cursorPos = query.value(Qt::ImCursorPosition).toInt();
292 return anchorPos != cursorPos;
295- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
297 const bool isSelectAction =
298 action == @selector(select:) ||
299 action == @selector(selectAll:);
301 const bool isReadAction = action == @selector(copy:);
303 if (!isSelectAction && !isReadAction)
304 return [super canPerformAction:action withSender:sender];
306 const bool hasSelection = [self hasSelection];
307 return (!hasSelection && isSelectAction) || (hasSelection && isReadAction);
310- (
void)copy:(id)sender
313 [self sendShortcut:QKeySequence::Copy];
316- (
void)select:(id)sender
319 [self sendShortcut:QKeySequence::MoveToPreviousWord];
320 [self sendShortcut:QKeySequence::SelectNextWord];
323- (
void)selectAll:(id)sender
326 [self sendShortcut:QKeySequence::SelectAll];
335@implementation QIOSTextInputResponder {
336 QString m_markedText;
337 BOOL m_inSelectionChange;
340- (instancetype)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)inputContext
342 if (!(self = [super initWithInputContext:inputContext]))
345 m_inSelectionChange = NO;
347 QVariantMap platformData = m_configuredImeState->value(Qt::ImPlatformData).toMap();
348 Qt::InputMethodHints hints = Qt::InputMethodHints(m_configuredImeState->value(Qt::ImHints).toUInt());
349 Qt::EnterKeyType enterKeyType = Qt::EnterKeyType(m_configuredImeState->value(Qt::ImEnterKeyType).toUInt());
351 switch (enterKeyType) {
352 case Qt::EnterKeyReturn:
353 self.returnKeyType = UIReturnKeyDefault;
355 case Qt::EnterKeyDone:
356 self.returnKeyType = UIReturnKeyDone;
359 self.returnKeyType = UIReturnKeyGo;
361 case Qt::EnterKeySend:
362 self.returnKeyType = UIReturnKeySend;
364 case Qt::EnterKeySearch:
365 self.returnKeyType = UIReturnKeySearch;
367 case Qt::EnterKeyNext:
368 self.returnKeyType = UIReturnKeyNext;
371 self.returnKeyType = (hints & Qt::ImhMultiLine) ? UIReturnKeyDefault : UIReturnKeyDone;
375 self.secureTextEntry = BOOL(hints & Qt::ImhHiddenText);
376 self.autocorrectionType = (hints & Qt::ImhNoPredictiveText) ?
377 UITextAutocorrectionTypeNo : UITextAutocorrectionTypeDefault;
378 self.spellCheckingType = (hints & Qt::ImhNoPredictiveText) ?
379 UITextSpellCheckingTypeNo : UITextSpellCheckingTypeDefault;
381 if (hints & Qt::ImhUppercaseOnly)
382 self.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters;
383 else if (hints & Qt::ImhNoAutoUppercase)
384 self.autocapitalizationType = UITextAutocapitalizationTypeNone;
386 self.autocapitalizationType = UITextAutocapitalizationTypeSentences;
388 if (hints & Qt::ImhUrlCharactersOnly)
389 self.keyboardType = UIKeyboardTypeURL;
390 else if (hints & Qt::ImhEmailCharactersOnly)
391 self.keyboardType = UIKeyboardTypeEmailAddress;
392 else if (hints & Qt::ImhDigitsOnly)
393 self.keyboardType = UIKeyboardTypeNumberPad;
394 else if (hints & Qt::ImhDialableCharactersOnly)
395 self.keyboardType = UIKeyboardTypePhonePad;
396 else if (hints & Qt::ImhLatinOnly)
397 self.keyboardType = UIKeyboardTypeASCIICapable;
398 else if (hints & (Qt::ImhPreferNumbers | Qt::ImhFormattedNumbersOnly))
399 self.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
400 else if (hints & Qt::ImhDecimalNumbersOnly)
401 self.keyboardType = UIKeyboardTypeDecimalPad;
403 self.keyboardType = UIKeyboardTypeDefault;
405 if (UIView *inputView =
static_cast<UIView *>(platformData.value(kImePlatformDataInputView).value<
void *>()))
406 self.inputView = [[[WrapperView alloc] initWithView:inputView] autorelease];
407 if (UIView *accessoryView =
static_cast<UIView *>(platformData.value(kImePlatformDataInputAccessoryView).value<
void *>()))
408 self.inputAccessoryView = [[[WrapperView alloc] initWithView:accessoryView] autorelease];
410#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
411 if (platformData.value(kImePlatformDataHideShortcutsBar).toBool()) {
415#pragma clang diagnostic push
416#pragma clang diagnostic ignored "-Wnonnull"
417 self.inputAssistantItem.leadingBarButtonGroups = nil;
418 self.inputAssistantItem.trailingBarButtonGroups = nil;
419#pragma clang diagnostic pop
423 self.undoManager.groupsByEvent = NO;
424 [self rebuildUndoStack];
432 self.inputAccessoryView = 0;
433 [self.undoManager removeAllActions];
438- (BOOL)needsKeyboardReconfigure:(Qt::InputMethodQueries)updatedProperties
440 Qt::InputMethodQueries relevantProperties = updatedProperties;
441 if ((relevantProperties & Qt::ImEnabled)) {
446 qImDebug(
"IM was turned on, we need to check hints and platform data as well");
447 relevantProperties |= (Qt::ImHints | Qt::ImPlatformData);
451 relevantProperties &= (Qt::ImHints | Qt::ImEnterKeyType | Qt::ImPlatformData);
453 if (!relevantProperties)
454 return [super needsKeyboardReconfigure:updatedProperties];
456 for (uint i = 0; i < (
sizeof(Qt::ImQueryAll) * CHAR_BIT); ++i) {
457 if (Qt::InputMethodQuery property = Qt::InputMethodQuery(
int(updatedProperties & (1 << i)))) {
458 if ([self currentImeState:property] != m_configuredImeState->value(property)) {
459 qImDebug() << property <<
"has changed since text responder was configured, need reconfigure";
465 return [super needsKeyboardReconfigure:updatedProperties];
470 [self setMarkedText:@
"" selectedRange:NSMakeRange(0, 0)];
471 [self notifyInputDelegate:Qt::ImSurroundingText];
477 [self notifyInputDelegate:Qt::ImSurroundingText];
482#ifndef QT_NO_SHORTCUT
484- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
486 bool isEditAction = (action == @selector(cut:)
487 || action == @selector(copy:)
488 || action == @selector(paste:)
489 || action == @selector(
delete:)
490 || action == @selector(toggleBoldface:)
491 || action == @selector(toggleItalics:)
492 || action == @selector(toggleUnderline:)
493 || action == @selector(undo)
494 || action == @selector(redo));
496 bool isSelectAction = (action == @selector(select:)
497 || action == @selector(selectAll:)
498 || action == @selector(paste:)
499 || action == @selector(undo)
500 || action == @selector(redo));
502 const bool unknownAction = !isEditAction && !isSelectAction;
503 const bool hasSelection = [self hasSelection];
506 return [super canPerformAction:action withSender:sender];
508 QObject *focusObject = QGuiApplication::focusObject();
509 if (focusObject && focusObject->property(
"qt_im_readonly").toBool()) {
511 if (action == @selector(cut:)
512 || action == @selector(paste:)
513 || action == @selector(
delete:))
515 if (action == @selector(copy:))
518 return (hasSelection && isEditAction) || (!hasSelection && isSelectAction);
521- (
void)cut:(id)sender
524 [self sendShortcut:QKeySequence::Cut];
527- (
void)paste:(id)sender
530 [self sendShortcut:QKeySequence::Paste];
533- (
void)
delete:(id)sender
536 [self sendShortcut:QKeySequence::Delete];
539- (
void)toggleBoldface:(id)sender
542 [self sendShortcut:QKeySequence::Bold];
545- (
void)toggleItalics:(id)sender
548 [self sendShortcut:QKeySequence::Italic];
551- (
void)toggleUnderline:(id)sender
554 [self sendShortcut:QKeySequence::Underline];
561 [self sendShortcut:QKeySequence::Undo];
562 [self rebuildUndoStack];
567 [self sendShortcut:QKeySequence::Redo];
568 [self rebuildUndoStack];
573 NSUndoManager *undoMgr = self.undoManager;
574 [undoMgr beginUndoGrouping];
575 [undoMgr registerUndoWithTarget:self selector:@selector(redo) object:nil];
576 [undoMgr endUndoGrouping];
579- (
void)rebuildUndoStack
581 dispatch_async(dispatch_get_main_queue (), ^{
586 NSUndoManager *undoMgr = self.undoManager;
587 [undoMgr removeAllActions];
589 [undoMgr beginUndoGrouping];
590 [undoMgr registerUndoWithTarget:self selector:@selector(undo) object:nil];
591 [undoMgr endUndoGrouping];
592 [undoMgr beginUndoGrouping];
593 [undoMgr registerUndoWithTarget:self selector:@selector(undo) object:nil];
594 [undoMgr endUndoGrouping];
597 [undoMgr beginUndoGrouping];
598 [undoMgr registerUndoWithTarget:self selector:@selector(registerRedo) object:nil];
599 [undoMgr endUndoGrouping];
600 [undoMgr beginUndoGrouping];
601 [undoMgr registerUndoWithTarget:self selector:@selector(registerRedo) object:nil];
602 [undoMgr endUndoGrouping];
622- (
void)keyCommandTriggered:(UIKeyCommand *)keyCommand
624 Qt::Key key = Qt::Key_unknown;
625 Qt::KeyboardModifiers modifiers = Qt::NoModifier;
627 if (keyCommand.input == UIKeyInputLeftArrow)
629 else if (keyCommand.input == UIKeyInputRightArrow)
631 else if (keyCommand.input == UIKeyInputUpArrow)
633 else if (keyCommand.input == UIKeyInputDownArrow)
638 if (keyCommand.modifierFlags & UIKeyModifierAlternate)
639 modifiers |= Qt::AltModifier;
640 if (keyCommand.modifierFlags & UIKeyModifierShift)
641 modifiers |= Qt::ShiftModifier;
642 if (keyCommand.modifierFlags & UIKeyModifierCommand)
643 modifiers |= Qt::ControlModifier;
645 [self sendKeyPressRelease:key modifiers:modifiers];
648- (
void)addKeyCommandsToArray:(NSMutableArray<UIKeyCommand *> *)array key:(NSString *)key
650 SEL s = @selector(keyCommandTriggered:);
651 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:0 action:s]];
652 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierShift action:s]];
653 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierAlternate action:s]];
654 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierAlternate|UIKeyModifierShift action:s]];
655 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierCommand action:s]];
656 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierCommand|UIKeyModifierShift action:s]];
659- (NSArray<UIKeyCommand *> *)keyCommands
663 static dispatch_once_t once;
664 static NSMutableArray<UIKeyCommand *> *array;
666 dispatch_once(&once, ^{
671 array = [NSMutableArray<UIKeyCommand *>
new];
672 [self addKeyCommandsToArray:array key:UIKeyInputUpArrow];
673 [self addKeyCommandsToArray:array key:UIKeyInputDownArrow];
674 [self addKeyCommandsToArray:array key:UIKeyInputLeftArrow];
675 [self addKeyCommandsToArray:array key:UIKeyInputRightArrow];
685- (
void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties
692 if (m_inSendEventToFocusObject)
695 if (updatedProperties & (Qt::ImCursorPosition | Qt::ImAnchorPosition)) {
696 QScopedValueRollback<BOOL> rollback(m_inSelectionChange,
true);
697 [self.inputDelegate selectionWillChange:self];
698 [self.inputDelegate selectionDidChange:self];
701 if (updatedProperties & Qt::ImSurroundingText) {
702 [self.inputDelegate textWillChange:self];
703 [self.inputDelegate textDidChange:self];
707- (
void)sendEventToFocusObject:(QEvent &)e
709 QObject *focusObject = QGuiApplication::focusObject();
716 QScopedValueRollback<BOOL> rollback(m_inSendEventToFocusObject);
717 m_inSendEventToFocusObject = YES;
718 QCoreApplication::sendEvent(focusObject, &e);
721- (id<UITextInputTokenizer>)tokenizer
723 return [[[UITextInputStringTokenizer alloc] initWithTextInput:self] autorelease];
726- (UITextPosition *)beginningOfDocument
728 return [QUITextPosition positionWithIndex:0];
731- (UITextPosition *)endOfDocument
733 QString surroundingText = [self currentImeState:Qt::ImSurroundingText].toString();
734 int endPosition = surroundingText.length() + m_markedText.length();
735 return [QUITextPosition positionWithIndex:endPosition];
738- (
void)setSelectedTextRange:(UITextRange *)range
740 if (m_inSelectionChange) {
749 QUITextRange *r =
static_cast<QUITextRange *>(range);
750 QList<QInputMethodEvent::Attribute> attrs;
751 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.range.location, r.range.length, 0);
752 QInputMethodEvent e(m_markedText, attrs);
753 [self sendEventToFocusObject:e];
756- (UITextRange *)selectedTextRange
758 int cursorPos = [self currentImeState:Qt::ImCursorPosition].toInt();
759 int anchorPos = [self currentImeState:Qt::ImAnchorPosition].toInt();
760 return [QUITextRange rangeWithNSRange:NSMakeRange(qMin(cursorPos, anchorPos), qAbs(anchorPos - cursorPos))];
763- (
NSString *)textInRange:(UITextRange *)range
765 QString text = [self currentImeState:Qt::ImSurroundingText].toString();
766 if (!m_markedText.isEmpty()) {
770 int cursorPos = [self currentImeState:Qt::ImCursorPosition].toInt();
771 text = text.left(cursorPos) + m_markedText + text.mid(cursorPos);
774 int s =
static_cast<QUITextPosition *>([range start]).index;
775 int e =
static_cast<QUITextPosition *>([range end]).index;
776 return text.mid(s, e - s).toNSString();
779- (
void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange
781 Q_UNUSED(selectedRange);
783 m_markedText = markedText ? QString::fromNSString(markedText) : QString();
785 static QTextCharFormat markedTextFormat;
786 if (markedTextFormat.isEmpty()) {
789 markedTextFormat.setBackground(QColor(206, 221, 238));
792 QList<QInputMethodEvent::Attribute> attrs;
793 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, markedText.length, markedTextFormat);
794 QInputMethodEvent e(m_markedText, attrs);
795 [self sendEventToFocusObject:e];
800 if (m_markedText.isEmpty())
804 e.setCommitString(m_markedText);
805 [self sendEventToFocusObject:e];
807 m_markedText.clear();
810- (NSComparisonResult)comparePosition:(UITextPosition *)position toPosition:(UITextPosition *)other
812 int p =
static_cast<QUITextPosition *>(position).index;
813 int o =
static_cast<QUITextPosition *>(other).index;
815 return NSOrderedAscending;
817 return NSOrderedDescending;
818 return NSOrderedSame;
821- (UITextRange *)markedTextRange
823 return m_markedText.isEmpty() ? nil : [QUITextRange rangeWithNSRange:NSMakeRange(0, m_markedText.length())];
826- (UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition
828 int f =
static_cast<QUITextPosition *>(fromPosition).index;
829 int t =
static_cast<QUITextPosition *>(toPosition).index;
830 return [QUITextRange rangeWithNSRange:NSMakeRange(f, t - f)];
833- (UITextPosition *)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset
835 int p =
static_cast<QUITextPosition *>(position).index;
836 const int posWithIndex = p + offset;
837 const int textLength = [self currentImeState:Qt::ImSurroundingText].toString().length();
838 if (posWithIndex < 0 || posWithIndex > textLength)
840 return [QUITextPosition positionWithIndex:posWithIndex];
843- (UITextPosition *)positionFromPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction offset:(NSInteger)offset
845 int p =
static_cast<QUITextPosition *>(position).index;
848 case UITextLayoutDirectionLeft:
849 return [QUITextPosition positionWithIndex:p - offset];
850 case UITextLayoutDirectionRight:
851 return [QUITextPosition positionWithIndex:p + offset];
859- (UITextPosition *)positionWithinRange:(UITextRange *)range farthestInDirection:(UITextLayoutDirection)direction
861 NSRange r =
static_cast<QUITextRange *>(range).range;
862 if (direction == UITextLayoutDirectionRight)
863 return [QUITextPosition positionWithIndex:r.location + r.length];
864 return [QUITextPosition positionWithIndex:r.location];
867- (
NSInteger)offsetFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition
869 int f =
static_cast<QUITextPosition *>(fromPosition).index;
870 int t =
static_cast<QUITextPosition *>(toPosition).index;
874- (UIView *)textInputView
876 auto *focusWindow = QGuiApplication::focusWindow();
884 Q_ASSERT(focusWindow->handle());
885 QPlatformWindow *topLevel = focusWindow->handle();
886 while (QPlatformWindow *p = topLevel->parent())
888 return reinterpret_cast<UIView *>(topLevel->winId());
891- (CGRect)firstRectForRange:(UITextRange *)range
893 QObject *focusObject = QGuiApplication::focusObject();
899 if (!m_markedText.isEmpty())
902 int cursorPos = [self currentImeState:Qt::ImCursorPosition].toInt();
903 int anchorPos = [self currentImeState:Qt::ImAnchorPosition].toInt();
905 NSRange r =
static_cast<QUITextRange*>(range).range;
906 QList<QInputMethodEvent::Attribute> attrs;
907 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.location, 0, 0);
909 QInputMethodEvent e(m_markedText, attrs);
910 [self sendEventToFocusObject:e];
912 QRectF startRect = QPlatformInputContext::cursorRectangle();
914 attrs = QList<QInputMethodEvent::Attribute>();
915 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.location + r.length, 0, 0);
917 QInputMethodEvent e(m_markedText, attrs);
918 [self sendEventToFocusObject:e];
920 QRectF endRect = QPlatformInputContext::cursorRectangle();
922 if (cursorPos !=
int(r.location + r.length) || cursorPos != anchorPos) {
923 attrs = QList<QInputMethodEvent::Attribute>();
924 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, qMin(cursorPos, anchorPos), qAbs(cursorPos - anchorPos), 0);
925 QInputMethodEvent e(m_markedText, attrs);
926 [self sendEventToFocusObject:e];
929 return startRect.united(endRect).toCGRect();
932- (NSArray<UITextSelectionRect *> *)selectionRectsForRange:(UITextRange *)range
938 return [[NSArray<UITextSelectionRect *>
new] autorelease];
941- (CGRect)caretRectForPosition:(UITextPosition *)position
946 return QPlatformInputContext::cursorRectangle().toCGRect();
949- (
void)replaceRange:(UITextRange *)range withText:(NSString *)text
951 [self setSelectedTextRange:range];
954 e.setCommitString(QString::fromNSString(text));
955 [self sendEventToFocusObject:e];
958- (
void)setBaseWritingDirection:(NSWritingDirection)writingDirection forRange:(UITextRange *)range
960 Q_UNUSED(writingDirection);
965- (NSWritingDirection)baseWritingDirectionForPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction
969 if (QLocale::system().textDirection() == Qt::RightToLeft)
970 return NSWritingDirectionRightToLeft;
971 return NSWritingDirectionLeftToRight;
974- (UITextRange *)characterRangeByExtendingPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction
976 int p =
static_cast<QUITextPosition *>(position).index;
977 if (direction == UITextLayoutDirectionLeft)
978 return [QUITextRange rangeWithNSRange:NSMakeRange(0, p)];
979 int l = [self currentImeState:Qt::ImSurroundingText].toString().length();
980 return [QUITextRange rangeWithNSRange:NSMakeRange(p, l - p)];
983- (UITextPosition *)closestPositionToPoint:(CGPoint)point
985 int textPos = QPlatformInputContext::queryFocusObject(Qt::ImCursorPosition, QPointF::fromCGPoint(point)).toInt();
986 return [QUITextPosition positionWithIndex:textPos];
989- (UITextPosition *)closestPositionToPoint:(CGPoint)point withinRange:(UITextRange *)range
994 return [QUITextPosition positionWithIndex:[self currentImeState:Qt::ImCursorPosition].toInt()];
997- (UITextRange *)characterRangeAtPoint:(CGPoint)point
1001 return [QUITextRange rangeWithNSRange:NSMakeRange([self currentImeState:Qt::ImCursorPosition].toInt(), 0)];
1004- (
void)setMarkedTextStyle:(NSDictionary *)style
1013- (NSDictionary *)textStylingAtPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction
1016 Q_UNUSED(direction);
1018 QObject *focusObject = QGuiApplication::focusObject();
1024 QInputMethodQueryEvent e(Qt::ImFont);
1025 QCoreApplication::sendEvent(focusObject, &e);
1026 QFont qfont = qvariant_cast<QFont>(e.value(Qt::ImFont));
1027 UIFont *uifont = [UIFont fontWithName:qfont.family().toNSString() size:qfont.pointSize()];
1030 return @{NSFontAttributeName: uifont};
1034- (NSDictionary *)markedTextStyle
1036 return [NSDictionary dictionary];
1044- (
void)insertText:(NSString *)text
1046 QObject *focusObject = QGuiApplication::focusObject();
1050 if ([text isEqualToString:@
"\n"]) {
1051 [self sendKeyPressRelease:Qt::Key_Return modifiers:Qt::NoModifier];
1056 if (focusObject != QGuiApplication::focusObject()) {
1057 qImDebug() <<
"focusObject already changed, not resigning first responder.";
1061 if (self.returnKeyType == UIReturnKeyDone || self.returnKeyType == UIReturnKeyGo
1062 || self.returnKeyType == UIReturnKeySend || self.returnKeyType == UIReturnKeySearch)
1063 [self resignFirstResponder];
1068 QInputMethodEvent e;
1069 e.setCommitString(QString::fromNSString(text));
1070 [self sendEventToFocusObject:e];
1073- (
void)deleteBackward
1077 [self sendKeyPressRelease:Qt::Key_Backspace modifiers:Qt::NoModifier];
Q_FORWARD_DECLARE_OBJC_CLASS(NSString)