summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/platforms/ios/ios.pro2
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.h19
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm177
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.h74
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.mm (renamed from src/plugins/platforms/ios/quiview_textinput.mm)227
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm4
-rw-r--r--src/plugins/platforms/ios/quiview.h28
-rw-r--r--src/plugins/platforms/ios/quiview.mm50
8 files changed, 335 insertions, 246 deletions
diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro
index ad9912a8d0..82f0bd91c4 100644
--- a/src/plugins/platforms/ios/ios.pro
+++ b/src/plugins/platforms/ios/ios.pro
@@ -27,6 +27,7 @@ OBJECTIVE_SOURCES = \
qiosclipboard.mm \
quiaccessibilityelement.mm \
qiosplatformaccessibility.mm \
+ qiostextresponder.mm \
HEADERS = \
qiosintegration.h \
@@ -46,6 +47,7 @@ HEADERS = \
qiosclipboard.h \
quiaccessibilityelement.h \
qiosplatformaccessibility.h \
+ qiostextresponder.h \
OTHER_FILES = \
quiview_textinput.mm \
diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h
index 13255ada56..7f94a9836a 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.h
+++ b/src/plugins/platforms/ios/qiosinputcontext.h
@@ -44,13 +44,21 @@
#include <UIKit/UIKit.h>
+#include <QtGui/qevent.h>
#include <QtGui/qtransform.h>
#include <qpa/qplatforminputcontext.h>
QT_BEGIN_NAMESPACE
@class QIOSKeyboardListener;
-@class QUIView;
+@class QIOSTextInputResponder;
+
+struct ImeState
+{
+ ImeState() : currentState(0) {}
+ Qt::InputMethodQueries update(Qt::InputMethodQueries properties);
+ QInputMethodQueryEvent currentState;
+};
class QIOSInputContext : public QPlatformInputContext
{
@@ -59,8 +67,11 @@ public:
~QIOSInputContext();
QRectF keyboardRect() const;
+
void showInputPanel();
void hideInputPanel();
+ void hideVirtualKeyboard();
+
bool isInputPanelVisible() const;
void setFocusObject(QObject *object);
@@ -73,10 +84,12 @@ public:
void reset();
void commit();
+ const ImeState &imeState() { return m_imeState; };
+
private:
QIOSKeyboardListener *m_keyboardListener;
- QUIView *m_focusView;
- bool m_hasPendingHideRequest;
+ QIOSTextInputResponder *m_textResponder;
+ ImeState m_imeState;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
index 064098157d..cbf3fb4ff2 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.mm
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -44,8 +44,10 @@
#import <UIKit/UIGestureRecognizerSubclass.h>
#include "qiosglobal.h"
+#include "qiostextresponder.h"
#include "qioswindow.h"
#include "quiview.h"
+
#include <QGuiApplication>
#include <QtGui/private/qwindow_p.h>
@@ -158,8 +160,6 @@
- (void) keyboardWillShow:(NSNotification *)notification
{
- if ([QUIView inUpdateKeyboardLayout])
- return;
// Note that UIKeyboardWillShowNotification is only sendt when the keyboard is docked.
m_keyboardVisibleAndDocked = YES;
m_keyboardEndRect = [self getKeyboardRect:notification];
@@ -173,8 +173,6 @@
- (void) keyboardWillHide:(NSNotification *)notification
{
- if ([QUIView inUpdateKeyboardLayout])
- return;
// Note that UIKeyboardWillHideNotification is also sendt when the keyboard is undocked.
m_keyboardVisibleAndDocked = NO;
m_keyboardEndRect = [self getKeyboardRect:notification];
@@ -207,7 +205,7 @@
QPointF p = fromCGPoint([[touches anyObject] locationInView:m_viewController.view]);
if (m_keyboardRect.contains(p)) {
m_keyboardHiddenByGesture = YES;
- m_context->hideInputPanel();
+ m_context->hideVirtualKeyboard();
}
[super touchesMoved:touches withEvent:event];
@@ -253,11 +251,43 @@
@end
+// -------------------------------------------------------------------------
+
+Qt::InputMethodQueries ImeState::update(Qt::InputMethodQueries properties)
+{
+ if (!properties)
+ return 0;
+
+ QInputMethodQueryEvent newState(properties);
+
+ if (qApp && qApp->focusObject())
+ QCoreApplication::sendEvent(qApp->focusObject(), &newState);
+
+ Qt::InputMethodQueries updatedProperties;
+ for (uint i = 0; i < (sizeof(Qt::ImQueryAll) * CHAR_BIT); ++i) {
+ if (Qt::InputMethodQuery property = Qt::InputMethodQuery(int(properties & (1 << i)))) {
+ if (newState.value(property) != currentState.value(property)) {
+ updatedProperties |= property;
+ currentState.setValue(property, newState.value(property));
+ }
+ }
+ }
+
+ return updatedProperties;
+}
+
+// -------------------------------------------------------------------------
+
+static QUIView *focusView()
+{
+ return qApp->focusWindow() ?
+ reinterpret_cast<QUIView *>(qApp->focusWindow()->handle()->winId()) : 0;
+}
+
QIOSInputContext::QIOSInputContext()
: QPlatformInputContext()
, m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this])
- , m_focusView(0)
- , m_hasPendingHideRequest(false)
+ , m_textResponder(0)
{
if (isQtApplication())
connect(qGuiApp->inputMethod(), &QInputMethod::cursorRectangleChanged, this, &QIOSInputContext::cursorRectangleChanged);
@@ -267,7 +297,7 @@ QIOSInputContext::QIOSInputContext()
QIOSInputContext::~QIOSInputContext()
{
[m_keyboardListener release];
- [m_focusView release];
+ [m_textResponder release];
}
QRectF QIOSInputContext::keyboardRect() const
@@ -277,61 +307,22 @@ QRectF QIOSInputContext::keyboardRect() const
void QIOSInputContext::showInputPanel()
{
- if (m_keyboardListener->m_keyboardHiddenByGesture) {
- // We refuse to re-show the keyboard until the touch
- // sequence that triggered the gesture has ended.
- 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 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_hasPendingHideRequest = false;
- [m_focusView becomeFirstResponder];
+ // No-op, keyboard controlled fully by platform based on focus
}
void QIOSInputContext::hideInputPanel()
{
- // Delay hiding the keyboard for cases where the user is transferring focus between
- // 'line edits'. In that case the 'line edit' that lost focus will close the input
- // panel, just to see that the new 'line edit' will open it again:
- m_hasPendingHideRequest = true;
- dispatch_async(dispatch_get_main_queue(), ^{
- if (m_hasPendingHideRequest)
- [m_focusView resignFirstResponder];
- });
+ // No-op, keyboard controlled fully by platform based on focus
}
-bool QIOSInputContext::isInputPanelVisible() const
+void QIOSInputContext::hideVirtualKeyboard()
{
- return m_keyboardListener->m_keyboardVisible;
+ static_cast<QWindowPrivate *>(QObjectPrivate::get(qApp->focusWindow()))->clearFocusObject();
}
-void QIOSInputContext::setFocusObject(QObject *focusObject)
-{
- if (!focusObject || !m_focusView || !m_focusView.isFirstResponder) {
- scroll(0);
- return;
- }
-
- reset();
-
- if (m_keyboardListener->m_keyboardVisibleAndDocked)
- scrollToCursor();
-}
-
-void QIOSInputContext::focusWindowChanged(QWindow *focusWindow)
+bool QIOSInputContext::isInputPanelVisible() const
{
- QUIView *view = focusWindow ? reinterpret_cast<QUIView *>(focusWindow->handle()->winId()) : 0;
- if ([m_focusView isFirstResponder])
- [view becomeFirstResponder];
- [m_focusView release];
- m_focusView = [view retain];
-
- if (view.window != m_keyboardListener->m_viewController.view)
- scroll(0);
+ return m_keyboardListener->m_keyboardVisible;
}
void QIOSInputContext::cursorRectangleChanged()
@@ -353,7 +344,7 @@ void QIOSInputContext::cursorRectangleChanged()
void QIOSInputContext::scrollToCursor()
{
- if (!isQtApplication() || !m_focusView)
+ if (!isQtApplication())
return;
if (m_keyboardListener->m_touchPressWhileKeyboardVisible) {
@@ -364,12 +355,12 @@ void QIOSInputContext::scrollToCursor()
}
UIView *view = m_keyboardListener->m_viewController.view;
- if (view.window != m_focusView.window)
+ if (view.window != focusView().window)
return;
const int margin = 20;
QRectF translatedCursorPos = qApp->inputMethod()->cursorRectangle();
- translatedCursorPos.translate(m_focusView.qwindow->geometry().topLeft());
+ translatedCursorPos.translate(focusView().qwindow->geometry().topLeft());
qreal keyboardY = m_keyboardListener->m_keyboardEndRect.y();
int statusBarY = qGuiApp->primaryScreen()->availableGeometry().y();
@@ -398,18 +389,84 @@ void QIOSInputContext::scroll(int y)
];
}
-void QIOSInputContext::update(Qt::InputMethodQueries query)
+// -------------------------------------------------------------------------
+
+void QIOSInputContext::setFocusObject(QObject *focusObject)
+{
+ Q_UNUSED(focusObject);
+
+ reset();
+
+ if (m_keyboardListener->m_keyboardVisibleAndDocked)
+ scrollToCursor();
+}
+
+void QIOSInputContext::focusWindowChanged(QWindow *focusWindow)
+{
+ Q_UNUSED(focusWindow);
+
+ reset();
+
+ if (m_keyboardListener->m_keyboardVisibleAndDocked)
+ scrollToCursor();
+}
+
+/*!
+ Called by the input item to inform the platform input methods when there has been
+ state changes in editor's input method query attributes. When calling the function
+ \a queries parameter has to be used to tell what has changes, which input method
+ can use to make queries for attributes it's interested with QInputMethodQueryEvent.
+*/
+void QIOSInputContext::update(Qt::InputMethodQueries updatedProperties)
{
- [m_focusView updateInputMethodWithQuery:query];
+ // Mask for properties that we are interested in and see if any of them changed
+ updatedProperties &= (Qt::ImEnabled | Qt::ImHints | Qt::ImQueryInput);
+
+ Qt::InputMethodQueries changedProperties = m_imeState.update(updatedProperties);
+ if (changedProperties & (Qt::ImEnabled | Qt::ImHints)) {
+ // Changes to enablement or hints require virtual keyboard reconfigure
+ [m_textResponder release];
+ m_textResponder = [[QIOSTextInputResponder alloc] initWithInputContext:this];
+ [m_textResponder reloadInputViews];
+ } else {
+ [m_textResponder notifyInputDelegate:changedProperties];
+ }
}
+/*!
+ Called by the input item to reset the input method state.
+*/
void QIOSInputContext::reset()
{
- [m_focusView reset];
+ update(Qt::ImQueryAll);
+
+ [m_textResponder setMarkedText:@"" selectedRange:NSMakeRange(0, 0)];
+ [m_textResponder notifyInputDelegate:Qt::ImQueryInput];
}
+/*!
+ Commits the word user is currently composing to the editor. The function is
+ mostly needed by the input methods with text prediction features and by the
+ methods where the script used for typing characters is different from the
+ script that actually gets appended to the editor. Any kind of action that
+ interrupts the text composing needs to flush the composing state by calling the
+ commit() function, for example when the cursor is moved elsewhere.
+*/
void QIOSInputContext::commit()
{
- [m_focusView commit];
+ [m_textResponder unmarkText];
+ [m_textResponder notifyInputDelegate:Qt::ImSurroundingText];
}
+// -------------------------------------------------------------------------
+
+@interface QUIView (InputMethods)
+- (void)reloadInputViews;
+@end
+
+@implementation QUIView (InputMethods)
+- (void)reloadInputViews
+{
+ qApp->inputMethod()->reset();
+}
+@end
diff --git a/src/plugins/platforms/ios/qiostextresponder.h b/src/plugins/platforms/ios/qiostextresponder.h
new file mode 100644
index 0000000000..7290d9e454
--- /dev/null
+++ b/src/plugins/platforms/ios/qiostextresponder.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#import <UIKit/UIKit.h>
+
+#include <QtCore/qstring.h>
+
+class QIOSInputContext;
+
+@interface QIOSTextInputResponder : UIResponder <UITextInputTraits, UIKeyInput, UITextInput>
+{
+ @public
+ QString m_markedText;
+ BOOL m_inSendEventToFocusObject;
+
+ @private
+ QIOSInputContext *m_inputContext;
+}
+
+- (id)initWithInputContext:(QIOSInputContext *)context;
+- (void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties;
+
+// UITextInputTraits
+@property(nonatomic) UITextAutocapitalizationType autocapitalizationType;
+@property(nonatomic) UITextAutocorrectionType autocorrectionType;
+@property(nonatomic) UITextSpellCheckingType spellCheckingType;
+@property(nonatomic) BOOL enablesReturnKeyAutomatically;
+@property(nonatomic) UIKeyboardAppearance keyboardAppearance;
+@property(nonatomic) UIKeyboardType keyboardType;
+@property(nonatomic) UIReturnKeyType returnKeyType;
+@property(nonatomic, getter=isSecureTextEntry) BOOL secureTextEntry;
+
+// UITextInput
+@property(nonatomic, assign) id<UITextInputDelegate> inputDelegate;
+
+@end
diff --git a/src/plugins/platforms/ios/quiview_textinput.mm b/src/plugins/platforms/ios/qiostextresponder.mm
index 6b2707e706..ea6b5ffb94 100644
--- a/src/plugins/platforms/ios/quiview_textinput.mm
+++ b/src/plugins/platforms/ios/qiostextresponder.mm
@@ -39,31 +39,22 @@
**
****************************************************************************/
+#include "qiostextresponder.h"
+
+#include "qiosglobal.h"
#include "qiosinputcontext.h"
+#include "quiview.h"
+
+#include <QtCore/qscopedvaluerollback.h>
+#include <QtGui/qevent.h>
#include <QtGui/qtextformat.h>
#include <QtGui/private/qguiapplication_p.h>
-
-class StaticVariables
-{
-public:
- QInputMethodQueryEvent inputMethodQueryEvent;
- bool inUpdateKeyboardLayout;
-
- StaticVariables()
- : inputMethodQueryEvent(Qt::ImQueryInput)
- , inUpdateKeyboardLayout(false)
- {
- }
-};
-
-Q_GLOBAL_STATIC(StaticVariables, staticVariables);
+#include <QtGui/qpa/qplatformwindow.h>
// -------------------------------------------------------------------------
@interface QUITextPosition : UITextPosition
-{
-}
@property (nonatomic) NSUInteger index;
+ (QUITextPosition *)positionWithIndex:(NSUInteger)index;
@@ -84,8 +75,6 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
// -------------------------------------------------------------------------
@interface QUITextRange : UITextRange
-{
-}
@property (nonatomic) NSRange range;
+ (QUITextRange *)rangeWithNSRange:(NSRange)range;
@@ -125,51 +114,82 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
// -------------------------------------------------------------------------
-@implementation QUIView (TextInput)
+@implementation QIOSTextInputResponder
-- (BOOL)canBecomeFirstResponder
+- (id)initWithInputContext:(QIOSInputContext *)inputContext
{
- return YES;
+ if (!(self = [self init]))
+ return self;
+
+ m_inSendEventToFocusObject = NO;
+ m_inputContext = inputContext;
+
+ Qt::InputMethodHints hints = Qt::InputMethodHints([self imValue:Qt::ImHints].toUInt());
+
+ self.returnKeyType = (hints & Qt::ImhMultiLine) ? UIReturnKeyDefault : UIReturnKeyDone;
+ self.secureTextEntry = BOOL(hints & Qt::ImhHiddenText);
+ self.autocorrectionType = (hints & Qt::ImhNoPredictiveText) ?
+ UITextAutocorrectionTypeNo : UITextAutocorrectionTypeDefault;
+ self.spellCheckingType = (hints & Qt::ImhNoPredictiveText) ?
+ UITextSpellCheckingTypeNo : UITextSpellCheckingTypeDefault;
+
+ if (hints & Qt::ImhUppercaseOnly)
+ self.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters;
+ else if (hints & Qt::ImhNoAutoUppercase)
+ self.autocapitalizationType = UITextAutocapitalizationTypeNone;
+ else
+ self.autocapitalizationType = UITextAutocapitalizationTypeSentences;
+
+ if (hints & Qt::ImhUrlCharactersOnly)
+ self.keyboardType = UIKeyboardTypeURL;
+ else if (hints & Qt::ImhEmailCharactersOnly)
+ self.keyboardType = UIKeyboardTypeEmailAddress;
+ else if (hints & Qt::ImhDigitsOnly)
+ self.keyboardType = UIKeyboardTypeNumberPad;
+ else if (hints & Qt::ImhFormattedNumbersOnly)
+ self.keyboardType = UIKeyboardTypeDecimalPad;
+ else if (hints & Qt::ImhDialableCharactersOnly)
+ self.keyboardType = UIKeyboardTypeNumberPad;
+ else
+ self.keyboardType = UIKeyboardTypeDefault;
+
+ return self;
}
-- (BOOL)becomeFirstResponder
+- (void)dealloc
{
- // Note: QIOSInputContext controls our first responder status based on
- // whether or not the keyboard should be open or closed.
- [self updateTextInputTraits];
- return [super becomeFirstResponder];
+ [super dealloc];
}
-- (BOOL)resignFirstResponder
+- (BOOL)isFirstResponder
{
- // Resigning first responed status means that the virtual keyboard was closed, or
- // some other view became first responder. In either case we clear the focus object to
- // avoid blinking cursors in line edits etc:
- if (m_qioswindow)
- static_cast<QWindowPrivate *>(QObjectPrivate::get(m_qioswindow->window()))->clearFocusObject();
- return [super resignFirstResponder];
+ return YES;
}
-+ (bool)inUpdateKeyboardLayout
+- (UIResponder*)nextResponder
{
- return staticVariables()->inUpdateKeyboardLayout;
+ return qApp->focusWindow() ?
+ reinterpret_cast<QUIView *>(qApp->focusWindow()->handle()->winId()) : 0;
}
-- (void)updateKeyboardLayout
+/*!
+ 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 (![self isFirstResponder])
- return;
+ if (protocol == @protocol(UIKeyInput))
+ return m_inputContext->inputMethodAccepted();
- // There seems to be no API to inform that the keyboard layout needs to update.
- // As a work-around, we quickly resign first responder just to reassign it again.
- QScopedValueRollback<bool> rollback(staticVariables()->inUpdateKeyboardLayout);
- staticVariables()->inUpdateKeyboardLayout = true;
- [super resignFirstResponder];
- [self updateTextInputTraits];
- [super becomeFirstResponder];
+ return [super conformsToProtocol:protocol];
}
-- (void)updateUITextInputDelegate:(Qt::InputMethodQueries)query
+// -------------------------------------------------------------------------
+
+- (void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties
{
// As documented, we should not report textWillChange/textDidChange unless the text
// was changed externally. That will cause spell checking etc to fail. But we don't
@@ -179,34 +199,17 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
if (m_inSendEventToFocusObject)
return;
- if (query & (Qt::ImCursorPosition | Qt::ImAnchorPosition)) {
- [self.inputDelegate selectionWillChange:id<UITextInput>(self)];
- [self.inputDelegate selectionDidChange:id<UITextInput>(self)];
+ if (updatedProperties & (Qt::ImCursorPosition | Qt::ImAnchorPosition)) {
+ [self.inputDelegate selectionWillChange:self];
+ [self.inputDelegate selectionDidChange:self];
}
- if (query & Qt::ImSurroundingText) {
- [self.inputDelegate textWillChange:id<UITextInput>(self)];
- [self.inputDelegate textDidChange:id<UITextInput>(self)];
+ if (updatedProperties & Qt::ImSurroundingText) {
+ [self.inputDelegate textWillChange:self];
+ [self.inputDelegate textDidChange:self];
}
}
-- (void)updateInputMethodWithQuery:(Qt::InputMethodQueries)query
-{
- Q_UNUSED(query);
-
- QObject *focusObject = QGuiApplication::focusObject();
- if (!focusObject)
- return;
-
- // Note that we ignore \a query, and instead update using Qt::ImQueryInput. This enables us to just
- // store the event without copying out the result from the event each time. Besides, we seem to be
- // called with Qt::ImQueryInput when only changing selection, and always if typing text. So there would
- // not be any performance gain by only updating \a query.
- staticVariables()->inputMethodQueryEvent = QInputMethodQueryEvent(Qt::ImQueryInput);
- QCoreApplication::sendEvent(focusObject, &staticVariables()->inputMethodQueryEvent);
- [self updateUITextInputDelegate:query];
-}
-
- (void)sendEventToFocusObject:(QEvent &)e
{
QObject *focusObject = QGuiApplication::focusObject();
@@ -221,32 +224,9 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
QCoreApplication::sendEvent(focusObject, &e);
}
-- (void)reset
-{
- [self setMarkedText:@"" selectedRange:NSMakeRange(0, 0)];
- [self updateInputMethodWithQuery:Qt::ImQueryInput];
-
- // Guard agains recursive callbacks by posting calls to UITextInput
- dispatch_async(dispatch_get_main_queue(), ^{
- [self updateKeyboardLayout];
- [self updateUITextInputDelegate:Qt::ImQueryInput];
- });
-}
-
-- (void)commit
-{
- [self unmarkText];
-
- // Guard agains recursive callbacks by posting calls to UITextInput
- dispatch_async(dispatch_get_main_queue(), ^{
- [self updateKeyboardLayout];
- [self updateUITextInputDelegate:Qt::ImSurroundingText];
- });
-}
-
- (QVariant)imValue:(Qt::InputMethodQuery)query
{
- return staticVariables()->inputMethodQueryEvent.value(query);
+ return m_inputContext->imeState().currentState.value(query);
}
-(id<UITextInputTokenizer>)tokenizer
@@ -274,7 +254,8 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
[self sendEventToFocusObject:e];
}
-- (UITextRange *)selectedTextRange {
+- (UITextRange *)selectedTextRange
+{
int cursorPos = [self imValue:Qt::ImCursorPosition].toInt();
int anchorPos = [self imValue:Qt::ImAnchorPosition].toInt();
return [QUITextRange rangeWithNSRange:NSMakeRange(qMin(cursorPos, anchorPos), qAbs(anchorPos - cursorPos))];
@@ -333,7 +314,8 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
return NSOrderedSame;
}
-- (UITextRange *)markedTextRange {
+- (UITextRange *)markedTextRange
+{
return m_markedText.isEmpty() ? nil : [QUITextRange rangeWithNSRange:NSMakeRange(0, m_markedText.length())];
}
@@ -377,7 +359,8 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
// to be relative to the view this method returns.
// Since QInputMethod returns rects relative to the top level
// QWindow, that is also the view we need to return.
- QPlatformWindow *topLevel = m_qioswindow;
+ Q_ASSERT(qApp->focusWindow()->handle());
+ QPlatformWindow *topLevel = qApp->focusWindow()->handle();
while (QPlatformWindow *p = topLevel->parent())
topLevel = p;
return reinterpret_cast<UIView *>(topLevel->winId());
@@ -530,14 +513,15 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
return;
if ([text isEqualToString:@"\n"]) {
- if (self.returnKeyType == UIReturnKeyDone)
- qApp->inputMethod()->hide();
-
QKeyEvent press(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier);
QKeyEvent release(QEvent::KeyRelease, Qt::Key_Return, Qt::NoModifier);
[self sendEventToFocusObject:press];
[self sendEventToFocusObject:release];
+ Qt::InputMethodHints imeHints = static_cast<Qt::InputMethodHints>([self imValue:Qt::ImHints].toUInt());
+ if (!(imeHints & Qt::ImhMultiLine))
+ m_inputContext->hideVirtualKeyboard();
+
return;
}
@@ -557,47 +541,4 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables);
[self sendEventToFocusObject:release];
}
-- (void)updateTextInputTraits
-{
- // Ask the current focus object what kind of input it
- // expects, and configure the keyboard appropriately:
- QObject *focusObject = QGuiApplication::focusObject();
- if (!focusObject)
- return;
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImHints);
- if (!QCoreApplication::sendEvent(focusObject, &queryEvent))
- return;
- if (!queryEvent.value(Qt::ImEnabled).toBool())
- return;
-
- Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryEvent.value(Qt::ImHints).toUInt());
-
- self.returnKeyType = (hints & Qt::ImhMultiLine) ? UIReturnKeyDefault : UIReturnKeyDone;
- self.secureTextEntry = BOOL(hints & Qt::ImhHiddenText);
- self.autocorrectionType = (hints & Qt::ImhNoPredictiveText) ?
- UITextAutocorrectionTypeNo : UITextAutocorrectionTypeDefault;
- self.spellCheckingType = (hints & Qt::ImhNoPredictiveText) ?
- UITextSpellCheckingTypeNo : UITextSpellCheckingTypeDefault;
-
- if (hints & Qt::ImhUppercaseOnly)
- self.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters;
- else if (hints & Qt::ImhNoAutoUppercase)
- self.autocapitalizationType = UITextAutocapitalizationTypeNone;
- else
- self.autocapitalizationType = UITextAutocapitalizationTypeSentences;
-
- if (hints & Qt::ImhUrlCharactersOnly)
- self.keyboardType = UIKeyboardTypeURL;
- else if (hints & Qt::ImhEmailCharactersOnly)
- self.keyboardType = UIKeyboardTypeEmailAddress;
- else if (hints & Qt::ImhDigitsOnly)
- self.keyboardType = UIKeyboardTypeNumberPad;
- else if (hints & Qt::ImhFormattedNumbersOnly)
- self.keyboardType = UIKeyboardTypeDecimalPad;
- else if (hints & Qt::ImhDialableCharactersOnly)
- self.keyboardType = UIKeyboardTypeNumberPad;
- else
- self.keyboardType = UIKeyboardTypeDefault;
-}
-
@end
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index aa33a9b21d..2874d272fe 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -264,12 +264,12 @@ void QIOSWindow::requestActivateWindow()
if (blockedByModal())
return;
+ Q_ASSERT(m_view.window);
[m_view.window makeKeyWindow];
+ [m_view becomeFirstResponder];
if (window()->isTopLevel())
raise();
-
- QWindowSystemInterface::handleWindowActivated(window());
}
void QIOSWindow::raiseOrLower(bool raise)
diff --git a/src/plugins/platforms/ios/quiview.h b/src/plugins/platforms/ios/quiview.h
index 99c710ffee..c5bf3b6cbe 100644
--- a/src/plugins/platforms/ios/quiview.h
+++ b/src/plugins/platforms/ios/quiview.h
@@ -56,42 +56,14 @@ class QIOSWindow;
QHash<UITouch *, QWindowSystemInterface::TouchPoint> m_activeTouches;
int m_nextTouchId;
- @public
- UITextAutocapitalizationType autocapitalizationType;
- UITextAutocorrectionType autocorrectionType;
- BOOL enablesReturnKeyAutomatically;
- UIKeyboardAppearance keyboardAppearance;
- UIKeyboardType keyboardType;
- UIReturnKeyType returnKeyType;
- BOOL secureTextEntry;
- QString m_markedText;
- BOOL m_inSendEventToFocusObject;
-
@private
NSMutableArray *m_accessibleElements;
}
-@property(nonatomic, assign) id<UITextInputDelegate> inputDelegate;
-@property(nonatomic) UITextAutocapitalizationType autocapitalizationType;
-@property(nonatomic) UITextAutocorrectionType autocorrectionType;
-@property(nonatomic) UITextSpellCheckingType spellCheckingType;
-@property(nonatomic) BOOL enablesReturnKeyAutomatically;
-@property(nonatomic) UIKeyboardAppearance keyboardAppearance;
-@property(nonatomic) UIKeyboardType keyboardType;
-@property(nonatomic) UIReturnKeyType returnKeyType;
-@property(nonatomic, getter=isSecureTextEntry) BOOL secureTextEntry;
-
- (id)initWithQIOSWindow:(QIOSWindow *)window;
- (void)sendUpdatedExposeEvent;
@end
-@interface QUIView (TextInput) <UITextInput>
-- (void)updateInputMethodWithQuery:(Qt::InputMethodQueries)query;
-- (void)reset;
-- (void)commit;
-+ (bool)inUpdateKeyboardLayout;
-@end
-
@interface QUIView (Accessibility)
- (void)clearAccessibleCache;
@end
diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm
index e534bdcd69..5687c078ea 100644
--- a/src/plugins/platforms/ios/quiview.mm
+++ b/src/plugins/platforms/ios/quiview.mm
@@ -50,14 +50,6 @@
@implementation QUIView
-@synthesize autocapitalizationType;
-@synthesize autocorrectionType;
-@synthesize enablesReturnKeyAutomatically;
-@synthesize keyboardAppearance;
-@synthesize keyboardType;
-@synthesize returnKeyType;
-@synthesize secureTextEntry;
-
+ (Class)layerClass
{
return [CAEAGLLayer class];
@@ -86,7 +78,6 @@
self.hidden = YES;
self.multipleTouchEnabled = YES;
- m_inSendEventToFocusObject = NO;
}
return self;
@@ -202,6 +193,46 @@
QWindowSystemInterface::flushWindowSystemEvents();
}
+// -------------------------------------------------------------------------
+
+- (BOOL)canBecomeFirstResponder
+{
+ return YES;
+}
+
+- (BOOL)becomeFirstResponder
+{
+ if ([super becomeFirstResponder]) {
+ QWindowSystemInterface::handleWindowActivated(m_qioswindow->window());
+ QWindowSystemInterface::flushWindowSystemEvents();
+
+ return YES;
+ }
+
+ return NO;
+}
+
+- (BOOL)resignFirstResponder
+{
+ if ([super resignFirstResponder]) {
+ // We don't want to send window deactivation in case we're in the process
+ // of activating another window. The handleWindowActivated of the activation
+ // will take care of both.
+ dispatch_async(dispatch_get_main_queue (), ^{
+ if (![[UIResponder currentFirstResponder] isKindOfClass:[QUIView class]])
+ QWindowSystemInterface::handleWindowActivated(0);
+ QWindowSystemInterface::flushWindowSystemEvents();
+ });
+
+ return YES;
+ }
+
+ return NO;
+}
+
+// -------------------------------------------------------------------------
+
+
- (void)updateTouchList:(NSSet *)touches withState:(Qt::TouchPointState)state
{
// We deliver touch events in global coordinates. But global in this respect
@@ -342,5 +373,4 @@
@end
// Include category as an alternative to using -ObjC (Apple QA1490)
-#include "quiview_textinput.mm"
#include "quiview_accessibility.mm"