From 67dee082ec74bf017c22bf2e71b11a719e56e4d0 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Wed, 11 Apr 2018 08:58:14 +0200 Subject: [PATCH] filtering of input method events moved to QskInputContext --- inputcontext/QskInputContext.cpp | 37 +++++++++++++- inputcontext/QskInputContext.h | 2 + src/controls/QskControl.cpp | 3 ++ src/inputpanel/QskInputPanel.cpp | 87 +------------------------------- src/inputpanel/QskInputPanel.h | 5 -- 5 files changed, 41 insertions(+), 93 deletions(-) diff --git a/inputcontext/QskInputContext.cpp b/inputcontext/QskInputContext.cpp index 7a1c0c3c..45ae6705 100644 --- a/inputcontext/QskInputContext.cpp +++ b/inputcontext/QskInputContext.cpp @@ -323,6 +323,8 @@ void QskInputContext::hideInputPanel() { m_data->inputPanel->setVisible( false ); } + + qGuiApp->removeEventFilter( this ); } bool QskInputContext::isInputPanelVisible() const @@ -365,6 +367,14 @@ void QskInputContext::setFocusObject( QObject* focusObject ) if( qskNearestFocusScope( focusItem ) != m_data->inputPanel ) setInputItem( focusItem ); } + + if ( m_data->inputPanel && m_data->inputPanel->isVisible() ) + { + if ( m_data->inputItem && focusItem != m_data->inputItem ) + qGuiApp->installEventFilter( this ); + else + qGuiApp->removeEventFilter( this ); + } } void QskInputContext::setCompositionModel( @@ -468,11 +478,12 @@ void QskInputContext::setInputPanel( QQuickItem* inputPanel ) if ( inputPanel ) { - // maybe using a QQuickItemChangeListener instead -#if 1 connect( inputPanel, &QQuickItem::visibleChanged, this, &QPlatformInputContext::emitInputPanelVisibleChanged ); + // maybe using a QQuickItemChangeListener instead +#if 1 + connect( inputPanel, &QQuickItem::xChanged, this, &QPlatformInputContext::emitKeyboardRectChanged ); @@ -508,6 +519,28 @@ void QskInputContext::commit() { } +bool QskInputContext::eventFilter( QObject* object, QEvent* event ) +{ + if ( event->type() == QEvent::InputMethodQuery ) + { + /* + Qt/Quick expects that the item associated with the input context + holds the focus. But this does not work, when a virtual + keyboard is used, where you can navigate and select inside. + So we have to fix the receiver. + */ + + if ( ( object != m_data->inputItem ) + && qskIsAncestorOf( m_data->inputPanel, m_data->inputItem ) ) + { + sendEventToInputItem( event ); + return true; + } + } + + return Inherited::eventFilter( object, event ); +} + bool QskInputContext::filterEvent( const QEvent* event ) { // called from QXcbKeyboard, but what about other platforms diff --git a/inputcontext/QskInputContext.h b/inputcontext/QskInputContext.h index 79458d70..887f3060 100644 --- a/inputcontext/QskInputContext.h +++ b/inputcontext/QskInputContext.h @@ -57,6 +57,8 @@ private Q_SLOTS: void handleCandidatesChanged(); void setInputPanel( QQuickItem* ); + virtual bool eventFilter( QObject*, QEvent* ) override; + private: void setInputItem( QQuickItem* ); QskInputCompositionModel* compositionModel() const; diff --git a/src/controls/QskControl.cpp b/src/controls/QskControl.cpp index 56a233e5..5b857a88 100644 --- a/src/controls/QskControl.cpp +++ b/src/controls/QskControl.cpp @@ -78,6 +78,9 @@ bool qskIsItemComplete( const QQuickItem* item ) bool qskIsAncestorOf( const QQuickItem* item, const QQuickItem* child ) { + if ( item == nullptr || child == nullptr ) + return false; + #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) return item->isAncestorOf( child ); #else diff --git a/src/inputpanel/QskInputPanel.cpp b/src/inputpanel/QskInputPanel.cpp index 413c7383..4e560d67 100644 --- a/src/inputpanel/QskInputPanel.cpp +++ b/src/inputpanel/QskInputPanel.cpp @@ -10,13 +10,7 @@ #include #include - -QSK_QT_PRIVATE_BEGIN -#include -QSK_QT_PRIVATE_END - -#include -#include +#include QString qskNativeLocaleString( const QLocale& locale ) { @@ -105,32 +99,6 @@ QString qskNativeLocaleString( const QLocale& locale ) } } -static inline QQuickItem* qskInputItem() -{ - QPlatformInputContext* inputContext; -#if 1 - inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext(); -#else - // for some reason the gcc sanitizer does not like this one - inputContext = QInputMethodPrivate::get( inputMethod )->platformInputContext(); -#endif - - QQuickItem* item = nullptr; - - QMetaObject::invokeMethod( inputContext, "inputItem", - Qt::DirectConnection, Q_RETURN_ARG( QQuickItem*, item ) ); - - return item; -} - -static inline void qskInstallEventFilter( QskInputPanel* panel, bool on ) -{ - if ( on ) - qGuiApp->installEventFilter( panel ); - else - qGuiApp->removeEventFilter( panel ); -} - class QskInputPanel::PrivateData { public: @@ -201,57 +169,4 @@ void QskInputPanel::commitKey( Qt::Key key ) static_cast< QInputMethod::Action >( Compose ), key ); } -void QskInputPanel::updateLayout() -{ - if ( !isInitiallyPainted() ) - qskInstallEventFilter( this, isVisible() ); - - Inherited::updateLayout(); -} - -void QskInputPanel::itemChange( QQuickItem::ItemChange change, - const QQuickItem::ItemChangeData& value ) -{ - switch( change ) - { - case QQuickItem::ItemVisibleHasChanged: - case QQuickItem::ItemSceneChange: - { - if ( isInitiallyPainted() ) - qskInstallEventFilter( this, isVisible() ); - - break; - } - default: - break; - } - - Inherited::itemChange( change, value ); -} - -bool QskInputPanel::eventFilter( QObject* object, QEvent* event ) -{ - if ( event->type() == QEvent::InputMethodQuery ) - { - const auto item = qskInputItem(); - - /* - Qt/Quick expects that the item associated with the input context - always has the focus. But this does not work, when a virtual - keyboard is used, where you can navigate and select inside. - So we have to fix the receiver. - - Maybe QEvent::EnterEditFocus is good for something ?? - */ - - if ( item && ( object != item ) && qskIsAncestorOf( this, item ) ) - { - QGuiApplication::sendEvent( item, event ); - return true; - } - } - - return Inherited::eventFilter( object, event ); -} - #include "moc_QskInputPanel.cpp" diff --git a/src/inputpanel/QskInputPanel.h b/src/inputpanel/QskInputPanel.h index ccdb84d6..f108770d 100644 --- a/src/inputpanel/QskInputPanel.h +++ b/src/inputpanel/QskInputPanel.h @@ -38,11 +38,6 @@ public Q_SLOTS: void setCandidatesEnabled( bool ); void setCandidates( const QVector< QString >& ); -protected: - virtual void updateLayout() override; - virtual void itemChange( ItemChange, const ItemChangeData& ) override; - virtual bool eventFilter( QObject*, QEvent* ) override; - private: void commitKey( Qt::Key ); void commitCandidate( int );