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;
397 else if (hints & Qt::ImhDecimaNumbersOnly)
398 self.keyboardType = UIKeyboardTypeDecimalPad;
400 self.keyboardType = UIKeyboardTypeDefault;
402 if (UIView *inputView =
static_cast<UIView *>(platformData.value(kImePlatformDataInputView).value<
void *>()))
403 self.inputView = [[[WrapperView alloc] initWithView:inputView] autorelease];
404 if (UIView *accessoryView =
static_cast<UIView *>(platformData.value(kImePlatformDataInputAccessoryView).value<
void *>()))
405 self.inputAccessoryView = [[[WrapperView alloc] initWithView:accessoryView] autorelease];
407#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
408 if (platformData.value(kImePlatformDataHideShortcutsBar).toBool()) {
412#pragma clang diagnostic push
413#pragma clang diagnostic ignored "-Wnonnull"
414 self.inputAssistantItem.leadingBarButtonGroups = nil;
415 self.inputAssistantItem.trailingBarButtonGroups = nil;
416#pragma clang diagnostic pop
420 self.undoManager.groupsByEvent = NO;
421 [self rebuildUndoStack];
429 self.inputAccessoryView = 0;
430 [self.undoManager removeAllActions];
435- (BOOL)needsKeyboardReconfigure:(Qt::InputMethodQueries)updatedProperties
437 Qt::InputMethodQueries relevantProperties = updatedProperties;
438 if ((relevantProperties & Qt::ImEnabled)) {
443 qImDebug(
"IM was turned on, we need to check hints and platform data as well");
444 relevantProperties |= (Qt::ImHints | Qt::ImPlatformData);
448 relevantProperties &= (Qt::ImHints | Qt::ImEnterKeyType | Qt::ImPlatformData);
450 if (!relevantProperties)
451 return [super needsKeyboardReconfigure:updatedProperties];
453 for (uint i = 0; i < (
sizeof(Qt::ImQueryAll) * CHAR_BIT); ++i) {
454 if (Qt::InputMethodQuery property = Qt::InputMethodQuery(
int(updatedProperties & (1 << i)))) {
455 if ([self currentImeState:property] != m_configuredImeState->value(property)) {
456 qImDebug() << property <<
"has changed since text responder was configured, need reconfigure";
462 return [super needsKeyboardReconfigure:updatedProperties];
467 [self setMarkedText:@
"" selectedRange:NSMakeRange(0, 0)];
468 [self notifyInputDelegate:Qt::ImSurroundingText];
474 [self notifyInputDelegate:Qt::ImSurroundingText];
479#ifndef QT_NO_SHORTCUT
481- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
483 bool isEditAction = (action == @selector(cut:)
484 || action == @selector(copy:)
485 || action == @selector(paste:)
486 || action == @selector(
delete:)
487 || action == @selector(toggleBoldface:)
488 || action == @selector(toggleItalics:)
489 || action == @selector(toggleUnderline:)
490 || action == @selector(undo)
491 || action == @selector(redo));
493 bool isSelectAction = (action == @selector(select:)
494 || action == @selector(selectAll:)
495 || action == @selector(paste:)
496 || action == @selector(undo)
497 || action == @selector(redo));
499 const bool unknownAction = !isEditAction && !isSelectAction;
500 const bool hasSelection = [self hasSelection];
503 return [super canPerformAction:action withSender:sender];
505 QObject *focusObject = QGuiApplication::focusObject();
506 if (focusObject && focusObject->property(
"qt_im_readonly").toBool()) {
508 if (action == @selector(cut:)
509 || action == @selector(paste:)
510 || action == @selector(
delete:))
512 if (action == @selector(copy:))
515 return (hasSelection && isEditAction) || (!hasSelection && isSelectAction);
518- (
void)cut:(id)sender
521 [self sendShortcut:QKeySequence::Cut];
524- (
void)paste:(id)sender
527 [self sendShortcut:QKeySequence::Paste];
530- (
void)
delete:(id)sender
533 [self sendShortcut:QKeySequence::Delete];
536- (
void)toggleBoldface:(id)sender
539 [self sendShortcut:QKeySequence::Bold];
542- (
void)toggleItalics:(id)sender
545 [self sendShortcut:QKeySequence::Italic];
548- (
void)toggleUnderline:(id)sender
551 [self sendShortcut:QKeySequence::Underline];
558 [self sendShortcut:QKeySequence::Undo];
559 [self rebuildUndoStack];
564 [self sendShortcut:QKeySequence::Redo];
565 [self rebuildUndoStack];
570 NSUndoManager *undoMgr = self.undoManager;
571 [undoMgr beginUndoGrouping];
572 [undoMgr registerUndoWithTarget:self selector:@selector(redo) object:nil];
573 [undoMgr endUndoGrouping];
576- (
void)rebuildUndoStack
578 dispatch_async(dispatch_get_main_queue (), ^{
583 NSUndoManager *undoMgr = self.undoManager;
584 [undoMgr removeAllActions];
586 [undoMgr beginUndoGrouping];
587 [undoMgr registerUndoWithTarget:self selector:@selector(undo) object:nil];
588 [undoMgr endUndoGrouping];
589 [undoMgr beginUndoGrouping];
590 [undoMgr registerUndoWithTarget:self selector:@selector(undo) object:nil];
591 [undoMgr endUndoGrouping];
594 [undoMgr beginUndoGrouping];
595 [undoMgr registerUndoWithTarget:self selector:@selector(registerRedo) object:nil];
596 [undoMgr endUndoGrouping];
597 [undoMgr beginUndoGrouping];
598 [undoMgr registerUndoWithTarget:self selector:@selector(registerRedo) object:nil];
599 [undoMgr endUndoGrouping];
619- (
void)keyCommandTriggered:(UIKeyCommand *)keyCommand
621 Qt::Key key = Qt::Key_unknown;
622 Qt::KeyboardModifiers modifiers = Qt::NoModifier;
624 if (keyCommand.input == UIKeyInputLeftArrow)
626 else if (keyCommand.input == UIKeyInputRightArrow)
628 else if (keyCommand.input == UIKeyInputUpArrow)
630 else if (keyCommand.input == UIKeyInputDownArrow)
635 if (keyCommand.modifierFlags & UIKeyModifierAlternate)
636 modifiers |= Qt::AltModifier;
637 if (keyCommand.modifierFlags & UIKeyModifierShift)
638 modifiers |= Qt::ShiftModifier;
639 if (keyCommand.modifierFlags & UIKeyModifierCommand)
640 modifiers |= Qt::ControlModifier;
642 [self sendKeyPressRelease:key modifiers:modifiers];
645- (
void)addKeyCommandsToArray:(NSMutableArray<UIKeyCommand *> *)array key:(NSString *)key
647 SEL s = @selector(keyCommandTriggered:);
648 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:0 action:s]];
649 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierShift action:s]];
650 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierAlternate action:s]];
651 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierAlternate|UIKeyModifierShift action:s]];
652 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierCommand action:s]];
653 [array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierCommand|UIKeyModifierShift action:s]];
656- (NSArray<UIKeyCommand *> *)keyCommands
660 static dispatch_once_t once;
661 static NSMutableArray<UIKeyCommand *> *array;
663 dispatch_once(&once, ^{
668 array = [NSMutableArray<UIKeyCommand *>
new];
669 [self addKeyCommandsToArray:array key:UIKeyInputUpArrow];
670 [self addKeyCommandsToArray:array key:UIKeyInputDownArrow];
671 [self addKeyCommandsToArray:array key:UIKeyInputLeftArrow];
672 [self addKeyCommandsToArray:array key:UIKeyInputRightArrow];
682- (
void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties
689 if (m_inSendEventToFocusObject)
692 if (updatedProperties & (Qt::ImCursorPosition | Qt::ImAnchorPosition)) {
693 QScopedValueRollback<BOOL> rollback(m_inSelectionChange,
true);
694 [self.inputDelegate selectionWillChange:self];
695 [self.inputDelegate selectionDidChange:self];
698 if (updatedProperties & Qt::ImSurroundingText) {
699 [self.inputDelegate textWillChange:self];
700 [self.inputDelegate textDidChange:self];
704- (
void)sendEventToFocusObject:(QEvent &)e
706 QObject *focusObject = QGuiApplication::focusObject();
713 QScopedValueRollback<BOOL> rollback(m_inSendEventToFocusObject);
714 m_inSendEventToFocusObject = YES;
715 QCoreApplication::sendEvent(focusObject, &e);
718- (id<UITextInputTokenizer>)tokenizer
720 return [[[UITextInputStringTokenizer alloc] initWithTextInput:self] autorelease];
723- (UITextPosition *)beginningOfDocument
725 return [QUITextPosition positionWithIndex:0];
728- (UITextPosition *)endOfDocument
730 QString surroundingText = [self currentImeState:Qt::ImSurroundingText].toString();
731 int endPosition = surroundingText.length() + m_markedText.length();
732 return [QUITextPosition positionWithIndex:endPosition];
735- (
void)setSelectedTextRange:(UITextRange *)range
737 if (m_inSelectionChange) {
746 QUITextRange *r =
static_cast<QUITextRange *>(range);
747 QList<QInputMethodEvent::Attribute> attrs;
748 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.range.location, r.range.length, 0);
749 QInputMethodEvent e(m_markedText, attrs);
750 [self sendEventToFocusObject:e];
753- (UITextRange *)selectedTextRange
755 int cursorPos = [self currentImeState:Qt::ImCursorPosition].toInt();
756 int anchorPos = [self currentImeState:Qt::ImAnchorPosition].toInt();
757 return [QUITextRange rangeWithNSRange:NSMakeRange(qMin(cursorPos, anchorPos), qAbs(anchorPos - cursorPos))];
760- (
NSString *)textInRange:(UITextRange *)range
762 QString text = [self currentImeState:Qt::ImSurroundingText].toString();
763 if (!m_markedText.isEmpty()) {
767 int cursorPos = [self currentImeState:Qt::ImCursorPosition].toInt();
768 text = text.left(cursorPos) + m_markedText + text.mid(cursorPos);
771 int s =
static_cast<QUITextPosition *>([range start]).index;
772 int e =
static_cast<QUITextPosition *>([range end]).index;
773 return text.mid(s, e - s).toNSString();
776- (
void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange
778 Q_UNUSED(selectedRange);
780 m_markedText = markedText ? QString::fromNSString(markedText) : QString();
782 static QTextCharFormat markedTextFormat;
783 if (markedTextFormat.isEmpty()) {
786 markedTextFormat.setBackground(QColor(206, 221, 238));
789 QList<QInputMethodEvent::Attribute> attrs;
790 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, markedText.length, markedTextFormat);
791 QInputMethodEvent e(m_markedText, attrs);
792 [self sendEventToFocusObject:e];
797 if (m_markedText.isEmpty())
801 e.setCommitString(m_markedText);
802 [self sendEventToFocusObject:e];
804 m_markedText.clear();
807- (NSComparisonResult)comparePosition:(UITextPosition *)position toPosition:(UITextPosition *)other
809 int p =
static_cast<QUITextPosition *>(position).index;
810 int o =
static_cast<QUITextPosition *>(other).index;
812 return NSOrderedAscending;
814 return NSOrderedDescending;
815 return NSOrderedSame;
818- (UITextRange *)markedTextRange
820 return m_markedText.isEmpty() ? nil : [QUITextRange rangeWithNSRange:NSMakeRange(0, m_markedText.length())];
823- (UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition
825 int f =
static_cast<QUITextPosition *>(fromPosition).index;
826 int t =
static_cast<QUITextPosition *>(toPosition).index;
827 return [QUITextRange rangeWithNSRange:NSMakeRange(f, t - f)];
830- (UITextPosition *)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset
832 int p =
static_cast<QUITextPosition *>(position).index;
833 const int posWithIndex = p + offset;
834 const int textLength = [self currentImeState:Qt::ImSurroundingText].toString().length();
835 if (posWithIndex < 0 || posWithIndex > textLength)
837 return [QUITextPosition positionWithIndex:posWithIndex];
840- (UITextPosition *)positionFromPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction offset:(NSInteger)offset
842 int p =
static_cast<QUITextPosition *>(position).index;
845 case UITextLayoutDirectionLeft:
846 return [QUITextPosition positionWithIndex:p - offset];
847 case UITextLayoutDirectionRight:
848 return [QUITextPosition positionWithIndex:p + offset];
856- (UITextPosition *)positionWithinRange:(UITextRange *)range farthestInDirection:(UITextLayoutDirection)direction
858 NSRange r =
static_cast<QUITextRange *>(range).range;
859 if (direction == UITextLayoutDirectionRight)
860 return [QUITextPosition positionWithIndex:r.location + r.length];
861 return [QUITextPosition positionWithIndex:r.location];
864- (
NSInteger)offsetFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition
866 int f =
static_cast<QUITextPosition *>(fromPosition).index;
867 int t =
static_cast<QUITextPosition *>(toPosition).index;
871- (UIView *)textInputView
873 auto *focusWindow = QGuiApplication::focusWindow();
881 Q_ASSERT(focusWindow->handle());
882 QPlatformWindow *topLevel = focusWindow->handle();
883 while (QPlatformWindow *p = topLevel->parent())
885 return reinterpret_cast<UIView *>(topLevel->winId());
888- (CGRect)firstRectForRange:(UITextRange *)range
890 QObject *focusObject = QGuiApplication::focusObject();
896 if (!m_markedText.isEmpty())
899 int cursorPos = [self currentImeState:Qt::ImCursorPosition].toInt();
900 int anchorPos = [self currentImeState:Qt::ImAnchorPosition].toInt();
902 NSRange r =
static_cast<QUITextRange*>(range).range;
903 QList<QInputMethodEvent::Attribute> attrs;
904 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.location, 0, 0);
906 QInputMethodEvent e(m_markedText, attrs);
907 [self sendEventToFocusObject:e];
909 QRectF startRect = QPlatformInputContext::cursorRectangle();
911 attrs = QList<QInputMethodEvent::Attribute>();
912 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.location + r.length, 0, 0);
914 QInputMethodEvent e(m_markedText, attrs);
915 [self sendEventToFocusObject:e];
917 QRectF endRect = QPlatformInputContext::cursorRectangle();
919 if (cursorPos !=
int(r.location + r.length) || cursorPos != anchorPos) {
920 attrs = QList<QInputMethodEvent::Attribute>();
921 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, qMin(cursorPos, anchorPos), qAbs(cursorPos - anchorPos), 0);
922 QInputMethodEvent e(m_markedText, attrs);
923 [self sendEventToFocusObject:e];
926 return startRect.united(endRect).toCGRect();
929- (NSArray<UITextSelectionRect *> *)selectionRectsForRange:(UITextRange *)range
935 return [[NSArray<UITextSelectionRect *>
new] autorelease];
938- (CGRect)caretRectForPosition:(UITextPosition *)position
943 return QPlatformInputContext::cursorRectangle().toCGRect();
946- (
void)replaceRange:(UITextRange *)range withText:(NSString *)text
948 [self setSelectedTextRange:range];
951 e.setCommitString(QString::fromNSString(text));
952 [self sendEventToFocusObject:e];
955- (
void)setBaseWritingDirection:(NSWritingDirection)writingDirection forRange:(UITextRange *)range
957 Q_UNUSED(writingDirection);
962- (NSWritingDirection)baseWritingDirectionForPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction
966 if (QLocale::system().textDirection() == Qt::RightToLeft)
967 return NSWritingDirectionRightToLeft;
968 return NSWritingDirectionLeftToRight;
971- (UITextRange *)characterRangeByExtendingPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction
973 int p =
static_cast<QUITextPosition *>(position).index;
974 if (direction == UITextLayoutDirectionLeft)
975 return [QUITextRange rangeWithNSRange:NSMakeRange(0, p)];
976 int l = [self currentImeState:Qt::ImSurroundingText].toString().length();
977 return [QUITextRange rangeWithNSRange:NSMakeRange(p, l - p)];
980- (UITextPosition *)closestPositionToPoint:(CGPoint)point
982 int textPos = QPlatformInputContext::queryFocusObject(Qt::ImCursorPosition, QPointF::fromCGPoint(point)).toInt();
983 return [QUITextPosition positionWithIndex:textPos];
986- (UITextPosition *)closestPositionToPoint:(CGPoint)point withinRange:(UITextRange *)range
991 return [QUITextPosition positionWithIndex:[self currentImeState:Qt::ImCursorPosition].toInt()];
994- (UITextRange *)characterRangeAtPoint:(CGPoint)point
998 return [QUITextRange rangeWithNSRange:NSMakeRange([self currentImeState:Qt::ImCursorPosition].toInt(), 0)];
1001- (
void)setMarkedTextStyle:(NSDictionary *)style
1010- (NSDictionary *)textStylingAtPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction
1013 Q_UNUSED(direction);
1015 QObject *focusObject = QGuiApplication::focusObject();
1021 QInputMethodQueryEvent e(Qt::ImFont);
1022 QCoreApplication::sendEvent(focusObject, &e);
1023 QFont qfont = qvariant_cast<QFont>(e.value(Qt::ImFont));
1024 UIFont *uifont = [UIFont fontWithName:qfont.family().toNSString() size:qfont.pointSize()];
1027 return @{NSFontAttributeName: uifont};
1031- (NSDictionary *)markedTextStyle
1033 return [NSDictionary dictionary];
1041- (
void)insertText:(NSString *)text
1043 QObject *focusObject = QGuiApplication::focusObject();
1047 if ([text isEqualToString:@
"\n"]) {
1048 [self sendKeyPressRelease:Qt::Key_Return modifiers:Qt::NoModifier];
1053 if (focusObject != QGuiApplication::focusObject()) {
1054 qImDebug() <<
"focusObject already changed, not resigning first responder.";
1058 if (self.returnKeyType == UIReturnKeyDone || self.returnKeyType == UIReturnKeyGo
1059 || self.returnKeyType == UIReturnKeySend || self.returnKeyType == UIReturnKeySearch)
1060 [self resignFirstResponder];
1065 QInputMethodEvent e;
1066 e.setCommitString(QString::fromNSString(text));
1067 [self sendEventToFocusObject:e];
1070- (
void)deleteBackward
1074 [self sendKeyPressRelease:Qt::Key_Backspace modifiers:Qt::NoModifier];
Q_FORWARD_DECLARE_OBJC_CLASS(NSString)