improving text input classes

This commit is contained in:
Uwe Rathmann 2018-04-03 20:15:20 +02:00
parent 26417ed49a
commit 777a134645
7 changed files with 243 additions and 81 deletions

View File

@ -29,6 +29,8 @@ public:
QskInputContext::QskInputContext() :
m_data( new PrivateData() )
{
setObjectName( "InputContext" );
m_data->compositionModel = new QskInputCompositionModel();
connect( m_data->compositionModel, &QskInputCompositionModel::candidatesChanged,
@ -50,6 +52,7 @@ QskInputContext::~QskInputContext()
delete m_data->inputPanel;
qDeleteAll( m_data->compositionModels );
delete m_data->compositionModel;
}
bool QskInputContext::isValid() const
@ -137,6 +140,11 @@ void QskInputContext::update( Qt::InputMethodQueries queries )
// Qt::ImPlatformData // hard to say...
}
QQuickItem* QskInputContext::inputItem()
{
return m_data->inputItem;
}
QRectF QskInputContext::keyboardRect() const
{
if ( m_data->inputPanel
@ -188,7 +196,7 @@ void QskInputContext::showInputPanel()
void QskInputContext::hideInputPanel()
{
if ( !m_data->inputPanel )
if ( m_data->inputPanel == nullptr )
return;
auto window = m_data->inputPanel->window();
@ -201,8 +209,9 @@ void QskInputContext::hideInputPanel()
bool QskInputContext::isInputPanelVisible() const
{
auto panel = m_data->inputPanel;
return panel && panel->isVisible()
&& panel->window() && panel->window()->isVisible();
&& panel->window() && panel->window()->isVisible();
}
QLocale QskInputContext::locale() const

View File

@ -11,6 +11,7 @@
class QskVirtualKeyboard;
class QskInputCompositionModel;
class QQuickItem;
class QskInputContext : public QPlatformInputContext
{
@ -40,6 +41,8 @@ public:
void setCompositionModel( const QLocale&, QskInputCompositionModel* );
Q_INVOKABLE QQuickItem* inputItem();
private Q_SLOTS:
void handleCandidatesChanged();
void setInputPanel( QskVirtualKeyboard* );

View File

@ -427,7 +427,7 @@ const int* QskSkin::dialogButtonLayout( Qt::Orientation orientation ) const
//auto policy = QPlatformDialogHelper::UnknownLayout;
auto policy = QPlatformDialogHelper::WinLayout;
if ( const QPlatformTheme* theme = QGuiApplicationPrivate::platformTheme() )
if ( const auto theme = QGuiApplicationPrivate::platformTheme() )
{
const QVariant v = theme->themeHint( QPlatformTheme::DialogButtonBoxLayout );
policy = static_cast< QPlatformDialogHelper::ButtonLayout >( v.toInt() );

View File

@ -8,9 +8,64 @@
QSK_QT_PRIVATE_BEGIN
#include <private/qquicktextinput_p.h>
#include <private/qquicktextinput_p_p.h>
QSK_QT_PRIVATE_END
#include <QDebug>
static inline void qskUpdateInputMethod(
const QskTextInput*, Qt::InputMethodQueries queries )
{
auto inputMethod = QGuiApplication::inputMethod();
inputMethod->update( queries );
}
static inline void qskBindSignals( const QQuickTextInput* wrappedInput,
QskTextInput* input )
{
QObject::connect( wrappedInput, &QQuickTextInput::textChanged,
input, [ input ] { input->Q_EMIT textChanged( input->text() ); } );
QObject::connect( wrappedInput, &QQuickTextInput::textEdited,
input, [ input ] { input->Q_EMIT textEdited( input->text() ); } );
QObject::connect( wrappedInput, &QQuickTextInput::textChanged,
input, [ input ] { input->Q_EMIT textChanged( input->text() ); } );
QObject::connect( wrappedInput, &QQuickTextInput::selectedTextChanged,
input, [ input ] { input->Q_EMIT selectedTextChanged( input->selectedText() ); } );
QObject::connect( wrappedInput, &QQuickTextInput::validatorChanged,
input, &QskTextInput::validatorChanged );
QObject::connect( wrappedInput, &QQuickTextInput::inputMaskChanged,
input, &QskTextInput::inputMaskChanged );
QObject::connect( wrappedInput, &QQuickTextInput::readOnlyChanged,
input, &QskTextInput::readOnlyChanged );
QObject::connect( wrappedInput, &QQuickTextInput::overwriteModeChanged,
input, &QskTextInput::overwriteModeChanged );
QObject::connect( wrappedInput, &QQuickTextInput::maximumLengthChanged,
input, &QskTextInput::maximumLengthChanged );
QObject::connect( wrappedInput, &QQuickTextInput::echoModeChanged,
input, [ input ] { input->Q_EMIT echoModeChanged( input->echoMode() ); } );
QObject::connect( wrappedInput, &QQuickTextInput::autoScrollChanged,
input, &QskTextInput::autoScrollChanged );
QObject::connect( wrappedInput, &QQuickTextInput::selectByMouseChanged,
input, &QskTextInput::selectByMouseChanged );
QObject::connect( wrappedInput, &QQuickTextInput::persistentSelectionChanged,
input, &QskTextInput::persistentSelectionChanged );
QObject::connect( wrappedInput, &QQuickItem::implicitWidthChanged,
input, &QskControl::resetImplicitSize );
QObject::connect( wrappedInput, &QQuickItem::implicitHeightChanged,
input, &QskControl::resetImplicitSize );
}
namespace
{
@ -20,6 +75,8 @@ namespace
TextInput( QQuickItem* parent ) :
QQuickTextInput( parent )
{
setActiveFocusOnTab( false );
setFlag( ItemAcceptsInputMethod, false );
}
void setAlignment( Qt::Alignment alignment )
@ -28,10 +85,26 @@ namespace
setVAlign( ( VAlignment ) ( int( alignment ) & 0xf0 ) );
}
protected:
virtual void inputMethodEvent( QInputMethodEvent* event ) override
inline bool handleEvent( QEvent* event )
{
QQuickTextInput::inputMethodEvent( event );
switch( event->type() )
{
case QEvent::FocusIn:
case QEvent::FocusOut:
{
auto d = QQuickTextInputPrivate::get( this );
d->focusOnPress = true;
d->handleFocusEvent( static_cast< QFocusEvent* >( event ) );
d->focusOnPress = false;
return true;
}
default:
return QQuickTextInput::event( event );
}
}
};
}
@ -46,81 +119,70 @@ public:
};
QskTextInput::QskTextInput( QQuickItem* parent ):
QskTextInput( QString(), parent )
{
}
QskTextInput::QskTextInput( const QString& text, QQuickItem* parent ):
Inherited( parent ),
m_data( new PrivateData() )
{
auto input = new TextInput( this );
connect( input, &QQuickTextInput::textChanged,
this, [ this ] { Q_EMIT textChanged( this->text() ); } );
connect( input, &QQuickTextInput::textEdited,
this, [ this ] { Q_EMIT textEdited( this->text() ); } );
connect( input, &QQuickTextInput::textChanged,
this, [ this ] { Q_EMIT textChanged( this->text() ); } );
connect( input, &QQuickTextInput::selectedTextChanged,
this, [ this ] { Q_EMIT selectedTextChanged( selectedText() ); } );
connect( input, &QQuickTextInput::validatorChanged,
this, &QskTextInput::validatorChanged );
connect( input, &QQuickTextInput::inputMaskChanged,
this, &QskTextInput::inputMaskChanged );
connect( input, &QQuickTextInput::readOnlyChanged,
this, &QskTextInput::readOnlyChanged );
connect( input, &QQuickTextInput::overwriteModeChanged,
this, &QskTextInput::overwriteModeChanged );
connect( input, &QQuickTextInput::maximumLengthChanged,
this, &QskTextInput::maximumLengthChanged );
connect( input, &QQuickTextInput::echoModeChanged,
this, [ this ] { Q_EMIT echoModeChanged( echoMode() ); } );
connect( input, &QQuickTextInput::autoScrollChanged,
this, &QskTextInput::autoScrollChanged );
connect( input, &QQuickTextInput::selectByMouseChanged,
this, &QskTextInput::selectByMouseChanged );
connect( input, &QQuickTextInput::persistentSelectionChanged,
this, &QskTextInput::persistentSelectionChanged );
connect( input, &QQuickItem::implicitWidthChanged,
this, &QskControl::resetImplicitSize );
connect( input, &QQuickItem::implicitHeightChanged,
this, &QskControl::resetImplicitSize );
input->setAlignment( alignment() );
input->setFont( font() );
input->setText( text );
m_data->textInput = input;
setPolishOnResize( true );
setFocusPolicy( Qt::StrongFocus );
#if 1
input->setActiveFocusOnTab( true );
#endif
setAcceptedMouseButtons( Qt::LeftButton );
setFlag( QQuickItem::ItemAcceptsInputMethod );
m_data->textInput = new TextInput( this );
qskBindSignals( m_data->textInput, this );
setAcceptedMouseButtons( m_data->textInput->acceptedMouseButtons() );
m_data->textInput->setAcceptedMouseButtons( Qt::NoButton );
initSizePolicy( QskSizePolicy::Minimum, QskSizePolicy::Fixed );
}
QskTextInput::QskTextInput( const QString& text, QQuickItem* parent ):
QskTextInput( parent )
{
m_data->textInput->setText( text );
}
QskTextInput::~QskTextInput()
{
}
bool QskTextInput::event( QEvent* event )
{
if ( event->type() == QEvent::ShortcutOverride )
{
return m_data->textInput->handleEvent( event );
}
return Inherited::event( event );
}
void QskTextInput::keyPressEvent( QKeyEvent* event )
{
m_data->textInput->handleEvent( event );
}
void QskTextInput::keyReleaseEvent( QKeyEvent* event )
{
Inherited::keyReleaseEvent( event );
}
void QskTextInput::inputMethodEvent( QInputMethodEvent* event )
{
m_data->textInput->handleEvent( event );
}
void QskTextInput::focusInEvent( QFocusEvent* event )
{
m_data->textInput->handleEvent( event );
Inherited::focusInEvent( event );
}
void QskTextInput::focusOutEvent( QFocusEvent* event )
{
m_data->textInput->handleEvent( event );
Inherited::focusOutEvent( event );
}
QSizeF QskTextInput::contentsSizeHint() const
{
using namespace QskAspect;
@ -136,7 +198,12 @@ QSizeF QskTextInput::contentsSizeHint() const
void QskTextInput::updateLayout()
{
qskSetItemGeometry( m_data->textInput, subControlRect( Text ) );
auto input = m_data->textInput;
input->setAlignment( alignment() );
input->setFont( font() );
qskSetItemGeometry( input, subControlRect( Text ) );
}
QString QskTextInput::text() const
@ -162,9 +229,12 @@ void QskTextInput::setFontRole( int role )
if ( oldRole != role )
{
#if 1
m_data->textInput->setFont( font() );
#endif
polish();
resetImplicitSize();
qskUpdateInputMethod( this,
Qt::ImCursorRectangle | Qt::ImFont | Qt::ImAnchorRectangle );
Q_EMIT fontRoleChanged();
}
}
@ -188,6 +258,8 @@ void QskTextInput::setAlignment( Qt::Alignment alignment )
m_data->textInput->setAlignment( alignment );
polish();
Q_EMIT alignmentChanged();
}
}
@ -211,6 +283,9 @@ bool QskTextInput::isReadOnly() const
void QskTextInput::setReadOnly( bool on )
{
m_data->textInput->setReadOnly( on );
m_data->textInput->setFlag( QQuickItem::ItemAcceptsInputMethod, false );
qskUpdateInputMethod( this, Qt::ImEnabled );
}
bool QskTextInput::isCursorVisible() const
@ -288,6 +363,8 @@ void QskTextInput::setEchoMode( EchoMode mode )
{
m_data->textInput->setEchoMode(
static_cast< QQuickTextInput::EchoMode >( mode ) );
qskUpdateInputMethod( this, Qt::ImHints );
}
QString QskTextInput::displayText() const
@ -360,13 +437,36 @@ bool QskTextInput::hasAcceptableInput() const
QVariant QskTextInput::inputMethodQuery(
Qt::InputMethodQuery property) const
{
return m_data->textInput->inputMethodQuery( property );
return inputMethodQuery( property, QVariant() );
}
QVariant QskTextInput::inputMethodQuery(
Qt::InputMethodQuery query, QVariant argument) const
{
return m_data->textInput->inputMethodQuery( query, argument );
switch( query )
{
case Qt::ImEnabled:
{
return QVariant( (bool)( flags() & ItemAcceptsInputMethod ) );
}
case Qt::ImFont:
{
return font();
}
case Qt::ImCursorPosition:
{
QVariant v = m_data->textInput->inputMethodQuery( query, argument );
#if 1
if ( v.canConvert< QPointF >() )
v.setValue( v.toPointF() + m_data->textInput->position() );
#endif
return v;
}
default:
{
return m_data->textInput->inputMethodQuery( query, argument );
}
}
}
bool QskTextInput::canUndo() const
@ -391,7 +491,11 @@ Qt::InputMethodHints QskTextInput::inputMethodHints() const
void QskTextInput::setInputMethodHints(Qt::InputMethodHints hints )
{
m_data->textInput->setInputMethodHints( hints );
if ( m_data->textInput->inputMethodHints() != hints )
{
m_data->textInput->setInputMethodHints( hints );
qskUpdateInputMethod( this, Qt::ImHints );
}
}
#include "moc_QskTextInput.cpp"

