iOS: close keyboard by resigning first responder

Current approach of reloading input views assumes that
the first responder is not a QIOSTextResponder, but
a QUIView. This is not always the case, e.g if someone
calls update after setting IM enabled on current focus
object to false. In that case we'll try to close the
keyboard by reloading input views on a quitextresponder which
can fail if the text responder has an external input view
attached.

This patch will instead hide the keyboard by resigning first
responder when it is a QIOSTextResponder. If it is not
a QIOSTextResponder it means that the keyboard is already
closed, or a third-party UIVIew that supports key input is first
responder. In either case we then leave it as-is.

Task-number: QTBUG-42523
Change-Id: I4dab648af9029941a8d5d3b00011fbd169be5482
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com>
This commit is contained in:
Richard Moe Gustavsen 2014-11-07 23:52:20 +01:00 committed by Jani Heikkinen
parent f3b93a7724
commit f12d4ee3fb
3 changed files with 4 additions and 41 deletions

View File

@ -85,15 +85,12 @@ public:
const ImeState &imeState() { return m_imeState; };
bool inputMethodAccepted() const;
bool isReloadingInputViewsFromUpdate() const { return m_isReloadingInputViewsFromUpdate; }
static QIOSInputContext *instance();
private:
QIOSKeyboardListener *m_keyboardListener;
QIOSTextInputResponder *m_textResponder;
ImeState m_imeState;
bool m_isReloadingInputViewsFromUpdate;
};
QT_END_NAMESPACE

View File

@ -330,7 +330,6 @@ QIOSInputContext::QIOSInputContext()
: QPlatformInputContext()
, m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this])
, m_textResponder(0)
, m_isReloadingInputViewsFromUpdate(false)
{
if (isQtApplication())
connect(qGuiApp->inputMethod(), &QInputMethod::cursorRectangleChanged, this, &QIOSInputContext::cursorRectangleChanged);
@ -540,10 +539,11 @@ void QIOSInputContext::update(Qt::InputMethodQueries updatedProperties)
[m_textResponder autorelease];
m_textResponder = [[QIOSTextInputResponder alloc] initWithInputContext:this];
[m_textResponder becomeFirstResponder];
} else if ([UIResponder currentFirstResponder] == m_textResponder) {
qImDebug() << "IM not enabled, resigning text responder as first responder";
[m_textResponder resignFirstResponder];
} else {
qImDebug() << "IM not enabled, reloading input views";
QScopedValueRollback<bool> recursionGuard(m_isReloadingInputViewsFromUpdate, true);
[[UIResponder currentFirstResponder] reloadInputViews];
qImDebug() << "IM not enabled. Text responder not first responder. Nothing to do";
}
} else {
[m_textResponder notifyInputDelegate:changedProperties];
@ -594,22 +594,3 @@ void QIOSInputContext::commit()
[m_textResponder unmarkText];
[m_textResponder notifyInputDelegate:Qt::ImSurroundingText];
}
// -------------------------------------------------------------------------
@interface QUIView (InputMethods)
- (void)reloadInputViews;
@end
@implementation QUIView (InputMethods)
- (void)reloadInputViews
{
if (QIOSInputContext::instance()->isReloadingInputViewsFromUpdate()) {
qImDebug() << "preventing recursion by reloading super";
[super reloadInputViews];
} else {
qImDebug() << "reseting input methods";
qApp->inputMethod()->reset();
}
}
@end

View File

@ -285,21 +285,6 @@
reinterpret_cast<QUIView *>(qApp->focusWindow()->handle()->winId()) : 0;
}
/*!
iOS uses [UIResponder(Internal) _requiresKeyboardWhenFirstResponder] to check if the
current responder should bring up the keyboard, which in turn checks if the responder
supports the UIKeyInput protocol. By dynamically reporting our protocol conformance
we can control the keyboard visibility depending on whether or not we have a focus
object with IME enabled.
*/
- (BOOL)conformsToProtocol:(Protocol *)protocol
{
if (protocol == @protocol(UIKeyInput))
return m_inputContext->inputMethodAccepted();
return [super conformsToProtocol:protocol];
}
// -------------------------------------------------------------------------
- (void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties