iOS: guard text responder from clearing selection

When programatically setting a text selection on iOS, we
call [UITextInputDelegate selectionWillChange] to report
the change. If auto correction is enabled, UIKit will then
reset the current tracking, and for some reason tell us to
clear the selection. This is contradictory to us
saying the the selection is about to change, and will
cause an unwanted recursion back to Qt.

Since there seems to be no way to stop UIKit from doing
this, this patch will instead add a guard that refuses
to change the selection recursively while processing
a selection change from Qt.

Task-number: QTBUG-43716
Change-Id: Id487a57cdda55d7e2d09c3efc14c7f03f566f15a
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@theqtcompany.com>
bb10
Richard Moe Gustavsen 2015-01-13 12:53:04 +01:00
parent 34ce66cd89
commit 13ecde3b7a
2 changed files with 12 additions and 0 deletions

View File

@ -51,6 +51,7 @@ class QIOSInputContext;
QIOSInputContext *m_inputContext;
QString m_markedText;
BOOL m_inSendEventToFocusObject;
BOOL m_inSelectionChange;
}
- (id)initWithInputContext:(QIOSInputContext *)context;

View File

@ -171,6 +171,7 @@
return self;
m_inSendEventToFocusObject = NO;
m_inSelectionChange = NO;
m_inputContext = inputContext;
QVariantMap platformData = [self imValue:Qt::ImPlatformData].toMap();
@ -302,6 +303,7 @@
return;
if (updatedProperties & (Qt::ImCursorPosition | Qt::ImAnchorPosition)) {
QScopedValueRollback<BOOL> rollback(m_inSelectionChange, true);
[self.inputDelegate selectionWillChange:self];
[self.inputDelegate selectionDidChange:self];
}
@ -349,6 +351,15 @@
- (void)setSelectedTextRange:(UITextRange *)range
{
if (m_inSelectionChange) {
// After [UITextInputDelegate selectionWillChange], UIKit will cancel
// any ongoing auto correction (if enabled) and ask us to set an empty selection.
// This is contradictory to our current attempt to set a selection, so we ignore
// the callback. UIKit will be re-notified of the new selection after
// [UITextInputDelegate selectionDidChange].
return;
}
QUITextRange *r = static_cast<QUITextRange *>(range);
QList<QInputMethodEvent::Attribute> attrs;
attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.range.location, r.range.length, 0);