diff --git a/playground/inputpanel/main.cpp b/playground/inputpanel/main.cpp index e05560c0..49e9b635 100644 --- a/playground/inputpanel/main.cpp +++ b/playground/inputpanel/main.cpp @@ -265,11 +265,7 @@ int main( int argc, char* argv[] ) #endif #if 0 - /* - If no input panel has been assigned QskInputContext creates - default panel if none has been assigned - */ - QskInputContext::setInputPanel( new QskInputPanel() ); + QskInputContext::setInputManager( ... ); #endif auto box = new QskLinearBox( Qt::Horizontal ); diff --git a/src/controls/QskTextInput.cpp b/src/controls/QskTextInput.cpp index d4f69503..504c8aac 100644 --- a/src/controls/QskTextInput.cpp +++ b/src/controls/QskTextInput.cpp @@ -790,4 +790,105 @@ void QskTextInput::setInputMethodHints(Qt::InputMethodHints hints ) } } +void QskTextInput::setupFrom( const QQuickItem* item ) +{ + if ( item == nullptr ) + return; + + // finding attributes from the input hints of item + + int maxCharacters = 32767; + QskTextInput::EchoMode echoMode = QskTextInput::Normal; + + Qt::InputMethodQueries queries = Qt::ImQueryAll; + queries &= ~Qt::ImEnabled; + + QInputMethodQueryEvent event( queries ); + QCoreApplication::sendEvent( const_cast< QQuickItem* >( item ), &event ); + + if ( event.queries() & Qt::ImHints ) + { + const auto hints = static_cast< Qt::InputMethodHints >( + event.value( Qt::ImHints ).toInt() ); + + if ( hints & Qt::ImhHiddenText ) + echoMode = QskTextInput::NoEcho; + } + + if ( event.queries() & Qt::ImMaximumTextLength ) + { + // needs to be handled before Qt::ImCursorPosition ! + + const auto max = event.value( Qt::ImMaximumTextLength ).toInt(); + maxCharacters = qBound( 0, max, maxCharacters ); + } + + setMaxLength( maxCharacters ); + + if ( event.queries() & Qt::ImSurroundingText ) + { + const auto text = event.value( Qt::ImSurroundingText ).toString(); + setText( text ); + } + + if ( event.queries() & Qt::ImCursorPosition ) + { + const auto pos = event.value( Qt::ImCursorPosition ).toInt(); + setCursorPosition( pos ); + } + + if ( event.queries() & Qt::ImCurrentSelection ) + { +#if 0 + const auto text = event.value( Qt::ImCurrentSelection ).toString(); + if ( !text.isEmpty() ) + { + } +#endif + } + + int passwordMaskDelay = -1; + QString passwordCharacter; + + if ( echoMode == QskTextInput::NoEcho ) + { + /* + Qt::ImhHiddenText does not provide information + to decide between NoEcho/Password, or provides + more details about how to deal with hidden inputs. + So we try to find out more from trying some properties. + */ + + QVariant value; + + value = item->property( "passwordMaskDelay" ); + if ( value.canConvert< int >() ) + passwordMaskDelay = value.toInt(); + + value = item->property( "passwordCharacter" ); + if ( value.canConvert< QString >() ) + passwordCharacter = value.toString(); + + value = item->property( "echoMode" ); + if ( value.canConvert< int >() ) + { + const auto mode = value.toInt(); + if ( mode == QskTextInput::Password ) + echoMode = QskTextInput::Password; + } + } + + if ( passwordMaskDelay >= 0 ) + setPasswordMaskDelay( passwordMaskDelay ); + else + resetPasswordMaskDelay(); + + if ( !passwordCharacter.isEmpty() ) + setPasswordCharacter( passwordCharacter ); + else + resetPasswordCharacter(); + + setEchoMode( echoMode ); +} + #include "moc_QskTextInput.cpp" diff --git a/src/controls/QskTextInput.h b/src/controls/QskTextInput.h index 76a474a5..994b987b 100644 --- a/src/controls/QskTextInput.h +++ b/src/controls/QskTextInput.h @@ -31,6 +31,9 @@ class QSK_EXPORT QskTextInput : public QskControl Q_PROPERTY( bool editing READ isEditing WRITE setEditing NOTIFY editingChanged ) + Q_PROPERTY( EchoMode echoMode READ echoMode + WRITE setEchoMode NOTIFY echoModeChanged ) + Q_PROPERTY( QString passwordCharacter READ passwordCharacter WRITE setPasswordCharacter RESET resetPasswordCharacter NOTIFY passwordCharacterChanged ) @@ -75,6 +78,8 @@ public: virtual ~QskTextInput(); + void setupFrom( const QQuickItem* ); + QString text() const; void setDescription( const QString& ); diff --git a/src/inputpanel/QskInputManager.cpp b/src/inputpanel/QskInputManager.cpp index 5b5241eb..96665e9c 100644 --- a/src/inputpanel/QskInputManager.cpp +++ b/src/inputpanel/QskInputManager.cpp @@ -11,6 +11,12 @@ #include #include +static inline QQuickItem* qskReceiverItem( const QskInputManager* manager ) +{ + auto item = manager->inputProxy(); + return item ? item : manager->inputItem(); +} + static inline void qskSendReplaceText( QQuickItem* receiver, const QString& text ) { if ( receiver == nullptr ) @@ -74,6 +80,7 @@ public: QPointer< QskControl > panel; QLocale predictorLocale; + Qt::InputMethodHints inputHints = 0; }; QskInputManager::QskInputManager( QObject* parent ): @@ -98,14 +105,18 @@ void QskInputManager::attachInputItem( QQuickItem* item ) const auto locale = context->locale(); updateEngine( locale ); + m_data->engine->reset(); - panel->setEngine( m_data->engine ); panel->setLocale( locale ); panel->attachInputItem( item ); + + Qt::InputMethodQueries queries = Qt::ImQueryAll; + queries &= ~Qt::ImEnabled; + + processInputMethodQueries( queries ); } else { - panel->setEngine( nullptr ); panel->attachInputItem( nullptr ); } } @@ -113,8 +124,21 @@ void QskInputManager::attachInputItem( QQuickItem* item ) void QskInputManager::processInputMethodQueries( Qt::InputMethodQueries queries ) { - if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) ) - panel->processInputMethodQueries( queries ); + if ( queries & Qt::ImHints ) + { + m_data->inputHints = 0; + + if ( auto item = inputItem() ) + { + QInputMethodQueryEvent event( Qt::ImHints ); + QCoreApplication::sendEvent( item, &event ); + + m_data->inputHints = static_cast< Qt::InputMethodHints >( + event.value( Qt::ImHints ).toInt() ); + } + + updatePanel(); + } } QskControl* QskInputManager::panel( bool doCreate ) @@ -134,7 +158,7 @@ Qt::Alignment QskInputManager::panelAlignment() const { if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) ) { - if ( panel->hasInputProxy() ) + if ( panel->panelHints() & QskInputPanel::InputProxy ) { /* When the panel has an input proxy we don't need to see @@ -152,14 +176,11 @@ QskControl* QskInputManager::createPanel() { auto panel = new QskInputPanel(); - connect( panel, &QskInputPanel::done, - this, &QskInputManager::applyInput, Qt::UniqueConnection ); + connect( panel, &QskInputPanel::keySelected, + this, &QskInputManager::commitKey, Qt::UniqueConnection ); - connect( panel, &QskInputPanel::textEntered, - this, &QskInputManager::applyText, Qt::UniqueConnection ); - - connect( panel, &QskInputPanel::keyEntered, - this, &QskInputManager::applyKey, Qt::UniqueConnection ); + connect( panel, &QskInputPanel::predictiveTextSelected, + this, &QskInputManager::commitPredictiveText, Qt::UniqueConnection ); return panel; } @@ -171,7 +192,7 @@ QskInputEngine* QskInputManager::createEngine() void QskInputManager::updateEngine( const QLocale& locale ) { - auto context = QskInputContext::instance(); + bool updatePredictor; if ( m_data->engine == nullptr) { @@ -179,18 +200,24 @@ void QskInputManager::updateEngine( const QLocale& locale ) if ( engine->parent() == nullptr ) engine->setParent( this ); - m_data->predictorLocale = locale; - engine->setPredictor( context->textPredictor( locale ) ); + connect( engine, &QskInputEngine::predictionChanged, + this, &QskInputManager::updatePrediction ); m_data->engine = engine; + updatePredictor = true; } else { - if ( m_data->predictorLocale != locale ) - { - m_data->predictorLocale = locale; - m_data->engine->setPredictor( context->textPredictor( locale ) ); - } + updatePredictor = ( locale != m_data->predictorLocale ); + } + + if ( updatePredictor ) + { + auto context = QskInputContext::instance(); + + m_data->predictorLocale = locale; + m_data->engine->setPredictor( context->textPredictor( locale ) ); + updatePanel(); } } @@ -206,6 +233,18 @@ void QskInputManager::updatePredictor() } } +void QskInputManager::updatePanel() +{ + if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) ) + { + const auto mask = Qt::ImhNoPredictiveText + | Qt::ImhExclusiveInputMask | Qt::ImhHiddenText; + + panel->setPanelHint( QskInputPanel::Prediction, + m_data->engine->predictor() && !( m_data->inputHints & mask ) ); + } +} + QQuickItem* QskInputManager::inputItem() const { if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) ) @@ -218,7 +257,7 @@ QQuickItem* QskInputManager::inputProxy() const { if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) ) { - if ( panel->hasInputProxy() ) + if ( panel->panelHints() & QskInputPanel::InputProxy ) return panel->inputProxy(); } @@ -246,22 +285,85 @@ void QskInputManager::applyInput( bool success ) void QskInputManager::applyText( const QString& text, bool isFinal ) { - auto item = inputProxy(); - if ( item == nullptr ) - item = inputItem(); - - qskSendText( item, text, isFinal ); + qskSendText( qskReceiverItem( this ), text, isFinal ); } void QskInputManager::applyKey( int key ) { // control keys like left/right + qskSendKey( qskReceiverItem( this ), key ); +} - auto item = inputProxy(); - if ( item == nullptr ) - item = inputItem(); +void QskInputManager::commitPredictiveText( int index ) +{ + if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) ) + { + panel->setPrediction( QStringList() ); - qskSendKey( item, key ); + const QString text = m_data->engine->predictiveText( index ); + + m_data->engine->reset(); + applyText( text, true ); + } +} + +void QskInputManager::updatePrediction() +{ + if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) ) + panel->setPrediction( m_data->engine->prediction() ); +} + +void QskInputManager::commitKey( int key ) +{ + auto panel = qobject_cast< QskInputPanel* >( m_data->panel ); + if ( panel == nullptr ) + return; + + int spaceLeft = -1; + + if ( !( m_data->inputHints & Qt::ImhMultiLine ) ) + { + QInputMethodQueryEvent event1( Qt::ImMaximumTextLength ); + QCoreApplication::sendEvent( panel->attachedInputItem(), &event1 ); + + const int maxChars = event1.value( Qt::ImMaximumTextLength ).toInt(); + if ( maxChars >= 0 ) + { + QInputMethodQueryEvent event2( Qt::ImSurroundingText ); + QCoreApplication::sendEvent( qskReceiverItem( this ), &event2 ); + + const auto text = event2.value( Qt::ImSurroundingText ).toString(); + spaceLeft = maxChars - text.length(); + } + } + + const auto result = m_data->engine->processKey( + key, m_data->inputHints, spaceLeft ); + + if ( result.key ) + { + switch( result.key ) + { + case Qt::Key_Return: + { + applyInput( true ); + break; + } + case Qt::Key_Escape: + { + applyInput( false ); + break; + } + default: + { + applyKey( result.key ); + } + } + } + else if ( !result.text.isEmpty() ) + { + applyText( result.text, result.isFinal ); + } } #include "moc_QskInputManager.cpp" diff --git a/src/inputpanel/QskInputManager.h b/src/inputpanel/QskInputManager.h index f818eb0d..4c0b33bd 100644 --- a/src/inputpanel/QskInputManager.h +++ b/src/inputpanel/QskInputManager.h @@ -46,6 +46,12 @@ private: void applyText( const QString&, bool isFinal ); void applyKey( int keyCode ); + void commitKey( int keyCode ); + void commitPredictiveText( int index ); + + void updatePrediction(); + void updatePanel(); + class PrivateData; std::unique_ptr< PrivateData > m_data; }; diff --git a/src/inputpanel/QskInputPanel.cpp b/src/inputpanel/QskInputPanel.cpp index 1b6344f2..fc93c46d 100644 --- a/src/inputpanel/QskInputPanel.cpp +++ b/src/inputpanel/QskInputPanel.cpp @@ -4,7 +4,6 @@ *****************************************************************************/ #include "QskInputPanel.h" -#include "QskInputEngine.h" #include "QskVirtualKeyboard.h" #include "QskInputPredictionBar.h" #include "QskTextInput.h" @@ -28,39 +27,6 @@ namespace setFocusPolicy( Qt::NoFocus ); } - void setup( QQuickItem* inputItem ) - { - int passwordMaskDelay = -1; - QString passwordCharacter; - - if ( auto textInput = qobject_cast< QskTextInput* >( inputItem ) ) - { - passwordMaskDelay = textInput->passwordMaskDelay(); - passwordCharacter = textInput->passwordCharacter(); - - if ( echoMode() == QskTextInput::NoEcho ) - { - /* - Qt::ImhHiddenText does not provide information - to decide between NoEcho/Password - */ - auto mode = textInput->echoMode(); - if ( mode == QskTextInput::Password ) - setEchoMode( mode ); - } - } - - if ( passwordMaskDelay >= 0 ) - setPasswordMaskDelay( passwordMaskDelay ); - else - resetPasswordMaskDelay(); - - if ( !passwordCharacter.isEmpty() ) - setPasswordCharacter( passwordCharacter ); - else - resetPasswordCharacter(); - } - protected: virtual void focusInEvent( QFocusEvent* ) override final { @@ -77,20 +43,6 @@ QSK_SUBCONTROL( QskInputPanel, Panel ) class QskInputPanel::PrivateData { public: - PrivateData(): - inputHints( 0 ), - maxChars( -1 ), - hasPrediction( true ), - hasInputProxy( true ) - { - } - - QQuickItem* receiverItem() - { - return hasInputProxy ? inputProxy : inputItem; - } - - QPointer< QskInputEngine > engine; QPointer< QQuickItem > inputItem; QskLinearBox* layout; @@ -99,11 +51,9 @@ public: QskInputPredictionBar* predictionBar; QskVirtualKeyboard* keyboard; - Qt::InputMethodHints inputHints; - int maxChars; + int maxChars = -1; - bool hasPrediction : 1; - bool hasInputProxy : 1; + QskInputPanel::PanelHints panelHints = QskInputPanel::InputProxy; }; QskInputPanel::QskInputPanel( QQuickItem* parent ): @@ -117,10 +67,12 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ): m_data->prompt->setVisible( false ); m_data->inputProxy = new TextInputProxy(); - m_data->inputProxy->setVisible( m_data->hasInputProxy ); + m_data->inputProxy->setVisible( + m_data->panelHints & QskInputPanel::InputProxy ); m_data->predictionBar = new QskInputPredictionBar(); - m_data->predictionBar->setVisible( false ); + m_data->predictionBar->setVisible( + m_data->panelHints & QskInputPanel::Prediction ); m_data->keyboard = new QskVirtualKeyboard(); @@ -135,34 +87,45 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ): m_data->layout = layout; connect( m_data->predictionBar, &QskInputPredictionBar::predictiveTextSelected, - this, &QskInputPanel::commitPredictiveText ); + this, &QskInputPanel::predictiveTextSelected ); connect( m_data->keyboard, &QskVirtualKeyboard::keySelected, - this, &QskInputPanel::commitKey ); + this, &QskInputPanel::keySelected ); } QskInputPanel::~QskInputPanel() { } -void QskInputPanel::setEngine( QskInputEngine* engine ) +void QskInputPanel::setPanelHint( PanelHint hint, bool on ) { - if ( engine == m_data->engine ) + if ( on ) + setPanelHints( m_data->panelHints | hint ); + else + setPanelHints( m_data->panelHints & ~hint ); +} + +void QskInputPanel::setPanelHints( PanelHints hints ) +{ + if ( hints == m_data->panelHints ) return; - if ( m_data->engine ) - m_data->engine->disconnect( this ); + m_data->panelHints = hints; - m_data->engine = engine; + m_data->inputProxy->setVisible( hints & QskInputPanel::InputProxy ); + m_data->predictionBar->setVisible( hints & QskInputPanel::Prediction ); - if ( engine ) - { - connect( engine, &QskInputEngine::predictionChanged, - this, &QskInputPanel::updatePrediction ); - } + const bool showPrompt = ( hints & QskInputPanel::InputProxy ) + && !m_data->prompt->text().isEmpty(); - m_data->predictionBar->setVisible( - m_data->hasPrediction && engine && engine->predictor() ); + m_data->prompt->setVisible( showPrompt ); + + Q_EMIT panelHintsChanged(); +} + +QskInputPanel::PanelHints QskInputPanel::panelHints() const +{ + return m_data->panelHints; } void QskInputPanel::attachInputItem( QQuickItem* item ) @@ -172,29 +135,19 @@ void QskInputPanel::attachInputItem( QQuickItem* item ) m_data->inputItem = item; - if ( m_data->engine ) - m_data->engine->reset(); - if ( item ) { - Qt::InputMethodQueries queries = Qt::ImQueryAll; - queries &= ~Qt::ImEnabled; - - processInputMethodQueries( queries ); - - if ( m_data->hasInputProxy ) + if ( m_data->panelHints & QskInputPanel::InputProxy ) { + m_data->inputProxy->setupFrom( item ); m_data->inputProxy->setEditing( true ); - // hiding the cursor in the real input item + // hiding the cursor in item const QInputMethodEvent::Attribute attribute( QInputMethodEvent::Cursor, 0, 0, QVariant() ); QInputMethodEvent event( QString(), { attribute } ); QCoreApplication::sendEvent( item, &event ); - - // not all information is available from the input method query - m_data->inputProxy->setup( item ); } } } @@ -209,17 +162,6 @@ QQuickItem* QskInputPanel::inputProxy() const return m_data->inputProxy; } -void QskInputPanel::updatePrediction() -{ - m_data->predictionBar->setPrediction( - m_data->engine->prediction() ); -} - -QskInputEngine* QskInputPanel::engine() -{ - return m_data->engine; -} - QskAspect::Subcontrol QskInputPanel::effectiveSubcontrol( QskAspect::Subcontrol subControl ) const { @@ -242,226 +184,16 @@ void QskInputPanel::setInputPrompt( const QString& text ) { prompt->setText( text ); - if ( m_data->hasInputProxy ) + if ( m_data->panelHints & QskInputPanel::InputProxy ) prompt->setVisible( !text.isEmpty() ); Q_EMIT inputPromptChanged( text ); } } -bool QskInputPanel::hasInputProxy() const +void QskInputPanel::setPrediction( const QStringList& prediction ) { - return m_data->hasInputProxy; -} - -void QskInputPanel::setInputProxy( bool on ) -{ - if ( m_data->hasInputProxy == on ) - return; - - m_data->hasInputProxy = on; - m_data->inputProxy->setVisible( on ); - - auto prompt = m_data->prompt; - - if ( on ) - prompt->setVisible( !prompt->text().isEmpty() ); - else - prompt->setVisible( false ); -} - -void QskInputPanel::commitPredictiveText( int index ) -{ - m_data->predictionBar->setPrediction( QStringList() ); - - if ( m_data->engine ) - { - const QString text = m_data->engine->predictiveText( index ); - - m_data->engine->reset(); - Q_EMIT textEntered( text, true ); - } -} - -void QskInputPanel::commitKey( int key ) -{ - if ( m_data->engine == nullptr || m_data->inputItem == nullptr ) - return; - - int spaceLeft = -1; - - if ( !( m_data->inputHints & Qt::ImhMultiLine ) ) - { - auto receiver = m_data->receiverItem(); - - if ( m_data->maxChars >= 0 ) - { - QInputMethodQueryEvent event( Qt::ImSurroundingText ); - QCoreApplication::sendEvent( receiver, &event ); - - const auto text = event.value( Qt::ImSurroundingText ).toString(); - spaceLeft = m_data->maxChars - text.length(); - } - } - - processKey( key, m_data->inputHints, spaceLeft ); -} - -void QskInputPanel::processKey( int key, - Qt::InputMethodHints inputHints, int spaceLeft ) -{ - const auto result = m_data->engine->processKey( key, inputHints, spaceLeft ); - - auto inputItem = m_data->inputItem; - - if ( result.key ) - { - switch( result.key ) - { - case Qt::Key_Return: - { - Q_EMIT done( true ); - break; - } - case Qt::Key_Escape: - { - Q_EMIT done( false ); - break; - } - default: - { - Q_EMIT keyEntered( result.key ); - } - } - } - else if ( !result.text.isEmpty() ) - { - Q_EMIT textEntered( result.text, result.isFinal ); - } -} - -void QskInputPanel::processInputMethodQueries( Qt::InputMethodQueries queries ) -{ - if ( m_data->inputItem == nullptr ) - return; - - QInputMethodQueryEvent event( queries ); - QCoreApplication::sendEvent( m_data->inputItem, &event ); - - if ( event.queries() & Qt::ImHints ) - { - bool hasPrediction = true; - QskTextInput::EchoMode echoMode = QskTextInput::Normal; - - const auto hints = static_cast< Qt::InputMethodHints >( - event.value( Qt::ImHints ).toInt() ); - - if ( hints & Qt::ImhHiddenText ) - { - echoMode = QskTextInput::NoEcho; - } - - /* - - Qt::ImhSensitiveData - - Qt::ImhNoAutoUppercase - - Qt::ImhMultiLine - - // we should start in a specific mode - - - Qt::ImhPreferNumbers - - Qt::ImhPreferUppercase - - Qt::ImhPreferLowercase - - Qt::ImhPreferLatin - - // we should lock all other modes - - - Qt::ImhFormattedNumbersOnly - - Qt::ImhUppercaseOnly - - Qt::ImhDialableCharactersOnly - - Qt::ImhEmailCharactersOnly - - Qt::ImhUrlCharactersOnly - - Qt::ImhLatinOnly - - // we should have specific input panels - - - Qt::ImhDate - - Qt::ImhTime - - Qt::ImhDigitsOnly - - Qt::ImhFormattedNumbersOnly - */ - - m_data->hasPrediction = - !( hints & ( Qt::ImhNoPredictiveText | Qt::ImhExclusiveInputMask ) ); - - m_data->predictionBar->setVisible( - hasPrediction && m_data->engine && m_data->engine->predictor() ); - - m_data->inputProxy->setEchoMode( echoMode ); - - m_data->inputHints = hints; - } - - if ( event.queries() & Qt::ImPreferredLanguage ) - { - // already handled by the input context - } - - if ( event.queries() & Qt::ImMaximumTextLength ) - { - // needs to be handled before Qt::ImCursorPosition ! - - m_data->maxChars = event.value( Qt::ImMaximumTextLength ).toInt(); -#if 1 - if ( m_data->maxChars >= 32767 ) - m_data->maxChars = -1; -#endif - - if ( m_data->hasInputProxy ) - m_data->inputProxy->setMaxLength( m_data->maxChars ); - } - - - if ( event.queries() & Qt::ImSurroundingText ) - { - if ( m_data->hasInputProxy ) - { - const auto text = event.value( Qt::ImSurroundingText ).toString(); - m_data->inputProxy->setText( text ); - } - } - - if ( event.queries() & Qt::ImCursorPosition ) - { - if ( m_data->hasInputProxy ) - { - const auto pos = event.value( Qt::ImCursorPosition ).toInt(); - m_data->inputProxy->setCursorPosition( pos ); - } - } - - if ( event.queries() & Qt::ImCurrentSelection ) - { -#if 0 - const auto text = event.value( Qt::ImCurrentSelection ).toString(); - if ( !text.isEmpty() ) - { - } -#endif - } - /* - Qt::ImMicroFocus - Qt::ImCursorRectangle - Qt::ImFont - Qt::ImAnchorPosition - - Qt::ImAbsolutePosition - Qt::ImTextBeforeCursor - Qt::ImTextAfterCursor - Qt::ImPlatformData // hard to say... - Qt::ImEnterKeyType - Qt::ImAnchorRectangle - Qt::ImInputItemClipRectangle - */ + m_data->predictionBar->setPrediction( prediction ); } void QskInputPanel::keyPressEvent( QKeyEvent* event ) @@ -473,7 +205,7 @@ void QskInputPanel::keyPressEvent( QKeyEvent* event ) case Qt::Key_Return: case Qt::Key_Escape: { - commitKey( event->key() ); + Q_EMIT keySelected( event->key() ); break; } @@ -492,17 +224,13 @@ void QskInputPanel::keyPressEvent( QKeyEvent* event ) default: { const auto text = event->text(); + if ( !text.isEmpty() ) - commitKey( text[0].unicode() ); + Q_EMIT keySelected( text[0].unicode() ); else - commitKey( event->key() ); + Q_EMIT keySelected( event->key() ); } } } -void QskInputPanel::keyReleaseEvent( QKeyEvent* event ) -{ - return Inherited::keyReleaseEvent( event ); -} - #include "moc_QskInputPanel.cpp" diff --git a/src/inputpanel/QskInputPanel.h b/src/inputpanel/QskInputPanel.h index 1df81adf..17e5f0a3 100644 --- a/src/inputpanel/QskInputPanel.h +++ b/src/inputpanel/QskInputPanel.h @@ -20,8 +20,8 @@ class QSK_EXPORT QskInputPanel : public QskBox using Inherited = QskBox; - Q_PROPERTY( bool inputProxy READ hasInputProxy - WRITE setInputProxy NOTIFY inputProxyChanged ) + Q_PROPERTY( PanelHints panelHints READ panelHints + WRITE setPanelHints NOTIFY panelHintsChanged ) Q_PROPERTY( QString inputPrompt READ inputPrompt WRITE setInputPrompt NOTIFY inputPromptChanged ) @@ -29,16 +29,26 @@ class QSK_EXPORT QskInputPanel : public QskBox public: QSK_SUBCONTROLS( Panel ) + enum PanelHint + { + InputProxy = 1 << 0, + Prediction = 1 << 1 + }; + + Q_ENUM( PanelHint ) + Q_DECLARE_FLAGS( PanelHints, PanelHint ) + QskInputPanel( QQuickItem* parent = nullptr ); virtual ~QskInputPanel() override; void attachInputItem( QQuickItem* ); QQuickItem* attachedInputItem() const; - void setEngine( QskInputEngine* ); - QskInputEngine* engine(); + void setPanelHint( PanelHint, bool on ); + + void setPanelHints( PanelHints ); + PanelHints panelHints() const; - bool hasInputProxy() const; QQuickItem* inputProxy() const; QString inputPrompt() const; @@ -46,35 +56,26 @@ public: virtual QskAspect::Subcontrol effectiveSubcontrol( QskAspect::Subcontrol ) const override; - virtual void processInputMethodQueries( Qt::InputMethodQueries ); - Q_SIGNALS: - void inputProxyChanged( bool ); + void panelHintsChanged(); void inputPromptChanged( const QString& ); - void textEntered( const QString&, bool isFinal ); - void keyEntered( int keyCode ); - void done( bool success ); + void keySelected( int keyCode ); + void predictiveTextSelected( int ); public Q_SLOTS: void setInputPrompt( const QString& ); - void setInputProxy( bool ); + void setPrediction( const QStringList& ); protected: virtual void keyPressEvent( QKeyEvent* ) override; - virtual void keyReleaseEvent( QKeyEvent* ) override; - - virtual void processKey( int key, - Qt::InputMethodHints, int spaceLeft ); - - virtual void updatePrediction(); private: - void commitKey( int key ); - void commitPredictiveText( int ); - class PrivateData; std::unique_ptr< PrivateData > m_data; }; +Q_DECLARE_OPERATORS_FOR_FLAGS( QskInputPanel::PanelHints ) +Q_DECLARE_METATYPE( QskInputPanel::PanelHints ) + #endif