iOS: let first responder follow the view of the focus window

This to ensure that the keyboard does not close prematurly.
This can happen if the user opens up the keyboard while typing
inside one window, then switch window, continue typing while
the other window gets deleted.

Change-Id: I5cfb1673ccbe4d5aaa14167b7aa53451031089a1
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com>
This commit is contained in:
Richard Moe Gustavsen 2013-01-16 10:42:31 +01:00 committed by Tor Arne Vestbø
parent 73e8796603
commit 0a9a4e826f
3 changed files with 23 additions and 18 deletions

View File

@ -61,8 +61,11 @@ public:
void hideInputPanel();
bool isInputPanelVisible() const;
void focusViewChanged(UIView *view);
private:
QIOSKeyboardListener *m_keyboardListener;
UIView *m_focusView;
};
QT_END_NAMESPACE

View File

@ -98,12 +98,14 @@
QIOSInputContext::QIOSInputContext()
: QPlatformInputContext()
, m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this])
, m_focusView(0)
{
}
QIOSInputContext::~QIOSInputContext()
{
[m_keyboardListener release];
[m_focusView release];
}
QRectF QIOSInputContext::keyboardRect() const
@ -113,33 +115,28 @@ QRectF QIOSInputContext::keyboardRect() const
void QIOSInputContext::showInputPanel()
{
if (isInputPanelVisible())
return;
// Documentation tells that one should call (and recall, if necessary) becomeFirstResponder/resignFirstResponder
// to show/hide the keyboard. This is slightly inconvenient, since there exist no API to get the current first
// responder. Rather than searching for it from the top, we assume that the view backing the focus window in Qt
// is the best candidate as long as there exist no first responder from before (which the isInputPanelVisible
// test on top should catch). Note that Qt will forward keyevents to whichever QObject that needs it, regardless of
// which UIView the input actually came from. So in this respect, we're undermining iOS' responder chain.
if (QWindow *window = QGuiApplication::focusWindow()) {
QIOSWindow *qiosWindow = static_cast<QIOSWindow *>(window->handle());
[qiosWindow->nativeView() becomeFirstResponder];
}
// responder. Rather than searching for it from the top, we let the active QIOSWindow tell us which view to use.
// Note that Qt will forward keyevents to whichever QObject that needs it, regardless of which UIView the input
// actually came from. So in this respect, we're undermining iOS' responder chain.
[m_focusView becomeFirstResponder];
}
void QIOSInputContext::hideInputPanel()
{
if (!isInputPanelVisible())
return;
if (QWindow *window = QGuiApplication::focusWindow()) {
QIOSWindow *qiosWindow = static_cast<QIOSWindow *>(window->handle());
[qiosWindow->nativeView() resignFirstResponder];
}
[m_focusView resignFirstResponder];
}
bool QIOSInputContext::isInputPanelVisible() const
{
return m_keyboardListener->m_keyboardVisible;
}
void QIOSInputContext::focusViewChanged(UIView *view)
{
if ([m_focusView isFirstResponder])
[view becomeFirstResponder];
[m_focusView release];
m_focusView = [view retain];
}

View File

@ -42,9 +42,12 @@
#include "qiosglobal.h"
#include "qioswindow.h"
#include "qioscontext.h"
#include "qiosinputcontext.h"
#include "qiosscreen.h"
#include "qiosapplicationdelegate.h"
#include "qiosviewcontroller.h"
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
#import <QuartzCore/CAEAGLLayer.h>
@ -327,6 +330,8 @@ void QIOSWindow::requestActivateWindow()
// hierarchy (transient children). But only one window can be QGuiApplication::focusWindow().
// Dispite the name, 'requestActivateWindow' means raise and transfer focus to the window:
raise();
QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext();
static_cast<QIOSInputContext *>(context)->focusViewChanged(m_view);
QPlatformWindow::requestActivateWindow();
}