diff --git a/inputcontext/QskHunspellCompositionModel.cpp b/inputcontext/QskHunspellCompositionModel.cpp index acb2527d..69c7e0a3 100644 --- a/inputcontext/QskHunspellCompositionModel.cpp +++ b/inputcontext/QskHunspellCompositionModel.cpp @@ -10,8 +10,8 @@ public: QVector< QString > candidates; }; -QskHunspellCompositionModel::QskHunspellCompositionModel( QskInputContext* context ): - Inherited( Words, context ), +QskHunspellCompositionModel::QskHunspellCompositionModel( QObject* object ): + Inherited( Words, object ), m_data( new PrivateData() ) { #if 1 diff --git a/inputcontext/QskHunspellCompositionModel.h b/inputcontext/QskHunspellCompositionModel.h index d7948c85..470cfaa7 100644 --- a/inputcontext/QskHunspellCompositionModel.h +++ b/inputcontext/QskHunspellCompositionModel.h @@ -14,7 +14,7 @@ class QskHunspellCompositionModel : public QskInputCompositionModel using Inherited = QskInputCompositionModel; public: - QskHunspellCompositionModel( QskInputContext* context ); + QskHunspellCompositionModel( QObject* ); virtual ~QskHunspellCompositionModel() override; virtual int candidateCount() const override; diff --git a/inputcontext/QskInputCompositionModel.cpp b/inputcontext/QskInputCompositionModel.cpp index 7005e03a..90879e85 100644 --- a/inputcontext/QskInputCompositionModel.cpp +++ b/inputcontext/QskInputCompositionModel.cpp @@ -4,13 +4,10 @@ *****************************************************************************/ #include "QskInputCompositionModel.h" -#include "QskInputContext.h" - -#include QskInputCompositionModel::QskInputCompositionModel( - Attributes attributes, QskInputContext* context ): - QObject( context ), + Attributes attributes, QObject* parent ): + QObject( parent ), m_attributes( attributes ) { } @@ -19,72 +16,9 @@ QskInputCompositionModel::~QskInputCompositionModel() { } -QskInputContext* QskInputCompositionModel::context() const +QskInputCompositionModel::Attributes QskInputCompositionModel::attributes() const { - return qobject_cast< QskInputContext* >( parent() ); -} - -void QskInputCompositionModel::composeKey( const QString& text, int spaceLeft ) -{ - if ( candidateCount() > 0 ) - { - m_preedit += text; - - requestCandidates( m_preedit ); - context()->sendText( m_preedit, false ); - - return; - } - - requestCandidates( m_preedit ); - - QString txt; - if ( candidateCount() == 0 ) - { - txt = m_preedit.left( spaceLeft ); - spaceLeft -= txt.length(); - } - else - { - txt = candidate( 0 ); - --spaceLeft; - } - - context()->sendText( txt, true ); - m_preedit.clear(); - resetCandidates(); - - if ( spaceLeft ) - { - m_preedit = text; - requestCandidates( m_preedit ); - - if ( candidateCount() > 0 ) - { - context()->sendText( m_preedit, false ); - } - else - { - context()->sendText( m_preedit, true ); - m_preedit.clear(); - resetCandidates(); - } - } -} - -void QskInputCompositionModel::setPreeditText( const QString& text ) -{ - if ( text != m_preedit ) - { - m_preedit = text; - requestCandidates( m_preedit ); - } -} - -void QskInputCompositionModel::reset() -{ - m_preedit.clear(); - resetCandidates(); + return m_attributes; } #include "moc_QskInputCompositionModel.cpp" diff --git a/inputcontext/QskInputCompositionModel.h b/inputcontext/QskInputCompositionModel.h index 56f4aa46..7d9e9930 100644 --- a/inputcontext/QskInputCompositionModel.h +++ b/inputcontext/QskInputCompositionModel.h @@ -8,8 +8,6 @@ #include -class QskInputContext; - class QskInputCompositionModel : public QObject { Q_OBJECT @@ -25,43 +23,22 @@ public: virtual ~QskInputCompositionModel(); - void composeKey( const QString& text, int spaceLeft ); + virtual void requestCandidates( const QString& preedit ) = 0; + virtual void resetCandidates() = 0; virtual int candidateCount() const = 0; virtual QString candidate( int ) const = 0; - void reset(); - - QString preeditText() const; - void setPreeditText( const QString& ); - Attributes attributes() const; -protected: - QskInputCompositionModel( Attributes, QskInputContext* ); - - virtual void requestCandidates( const QString& preedit ) = 0; - virtual void resetCandidates() = 0; - - QskInputContext* context() const; - Q_SIGNALS: void candidatesChanged(); +protected: + QskInputCompositionModel( Attributes, QObject* ); + private: - QString m_preedit; const Attributes m_attributes; }; -inline QString QskInputCompositionModel::preeditText() const -{ - return m_preedit; -} - -inline QskInputCompositionModel::Attributes -QskInputCompositionModel::attributes() const -{ - return m_attributes; -} - #endif diff --git a/inputcontext/QskInputContext.cpp b/inputcontext/QskInputContext.cpp index f3cbecbe..cc1644a8 100644 --- a/inputcontext/QskInputContext.cpp +++ b/inputcontext/QskInputContext.cpp @@ -49,22 +49,6 @@ static inline QString qskKeyString( int keyCode ) return QChar( keyCode ); } -static inline bool qskIsControlKey( int keyCode ) -{ - switch ( keyCode ) - { - case Qt::Key_Backspace: - case Qt::Key_Muhenkan: - case Qt::Key_Return: - case Qt::Key_Left: - case Qt::Key_Right: - case Qt::Key_Escape: - return true; - } - - return false; -} - static void qskSetLocale( QQuickItem* inputPanel, const QLocale& locale ) { if ( auto control = qobject_cast< QskControl* >( inputPanel ) ) @@ -145,6 +129,8 @@ public: QHash< uint, QskInputCompositionModel* > compositionModels; + QString preedit; + // the input panel is embedded in a window bool ownsInputPanelWindow : 1; }; @@ -225,7 +211,7 @@ void QskInputContext::update( Qt::InputMethodQueries queries ) ImhPreferNumbers = 0x8, // default to number keyboard ImhPreferUppercase = 0x10, // start with shift on ImhPreferLowercase = 0x20, // start with shift off - ImhNoPredictiveText = 0x40, // ignored for now + ImhNoPredictiveText = 0x40, // not use predictive text ImhDate = 0x80, // ignored for now (no date keyboard) ImhTime = 0x100, // ignored for know (no time keyboard) @@ -426,6 +412,12 @@ void QskInputContext::showInputPanel() } update( Qt::ImQueryAll ); + +#if 1 + if ( auto panel = qobject_cast< QskInputPanel* >( m_data->inputPanel ) ) + panel->updateInputProxy( m_data->inputItem ); +#endif + inputPanel->setVisible( true ); #if 0 @@ -482,6 +474,10 @@ void QskInputContext::hideInputPanel() } qGuiApp->removeEventFilter( this ); + + m_data->preedit.clear(); + if ( auto model = compositionModel() ) + model->resetCandidates(); } bool QskInputContext::isInputPanelVisible() const @@ -612,7 +608,8 @@ void QskInputContext::invokeAction( QInputMethod::Action action, int value ) sendText( text, true ); - model->reset(); + m_data->preedit.clear(); + model->resetCandidates(); } break; @@ -664,6 +661,7 @@ void QskInputContext::processKey( int key ) if ( !( hints & Qt::ImhHiddenText ) ) model = compositionModel(); + auto& preedit = m_data->preedit; /* First we have to handle the control keys */ @@ -674,13 +672,12 @@ void QskInputContext::processKey( int key ) { if ( model ) { - auto preeditText = model->preeditText(); - if ( !preeditText.isEmpty() ) + if ( !preedit.isEmpty() ) { - preeditText.chop( 1 ); - sendText( preeditText, false ); + preedit.chop( 1 ); + sendText( preedit, false ); - model->setPreeditText( preeditText ); + model->requestCandidates( preedit ); return; } } @@ -692,13 +689,14 @@ void QskInputContext::processKey( int key ) { if ( model ) { - const auto preeditText = model->preeditText(); - if ( !preeditText.isEmpty() ) + if ( !preedit.isEmpty() ) { if ( spaceLeft ) - sendText( preeditText.left( spaceLeft ), true ); + sendText( preedit.left( spaceLeft ), true ); + + preedit.clear(); + model->resetCandidates(); - model->reset(); return; } } @@ -715,14 +713,14 @@ void QskInputContext::processKey( int key ) { if ( model ) { - auto preeditText = model->preeditText(); - if ( !preeditText.isEmpty() && spaceLeft) + if ( !preedit.isEmpty() && spaceLeft) { - preeditText = preeditText.left( spaceLeft ); - sendText( preeditText, true ); - spaceLeft -= preeditText.length(); + preedit = preedit.left( spaceLeft ); + sendText( preedit, true ); + spaceLeft -= preedit.length(); - model->reset(); + preedit.clear(); + model->resetCandidates(); } } @@ -741,7 +739,19 @@ void QskInputContext::processKey( int key ) if ( model ) { - model->composeKey( text, spaceLeft ); + preedit += text; + + model->requestCandidates( preedit ); + + if ( model->candidateCount() > 0 ) + { + sendText( preedit, false ); + } + else + { + sendText( preedit.left( spaceLeft ), true ); + preedit.clear(); + } } else { diff --git a/inputcontext/QskPinyinCompositionModel.cpp b/inputcontext/QskPinyinCompositionModel.cpp index 69850107..469b5745 100644 --- a/inputcontext/QskPinyinCompositionModel.cpp +++ b/inputcontext/QskPinyinCompositionModel.cpp @@ -17,8 +17,8 @@ public: QStringList candidates; }; -QskPinyinCompositionModel::QskPinyinCompositionModel( QskInputContext* context ): - Inherited( Attributes(), context ), +QskPinyinCompositionModel::QskPinyinCompositionModel( QObject* parent ): + Inherited( Attributes(), parent ), m_data( new PrivateData ) { #if 1 diff --git a/inputcontext/QskPinyinCompositionModel.h b/inputcontext/QskPinyinCompositionModel.h index 5cad5b80..487f27a6 100644 --- a/inputcontext/QskPinyinCompositionModel.h +++ b/inputcontext/QskPinyinCompositionModel.h @@ -14,7 +14,7 @@ class QskPinyinCompositionModel : public QskInputCompositionModel using Inherited = QskInputCompositionModel; public: - QskPinyinCompositionModel( QskInputContext* ); + QskPinyinCompositionModel( QObject* ); virtual ~QskPinyinCompositionModel() override; virtual int candidateCount() const override; diff --git a/src/inputpanel/QskInputPanel.cpp b/src/inputpanel/QskInputPanel.cpp index 1d4a39f8..c167c576 100644 --- a/src/inputpanel/QskInputPanel.cpp +++ b/src/inputpanel/QskInputPanel.cpp @@ -125,7 +125,7 @@ public: QskLinearBox* layout; QskTextLabel* prompt; - TextInput* textInput; + TextInput* inputProxy; QskInputSuggestionBar* suggestionBar; QskVirtualKeyboard* keyboard; @@ -142,8 +142,8 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ): m_data->prompt = new QskTextLabel(); m_data->prompt->setVisible( false ); - m_data->textInput = new TextInput(); - m_data->textInput->setVisible( m_data->hasInputProxy ); + m_data->inputProxy = new TextInput(); + m_data->inputProxy->setVisible( m_data->hasInputProxy ); m_data->suggestionBar = new QskInputSuggestionBar(); m_data->suggestionBar->setVisible( false ); @@ -153,7 +153,7 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ): auto layout = new QskLinearBox( Qt::Vertical, this ); layout->addItem( m_data->prompt, Qt::AlignLeft | Qt::AlignHCenter ); - layout->addItem( m_data->textInput, Qt::AlignLeft | Qt::AlignHCenter ); + layout->addItem( m_data->inputProxy, Qt::AlignLeft | Qt::AlignHCenter ); layout->addStretch( 10 ); layout->addItem( m_data->suggestionBar ); layout->addItem( m_data->keyboard ); @@ -199,7 +199,7 @@ qreal QskInputPanel::heightForWidth( qreal width ) const qreal height = m_data->keyboard->heightForWidth( width ); const QskControl* controls[] = - { m_data->prompt, m_data->textInput, m_data->suggestionBar }; + { m_data->prompt, m_data->inputProxy, m_data->suggestionBar }; for ( auto control : controls ) { @@ -228,7 +228,7 @@ qreal QskInputPanel::widthForHeight( qreal height ) const height -= padding.top() + padding.bottom(); const QskControl* controls[] = - { m_data->prompt, m_data->textInput, m_data->suggestionBar }; + { m_data->prompt, m_data->inputProxy, m_data->suggestionBar }; for ( auto control : controls ) { @@ -278,7 +278,7 @@ void QskInputPanel::setInputProxy( bool on ) return; m_data->hasInputProxy = on; - m_data->textInput->setVisible( on ); + m_data->inputProxy->setVisible( on ); auto prompt = m_data->prompt; @@ -288,6 +288,56 @@ void QskInputPanel::setInputProxy( bool on ) prompt->setVisible( false ); } +void QskInputPanel::updateInputProxy( const QQuickItem* inputItem ) +{ + if ( inputItem == nullptr ) + return; + + QInputMethodQueryEvent event( Qt::ImQueryAll ); + QCoreApplication::sendEvent( const_cast< QQuickItem* >( inputItem ), &event ); + + const auto proxy = m_data->inputProxy; + + if ( event.queries() & Qt::ImHints ) + { + const auto hints = static_cast< Qt::InputMethodHints >( + event.value( Qt::ImHints ).toInt() ); + + const auto echoMode = ( hints & Qt::ImhHiddenText ) + ? QskTextInput::PasswordEchoOnEdit : QskTextInput::Normal; + + proxy->setEchoMode( echoMode ); + } + + if ( event.queries() & Qt::ImSurroundingText ) + { + const auto text = event.value( Qt::ImSurroundingText ).toString(); + proxy->setText( text ); + } + + if ( event.queries() & Qt::ImCursorPosition ) + { + const auto pos = event.value( Qt::ImCursorPosition ).toInt(); + proxy->setCursorPosition( pos ); + } + +#if 0 + if ( event.queries() & Qt::ImCurrentSelection ) + { + const auto text = event.value( Qt::ImCursorPosition ).toString(); + if ( !text.isEmpty() ) + { + } + } +#endif + + if ( event.queries() & Qt::ImMaximumTextLength ) + { + const auto length = event.value( Qt::ImMaximumTextLength ).toInt(); + proxy->setMaxLength( length ); + } +} + bool QskInputPanel::isCandidatesEnabled() const { return m_data->suggestionBar->isVisible(); diff --git a/src/inputpanel/QskInputPanel.h b/src/inputpanel/QskInputPanel.h index 125ac915..1c9a4b50 100644 --- a/src/inputpanel/QskInputPanel.h +++ b/src/inputpanel/QskInputPanel.h @@ -52,6 +52,8 @@ public: virtual QskAspect::Subcontrol effectiveSubcontrol( QskAspect::Subcontrol ) const override; + void updateInputProxy( const QQuickItem* ); + Q_SIGNALS: void inputProxyChanged( bool ); void inputPromptChanged( const QString& );