View File

@ -153,6 +153,13 @@ Q_SIGNALS:
void inputMaskChanged( const QString& );
protected:
virtual bool event( QEvent* ) override;
virtual void keyPressEvent( QKeyEvent* ) override;
virtual void keyReleaseEvent( QKeyEvent* ) override;
virtual void inputMethodEvent( QInputMethodEvent* ) override;
virtual void focusInEvent( QFocusEvent* ) override;
virtual void focusOutEvent( QFocusEvent* ) override;
virtual void updateLayout() override;
private:

View File

@ -10,6 +10,13 @@
#include <QGuiApplication>
#include <QStyleHints>
QSK_QT_PRIVATE_BEGIN
#include <private/qguiapplication_p.h>
QSK_QT_PRIVATE_END
#include <qpa/qplatformintegration.h>
#include <qpa/qplatforminputcontext.h>
namespace
{
struct KeyTable
@ -137,10 +144,8 @@ QskVirtualKeyboardCandidateButton::QskVirtualKeyboardCandidateButton(
setFlag( QQuickItem::ItemAcceptsInputMethod );
setText( QStringLiteral( " " ) ); // ###
connect( this, &QskVirtualKeyboardButton::pressed, this, [ this ]()
{
m_inputPanel->handleCandidateKey( m_index, m_text );
} );
connect( this, &QskVirtualKeyboardButton::pressed,
this, [ this ]() { m_inputPanel->handleCandidateKey( m_index, m_text ); } );
}
void QskVirtualKeyboardCandidateButton::setIndexAndText(int index, const QString& text )
@ -150,7 +155,8 @@ void QskVirtualKeyboardCandidateButton::setIndexAndText(int index, const QString
setText( m_text );
}
QskAspect::Subcontrol QskVirtualKeyboardCandidateButton::effectiveSubcontrol( QskAspect::Subcontrol subControl ) const
QskAspect::Subcontrol QskVirtualKeyboardCandidateButton::effectiveSubcontrol(
QskAspect::Subcontrol subControl ) const
{
if( subControl == QskPushButton::Panel )
{
@ -317,6 +323,7 @@ QskVirtualKeyboard::QskVirtualKeyboard( QQuickItem* parent ):
const int keyIndex = m_data->keyTable[ m_data->mode ].indexOf( &keyData );
auto button = new QskVirtualKeyboardButton( keyIndex, this, rowBox );
button->installEventFilter( this );
rowBox->setRetainSizeWhenHidden( button, true );
m_data->keyButtons.append( button );
@ -912,4 +919,35 @@ void QskVirtualKeyboard::setMode( QskVirtualKeyboard::Mode mode )
Q_EMIT modeChanged( m_data->mode );
}
bool QskVirtualKeyboard::eventFilter( QObject* object, QEvent* event )
{
if ( event->type() == QEvent::InputMethodQuery )
{
/*
Qt/Quick expects that the item associated with the virtual keyboard
always has the focus. But you also find systems, where you have to
navigate and select inside the virtual keyboard.
So we have to fix the receiver.
*/
const auto platformIntegration = QGuiApplicationPrivate::platformIntegration();
if ( const auto inputContext = platformIntegration->inputContext() )
{
QQuickItem* item = nullptr;
if ( QMetaObject::invokeMethod( inputContext, "inputItem",
Qt::DirectConnection, Q_RETURN_ARG( QQuickItem*, item ) ) )
{
if ( item )
QGuiApplication::sendEvent( item, event );
}
}
return true;
}
return Inherited::eventFilter( object, event );
}
#include "moc_QskVirtualKeyboard.cpp"

View File

@ -137,6 +137,7 @@ public Q_SLOTS:
void setPreeditCandidates( const QVector< QString >& );
protected:
virtual bool eventFilter( QObject*, QEvent* ) override;
virtual void geometryChanged( const QRectF&, const QRectF& ) override;
virtual void updateLayout() override;