diff options
author | Morten Johan Sørvig <morten.sorvig@theqtcompany.com> | 2015-11-10 16:01:01 +0100 |
---|---|---|
committer | Timur Pocheptsov <timur.pocheptsov@theqtcompany.com> | 2016-03-21 16:26:27 +0000 |
commit | 68987d5454a347807c227ba3e2e2db3e050911df (patch) | |
tree | 1875d76a306dc17f11ec167d41db8af151ed6646 /src/plugins/platforms | |
parent | 820e69d6c214f95e6db101c6e7caf28b0a248c69 (diff) |
Cocoa: Forward rejected key events.
Forward rejected key events to the next responder
by checking the return value from QWindowSystemInterface
and calling the superclass event handler.
This is useful when Qt is running as a plugin in a
host application; the host can now react to key
events even if Qt has focus.
Qt will often not accept keyUp events, even if the
corresponding keyDown was accepted, for example in
the case of text controls. We don't want to forward
'bare' keyUps, so keep track of which keyDowns have
been seen.
Change-Id: I976448a5d305a657a0e91aeb271b158f8b598286
Task-number: QTBUG-45768
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@theqtcompany.com>
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview.h | 4 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview.mm | 49 |
2 files changed, 47 insertions, 6 deletions
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 59df75b980..e5f136d0cd 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -43,6 +43,7 @@ #include <AppKit/AppKit.h> #include <QtCore/QPointer> +#include <QtCore/QSet> #include <QtGui/QImage> #include <QtGui/QAccessible> @@ -85,6 +86,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); bool m_exposedOnMoveToWindow; NSEvent *m_currentlyInterpretedKeyEvent; bool m_isMenuView; + QSet<quint32> m_acceptedKeyDowns; } - (id)init; @@ -142,7 +144,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); - (int) convertKeyCode : (QChar)keyCode; + (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags; -- (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType; +- (bool)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType; - (void)keyDown:(NSEvent *)theEvent; - (void)keyUp:(NSEvent *)theEvent; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index ecc9f2db11..fb83f3211a 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -911,6 +911,25 @@ QT_WARNING_POP } } + QPointF qtWindowPoint; + QPointF qtScreenPoint; + [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; + Q_UNUSED(qtScreenPoint); + + bool masked = m_maskRegion.contains(qtWindowPoint.toPoint()); + + // Maintain masked state for the button for use by MouseDragged and Up. + if (masked) + m_acceptedMouseDowns.remove(Qt::LeftButton); + else + m_acceptedMouseDowns.insert(Qt::LeftButton); + + // Forward masked out events to the next responder + if (masked) { + [super mouseDown:theEvent]; + return; + } + if ([self hasMarkedText]) { [[NSTextInputContext currentInputContext] handleEvent:theEvent]; } else { @@ -1483,7 +1502,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) return qtMods; } -- (void)handleKeyEvent:(NSEvent *)nsevent eventType:(int)eventType +- (bool)handleKeyEvent:(NSEvent *)nsevent eventType:(int)eventType { ulong timestamp = [nsevent timestamp] * 1000; ulong nativeModifiers = [nsevent modifierFlags]; @@ -1553,26 +1572,46 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) m_sendKeyEvent = true; } - if (m_sendKeyEvent && m_composingText.isEmpty()) + bool accepted = true; + if (m_sendKeyEvent && m_composingText.isEmpty()) { QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, QEvent::Type(eventType), keyCode, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1, false); - + accepted = QWindowSystemInterface::flushWindowSystemEvents(); + } m_sendKeyEvent = false; m_resendKeyEvent = false; + return accepted; } - (void)keyDown:(NSEvent *)nsevent { if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) ) return [super keyDown:nsevent]; - [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)]; + + const bool accepted = [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)]; + + // Track keyDown acceptance state for later acceptance of the keyUp. + if (accepted) + m_acceptedKeyDowns.insert([nsevent keyCode]); + + // Propagate the keyDown to the next responder if Qt did not accept it. + if (!accepted) + [super keyDown:nsevent]; } - (void)keyUp:(NSEvent *)nsevent { if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) ) return [super keyUp:nsevent]; - [self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)]; + + const bool keyUpAccepted = [self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)]; + + // Propagate the keyUp if neither Qt accepted it nor the corresponding KeyDown was + // accepted. Qt text controls wil often not use and ignore keyUp events, but we + // want to avoid propagating unmatched keyUps. + const bool keyDownAccepted = m_acceptedKeyDowns.remove([nsevent keyCode]); + if (!keyUpAccepted && !keyDownAccepted) + [super keyUp:nsevent]; } - (void)cancelOperation:(id)sender |