From 5a250eff8bb010930306d6add6f44a3c9498c690 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 14 Mar 2018 17:30:39 +0100 Subject: [PATCH] Fix input panel event propagation --- inputcontext/QskInputCompositionModel.cpp | 29 ++++++++++----- inputcontext/QskInputCompositionModel.h | 4 +++ inputcontext/QskInputContext.cpp | 43 +++++++++++++++++------ inputcontext/QskInputContext.h | 2 ++ playground/inputpanel/TextInput.cpp | 5 +++ playground/inputpanel/TextInput.h | 5 ++- src/controls/QskInputPanel.cpp | 5 +-- 7 files changed, 71 insertions(+), 22 deletions(-) diff --git a/inputcontext/QskInputCompositionModel.cpp b/inputcontext/QskInputCompositionModel.cpp index 601b7aef..567f0dcb 100644 --- a/inputcontext/QskInputCompositionModel.cpp +++ b/inputcontext/QskInputCompositionModel.cpp @@ -37,20 +37,20 @@ static QString qskKeyString( int code ) class QskInputCompositionModel::PrivateData { public: + PrivateData() : + inputItem( nullptr ), + groupIndex( 0 ) + { + } // QInputMethod QString preedit; QTextCharFormat preeditFormat; QList< QInputMethodEvent::Attribute > preeditAttributes; + QObject* inputItem; int groupIndex; }; -static inline void sendCompositionEvent( QInputMethodEvent* e ) -{ - if ( auto focusObject = QGuiApplication::focusObject() ) - QCoreApplication::sendEvent( focusObject, e ); -} - QskInputCompositionModel::QskInputCompositionModel(): m_data( new PrivateData ) { @@ -77,7 +77,7 @@ void QskInputCompositionModel::composeKey( Qt::Key key ) QInputMethodQueryEvent queryEvent( Qt::ImSurroundingText | Qt::ImMaximumTextLength | Qt::ImHints ); - QCoreApplication::sendEvent( focusObject, &queryEvent ); + QCoreApplication::sendEvent( m_data->inputItem, &queryEvent ); const auto hints = static_cast< Qt::InputMethodHints >( queryEvent.value( Qt::ImHints ).toInt() ); const int maxLength = queryEvent.value( Qt::ImMaximumTextLength ).toInt(); @@ -237,8 +237,8 @@ void QskInputCompositionModel::backspace() // Backspace one character only if preedit was inactive QKeyEvent keyPress( QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier ); QKeyEvent keyRelease( QEvent::KeyRelease, Qt::Key_Backspace, Qt::NoModifier ); - QCoreApplication::sendEvent( focusWindow, &keyPress ); - QCoreApplication::sendEvent( focusWindow, &keyRelease ); + QCoreApplication::sendEvent( m_data->inputItem, &keyPress ); + QCoreApplication::sendEvent( m_data->inputItem, &keyRelease ); return; } @@ -267,6 +267,12 @@ void QskInputCompositionModel::moveCursor( Qt::Key key ) QCoreApplication::sendEvent( focusWindow, &moveCursorRelease ); } +void QskInputCompositionModel::sendCompositionEvent( QInputMethodEvent* e ) +{ + if ( m_data->inputItem ) + QCoreApplication::sendEvent( m_data->inputItem, e ); +} + bool QskInputCompositionModel::hasIntermediate() const { return false; @@ -300,6 +306,11 @@ QVector< Qt::Key > QskInputCompositionModel::groups() const return QVector< Qt::Key >(); } +void QskInputCompositionModel::setInputItem( QObject *inputItem ) +{ + m_data->inputItem = inputItem; +} + bool QskInputCompositionModel::nextGroupIndex(int& index, bool forward) const { Q_UNUSED(index); diff --git a/inputcontext/QskInputCompositionModel.h b/inputcontext/QskInputCompositionModel.h index e96eecd2..94e5be53 100644 --- a/inputcontext/QskInputCompositionModel.h +++ b/inputcontext/QskInputCompositionModel.h @@ -10,6 +10,7 @@ #include +class QInputMethodEvent; class QStringList; class QskInputCompositionModel : public QObject @@ -37,6 +38,8 @@ public: virtual QVector< Qt::Key > groups() const; + void setInputItem( QObject* inputItem ); + protected: // Used for text composition virtual bool hasIntermediate() const; @@ -50,6 +53,7 @@ Q_SIGNALS: private: void backspace(); void moveCursor( Qt::Key key ); + void sendCompositionEvent( QInputMethodEvent* e ); class PrivateData; std::unique_ptr< PrivateData > m_data; diff --git a/inputcontext/QskInputContext.cpp b/inputcontext/QskInputContext.cpp index 20a24c20..9f97057e 100644 --- a/inputcontext/QskInputContext.cpp +++ b/inputcontext/QskInputContext.cpp @@ -26,6 +26,8 @@ QskInputContext::QskInputContext(): connect( qskSetup, &QskSetup::inputPanelChanged, this, &QskInputContext::setInputPanel ); setInputPanel( qskSetup->inputPanel() ); + + m_inputCompositionModel.reset( new QskInputCompositionModel ); } QskInputContext::~QskInputContext() @@ -41,11 +43,11 @@ bool QskInputContext::isValid() const void QskInputContext::update( Qt::InputMethodQueries queries ) { - if ( !m_focusObject ) + if ( !m_inputItem ) return; QInputMethodQueryEvent queryEvent( queries ); - if ( !QCoreApplication::sendEvent( m_focusObject, &queryEvent ) ) + if ( !QCoreApplication::sendEvent( m_inputItem, &queryEvent ) ) return; // Qt::ImCursorRectangle @@ -209,18 +211,39 @@ void QskInputContext::setFocusObject( QObject* focusObject ) m_focusObject = focusObject; if ( !m_focusObject ) - return; - - QInputMethodQueryEvent queryEvent( Qt::ImEnabled ); - if ( !QCoreApplication::sendEvent( m_focusObject, &queryEvent ) ) - return; - - if ( !queryEvent.value( Qt::ImEnabled ).toBool() ) { - hideInputPanel(); + m_inputItem = nullptr; + m_inputCompositionModel->setInputItem( nullptr ); return; } + bool inputItemChanged = false; + + auto focusQuickItem = qobject_cast< QQuickItem* >( focusObject ); + if( focusQuickItem ) + { + // Do not change the input item when panel buttons get the focus: + if( qskNearestFocusScope( focusQuickItem ) != m_inputPanel ) + { + m_inputItem = focusQuickItem; + m_inputCompositionModel->setInputItem( m_inputItem ); // ### use a signal/slot connection + inputItemChanged = true; + } + } + + if( inputItemChanged ) + { + QInputMethodQueryEvent queryEvent( Qt::ImEnabled ); + if ( !QCoreApplication::sendEvent( m_inputItem, &queryEvent ) ) + return; + + if ( !queryEvent.value( Qt::ImEnabled ).toBool() ) + { + hideInputPanel(); + return; + } + } + m_focusObject->installEventFilter( this ); update( Qt::InputMethodQuery( Qt::ImQueryAll & ~Qt::ImEnabled ) ); } diff --git a/inputcontext/QskInputContext.h b/inputcontext/QskInputContext.h index 1a167f86..31a7c30d 100644 --- a/inputcontext/QskInputContext.h +++ b/inputcontext/QskInputContext.h @@ -8,6 +8,7 @@ #include #include +#include #include @@ -45,6 +46,7 @@ private Q_SLOTS: private: QPointer< QObject > m_focusObject; + QPointer< QQuickItem > m_inputItem; QPointer< QskInputPanel > m_inputPanel; std::unique_ptr< QskInputCompositionModel > m_inputCompositionModel; }; diff --git a/playground/inputpanel/TextInput.cpp b/playground/inputpanel/TextInput.cpp index 8d43e2f3..6069ffdc 100644 --- a/playground/inputpanel/TextInput.cpp +++ b/playground/inputpanel/TextInput.cpp @@ -10,3 +10,8 @@ TextInput::~TextInput() { } + +void TextInput::inputMethodEvent(QInputMethodEvent *event) +{ + QQuickTextInput::inputMethodEvent(event); +} diff --git a/playground/inputpanel/TextInput.h b/playground/inputpanel/TextInput.h index 3fe56eeb..86ff4f3f 100644 --- a/playground/inputpanel/TextInput.h +++ b/playground/inputpanel/TextInput.h @@ -7,7 +7,10 @@ class TextInput : public QQuickTextInput { public: TextInput( QQuickItem* parent ); - virtual ~TextInput(); + virtual ~TextInput() override; + +protected: + void inputMethodEvent(QInputMethodEvent *) Q_DECL_OVERRIDE; }; #endif // TEXTINPUT_H diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index 967e1e34..e49e94db 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -148,8 +148,6 @@ QskKeyButton::QskKeyButton( int keyIndex, QskInputPanel* inputPanel, QQuickItem* m_keyIndex( keyIndex ), m_inputPanel( inputPanel ) { - setFlag( QQuickItem::ItemAcceptsInputMethod ); - updateText(); connect( this, &QskKeyButton::pressed, this, [ this ]() @@ -248,6 +246,9 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ): QObject::connect( this, &QskControl::localeChanged, this, &QskInputPanel::updateLocale ); + + setFlag( ItemIsFocusScope, true ); + setTabFence( true ); } QskInputPanel::~QskInputPanel()