From 46acfa5d2ab803d8b5fbfbcdd826650b94624187 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Thu, 20 Mar 2014 10:22:46 +0100 Subject: iOS: stop keyboard from reopending after the gesture finishes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On iOS we have set the style hint 'SetFocusOnTouchRelease'. This is in conflict with the 'hide keyboard' gesture, since a control can try to regain focus (and open the keyboard) if the gesture ends on top of it. So we need some extra work-around code to prevent this from happening. The correct way would probably be to cancel the touch sequence once the gesture triggers, but this is not well implemented in Qt yet, especially in combination with widgets and mouse synthesis. Since usage of the gesture behaves really bad in some cases (e.g if using the TextEdit example) we need to apply this for now. Change-Id: Ib3327c0bd94d722b4c4793bc6d152d6d19810e4b Reviewed-by: Morten Johan Sørvig Reviewed-by: Richard Moe Gustavsen --- src/plugins/platforms/ios/qiosinputcontext.mm | 40 +++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index f5d1b8f220..ab4e3f38e7 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -47,6 +47,7 @@ #include "qioswindow.h" #include "quiview.h" #include +#include @interface QIOSKeyboardListener : UIGestureRecognizer { @public @@ -54,6 +55,7 @@ BOOL m_keyboardVisible; BOOL m_keyboardVisibleAndDocked; BOOL m_ignoreKeyboardChanges; + BOOL m_keyboardHiddenByGesture; QRectF m_keyboardRect; QRectF m_keyboardEndRect; NSTimeInterval m_duration; @@ -72,6 +74,7 @@ m_keyboardVisible = NO; m_keyboardVisibleAndDocked = NO; m_ignoreKeyboardChanges = NO; + m_keyboardHiddenByGesture = NO; m_duration = 0; m_curve = UIViewAnimationCurveEaseOut; m_viewController = 0; @@ -175,7 +178,11 @@ // Note that UIKeyboardWillHideNotification is also sendt when the keyboard is undocked. m_keyboardVisibleAndDocked = NO; m_keyboardEndRect = [self getKeyboardRect:notification]; - self.enabled = NO; + if (!m_keyboardHiddenByGesture) { + // Only disable the gesture if the hiding of the keyboard was not caused by it. + // Otherwise we need to await the final touchEnd callback for doing some clean-up. + self.enabled = NO; + } m_context->scroll(0); } @@ -198,12 +205,35 @@ - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { QPointF p = fromCGPoint([[touches anyObject] locationInView:m_viewController.view]); - if (m_keyboardRect.contains(p)) + if (m_keyboardRect.contains(p)) { + m_keyboardHiddenByGesture = YES; m_context->hideInputPanel(); + } [super touchesMoved:touches withEvent:event]; } +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ + [self performSelectorOnMainThread:@selector(touchesEndedPostDelivery) withObject:nil waitUntilDone:NO]; + [super touchesEnded:touches withEvent:event]; +} + +- (void)touchesEndedPostDelivery +{ + // Do some clean-up _after_ touchEnd has been delivered to QUIView + m_keyboardHiddenByGesture = NO; + if (!m_keyboardVisibleAndDocked) { + self.enabled = NO; + if (qApp->focusObject()) { + // UI Controls are told to gain focus on touch release. So when the 'hide keyboard' gesture + // finishes, the final touch end can trigger a control to gain focus. This is in conflict with + // the gesture, so we clear focus once more as a work-around. + static_cast(QObjectPrivate::get(qApp->focusWindow()))->clearFocusObject(); + } + } +} + @end QIOSInputContext::QIOSInputContext() @@ -230,6 +260,12 @@ 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. -- cgit v1.2.3