input comntext improvements
This commit is contained in:
parent
16efc695b9
commit
602e3748df
|
@ -6,16 +6,15 @@
|
|||
#include <SkinnyFont.h>
|
||||
#include <SkinnyShortcut.h>
|
||||
|
||||
#include <QskInputPanel.h>
|
||||
#include <QskDialog.h>
|
||||
#include <QskFocusIndicator.h>
|
||||
#include <QskLinearBox.h>
|
||||
#include <QskListView.h>
|
||||
#include <QskTextInput.h>
|
||||
#include <QskInputPanel.h>
|
||||
#include <QskInputContext.h>
|
||||
|
||||
#include <QskWindow.h>
|
||||
#include <QskSetup.h>
|
||||
#include <QskAspect.h>
|
||||
|
||||
#include <QskObjectCounter.h>
|
||||
|
@ -258,17 +257,16 @@ int main( int argc, char* argv[] )
|
|||
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
|
||||
|
||||
#if 1
|
||||
// We don't want to have a top level window.
|
||||
// We don't want to have the input panel in a top level window.
|
||||
qskDialog->setPolicy( QskDialog::EmbeddedBox );
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/*
|
||||
QskInputContext is connected to QskSetup::inputPanelChanged,
|
||||
making it the system input. If no input panel has been assigned
|
||||
QskInputContext would create a window or subwindow on the fly.
|
||||
If no input panel has been assigned QskInputContext creates
|
||||
default panel if none has been assigned
|
||||
*/
|
||||
qskSetup->setInputPanel( new QskInputPanel() );
|
||||
QskInputContext::setInputPanel( new QskInputPanel() );
|
||||
#endif
|
||||
|
||||
auto box = new QskLinearBox( Qt::Horizontal );
|
||||
|
|
|
@ -159,9 +159,6 @@ public:
|
|||
|
||||
Q_PROPERTY( QStringList skinList READ skinList NOTIFY skinListChanged )
|
||||
|
||||
Q_PRIVATE_PROPERTY( setup(), QQuickItem* inputPanel READ inputPanel
|
||||
WRITE setInputPanel NOTIFY inputPanelChanged )
|
||||
|
||||
Q_PRIVATE_PROPERTY( setup(), QskSetupFlagsProvider controlFlags
|
||||
READ controlFlags WRITE setControlFlags NOTIFY controlFlagsChanged )
|
||||
|
||||
|
@ -177,8 +174,7 @@ public:
|
|||
|
||||
connect( setup(), &QskSetup::skinChanged,
|
||||
this, &QskMain::skinChanged, Qt::QueuedConnection );
|
||||
connect( setup(), &QskSetup::inputPanelChanged,
|
||||
this, &QskMain::inputPanelChanged );
|
||||
|
||||
connect( setup(), &QskSetup::controlFlagsChanged,
|
||||
this, &QskMain::controlFlagsChanged, Qt::QueuedConnection );
|
||||
}
|
||||
|
|
|
@ -172,34 +172,37 @@ void qskForceActiveFocus( QQuickItem* item, Qt::FocusReason reason )
|
|||
|
||||
void qskUpdateInputMethod( const QQuickItem* item, Qt::InputMethodQueries queries )
|
||||
{
|
||||
if ( ( item == nullptr ) ||
|
||||
!( item->flags() & QQuickItem::ItemAcceptsInputMethod ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto inputMethod = QGuiApplication::inputMethod();
|
||||
|
||||
bool doUpdate = item->hasActiveFocus();
|
||||
|
||||
if ( !doUpdate )
|
||||
/*
|
||||
We could also get the inputContext from QInputMethodPrivate
|
||||
but for some reason the gcc sanitizer reports errors
|
||||
when using it. So let's go with QGuiApplicationPrivate.
|
||||
*/
|
||||
const auto inputContext =
|
||||
QGuiApplicationPrivate::platformIntegration()->inputContext();
|
||||
|
||||
if ( inputContext && inputContext->isInputPanelVisible() )
|
||||
{
|
||||
/*
|
||||
We could also get the inputContext from QInputMethodPrivate
|
||||
but for some reason the gcc sanitizer reports errors
|
||||
when using it. So let's go with QGuiApplicationPrivate.
|
||||
QskInputContext allows to navigate inside the input panel
|
||||
without losing the connected input item
|
||||
*/
|
||||
const auto inputContext =
|
||||
QGuiApplicationPrivate::platformIntegration()->inputContext();
|
||||
|
||||
if ( inputContext && inputContext->isInputPanelVisible() )
|
||||
QQuickItem* inputItem = nullptr;
|
||||
|
||||
if ( QMetaObject::invokeMethod( inputContext, "inputItem",
|
||||
Qt::DirectConnection, Q_RETURN_ARG( QQuickItem*, inputItem ) ) )
|
||||
{
|
||||
/*
|
||||
QskInputContext allows to navigate inside the input panel
|
||||
without losing the connected input item
|
||||
*/
|
||||
|
||||
QQuickItem* inputItem = nullptr;
|
||||
|
||||
if ( QMetaObject::invokeMethod( inputContext, "inputItem",
|
||||
Qt::DirectConnection, Q_RETURN_ARG( QQuickItem*, inputItem ) ) )
|
||||
{
|
||||
doUpdate = ( item == inputItem );
|
||||
}
|
||||
doUpdate = ( item == inputItem );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -126,7 +126,6 @@ public:
|
|||
|
||||
QskGraphicProviderMap graphicProviders;
|
||||
|
||||
QPointer< QQuickItem > inputPanel;
|
||||
QskSetup::Flags controlFlags;
|
||||
};
|
||||
|
||||
|
@ -261,20 +260,6 @@ QskGraphicProvider* QskSetup::graphicProvider( const QString& providerId ) const
|
|||
return m_data->graphicProviders.provider( providerId );
|
||||
}
|
||||
|
||||
void QskSetup::setInputPanel( QQuickItem* inputPanel )
|
||||
{
|
||||
if ( m_data->inputPanel == inputPanel )
|
||||
return;
|
||||
|
||||
m_data->inputPanel = inputPanel;
|
||||
Q_EMIT inputPanelChanged( m_data->inputPanel );
|
||||
}
|
||||
|
||||
QQuickItem* QskSetup::inputPanel()
|
||||
{
|
||||
return m_data->inputPanel;
|
||||
}
|
||||
|
||||
QLocale QskSetup::inheritedLocale( const QObject* object )
|
||||
{
|
||||
VisitorLocale visitor;
|
||||
|
|
|
@ -58,9 +58,6 @@ public:
|
|||
|
||||
QskSkin* skin();
|
||||
|
||||
void setInputPanel( QQuickItem* );
|
||||
QQuickItem* inputPanel();
|
||||
|
||||
void addGraphicProvider( const QString& providerId, QskGraphicProvider* );
|
||||
QskGraphicProvider* graphicProvider( const QString& providerId ) const;
|
||||
|
||||
|
@ -74,7 +71,6 @@ public:
|
|||
|
||||
Q_SIGNALS:
|
||||
void skinChanged( QskSkin* );
|
||||
void inputPanelChanged( QQuickItem* );
|
||||
void controlFlagsChanged();
|
||||
|
||||
private:
|
||||
|
|
|
@ -540,6 +540,7 @@ void QskTextInput::setReadOnly( bool on )
|
|||
|
||||
m_data->textInput->setReadOnly( on );
|
||||
|
||||
// we are killing user settings here ?
|
||||
m_data->textInput->setFlag( QQuickItem::ItemAcceptsInputMethod, !on );
|
||||
qskUpdateInputMethod( this, Qt::ImEnabled );
|
||||
|
||||
|
@ -645,10 +646,13 @@ QskTextInput::EchoMode QskTextInput::echoMode() const
|
|||
|
||||
void QskTextInput::setEchoMode( EchoMode mode )
|
||||
{
|
||||
m_data->textInput->setEchoMode(
|
||||
static_cast< QQuickTextInput::EchoMode >( mode ) );
|
||||
if ( mode != echoMode() )
|
||||
{
|
||||
m_data->textInput->setEchoMode(
|
||||
static_cast< QQuickTextInput::EchoMode >( mode ) );
|
||||
|
||||
qskUpdateInputMethod( this, Qt::ImHints );
|
||||
qskUpdateInputMethod( this, Qt::ImHints );
|
||||
}
|
||||
}
|
||||
|
||||
QString QskTextInput::displayText() const
|
||||
|
|
|
@ -4,21 +4,68 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include "QskInputContext.h"
|
||||
#include "QskInputPanel.h"
|
||||
#include "QskTextPredictor.h"
|
||||
#include "QskInputPanel.h"
|
||||
#include "QskInputEngine.h"
|
||||
|
||||
#include "QskLinearBox.h"
|
||||
#include <QskLinearBox.h>
|
||||
#include <QskDialog.h>
|
||||
#include <QskPopup.h>
|
||||
#include <QskWindow.h>
|
||||
#include <QskSetup.h>
|
||||
#include <QskEvent.h>
|
||||
|
||||
#include <QHash>
|
||||
#include <QPointer>
|
||||
#include <QGuiApplication>
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qguiapplication_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
#include <qpa/qplatformintegration.h>
|
||||
|
||||
static QPointer< QskInputPanel > qskInputPanel = nullptr;
|
||||
|
||||
static void qskDeletePanel()
|
||||
{
|
||||
delete qskInputPanel;
|
||||
}
|
||||
|
||||
static void qskInputPanelHook()
|
||||
{
|
||||
qAddPostRoutine( qskDeletePanel );
|
||||
}
|
||||
|
||||
Q_COREAPP_STARTUP_FUNCTION( qskInputPanelHook )
|
||||
|
||||
static void qskSetInputPanel( QskInputPanel* inputPanel )
|
||||
{
|
||||
if ( inputPanel == qskInputPanel )
|
||||
return;
|
||||
|
||||
delete qskInputPanel;
|
||||
qskInputPanel = inputPanel;
|
||||
}
|
||||
|
||||
void QskInputContext::setInputPanel( QskInputPanel* inputPanel )
|
||||
{
|
||||
if ( inputPanel == qskInputPanel )
|
||||
return;
|
||||
|
||||
qskSetInputPanel( inputPanel );
|
||||
|
||||
const auto inputContext =
|
||||
QGuiApplicationPrivate::platformIntegration()->inputContext();
|
||||
|
||||
if ( auto context = qobject_cast< QskInputContext* >( inputContext ) )
|
||||
context->hideInputPanel();
|
||||
}
|
||||
|
||||
QskInputPanel* QskInputContext::inputPanel()
|
||||
{
|
||||
return qskInputPanel;
|
||||
}
|
||||
|
||||
static inline uint qskHashLocale( const QLocale& locale )
|
||||
{
|
||||
return uint( locale.language() + ( uint( locale.country() ) << 16 ) );
|
||||
|
@ -77,32 +124,20 @@ public:
|
|||
// item receiving the input
|
||||
QPointer< QQuickItem > inputItem;
|
||||
|
||||
// item, wher the user enters texts/keys
|
||||
QPointer< QQuickItem > inputPanel;
|
||||
|
||||
// popup or window embedding the inputPanel
|
||||
// popup or window embedding qskInputPanel
|
||||
QskPopup* inputPopup = nullptr;
|
||||
QskWindow* inputWindow = nullptr;
|
||||
|
||||
PredictorTable predictorTable;
|
||||
|
||||
QskInputEngine* engine = nullptr;
|
||||
|
||||
// the input panel is embedded in a window
|
||||
bool ownsInputPanelWindow : 1;
|
||||
};
|
||||
|
||||
QskInputContext::QskInputContext():
|
||||
m_data( new PrivateData() )
|
||||
{
|
||||
setObjectName( "InputContext" );
|
||||
|
||||
m_data->engine = new QskInputEngine( this );
|
||||
|
||||
connect( qskSetup, &QskSetup::inputPanelChanged,
|
||||
this, &QskInputContext::setInputPanel );
|
||||
|
||||
setInputPanel( qskSetup->inputPanel() );
|
||||
}
|
||||
|
||||
QskInputContext::~QskInputContext()
|
||||
|
@ -125,37 +160,6 @@ QQuickItem* QskInputContext::inputItem()
|
|||
return m_data->inputItem;
|
||||
}
|
||||
|
||||
void QskInputContext::setInputItem( QQuickItem* item )
|
||||
{
|
||||
if ( m_data->inputItem == item )
|
||||
return;
|
||||
|
||||
auto panel = qobject_cast< QskInputPanel* >( m_data->inputPanel );
|
||||
|
||||
if ( isInputPanelVisible() )
|
||||
{
|
||||
if ( item == nullptr )
|
||||
{
|
||||
hideInputPanel();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( panel )
|
||||
panel->attachInputItem( item );
|
||||
|
||||
update( Qt::ImQueryAll );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no need for updates
|
||||
if ( panel )
|
||||
panel->attachInputItem( nullptr );
|
||||
}
|
||||
|
||||
m_data->inputItem = item;
|
||||
}
|
||||
|
||||
void QskInputContext::update( Qt::InputMethodQueries queries )
|
||||
{
|
||||
if ( queries & Qt::ImEnabled )
|
||||
|
@ -170,225 +174,172 @@ void QskInputContext::update( Qt::InputMethodQueries queries )
|
|||
}
|
||||
}
|
||||
|
||||
if ( auto panel = qobject_cast< QskInputPanel* >( m_data->inputPanel ) )
|
||||
panel->processInputMethodQueries( queries );
|
||||
if ( qskInputPanel )
|
||||
qskInputPanel->processInputMethodQueries( queries );
|
||||
}
|
||||
|
||||
QRectF QskInputContext::keyboardRect() const
|
||||
{
|
||||
if ( m_data->inputPanel
|
||||
&& QskDialog::instance()->policy() != QskDialog::TopLevelWindow )
|
||||
{
|
||||
return qskItemGeometry( m_data->inputPanel );
|
||||
}
|
||||
// is this correct and what is this good for ?
|
||||
if ( m_data->inputPopup )
|
||||
return m_data->inputPopup->geometry();
|
||||
|
||||
return Inherited::keyboardRect();
|
||||
}
|
||||
|
||||
bool QskInputContext::isAnimating() const
|
||||
{
|
||||
// can be implemented once we have some sliding/fading effects
|
||||
return false;
|
||||
}
|
||||
|
||||
void QskInputContext::showInputPanel()
|
||||
{
|
||||
auto& inputPanel = m_data->inputPanel;
|
||||
auto focusItem = qobject_cast< QQuickItem* >( qGuiApp->focusObject() );
|
||||
|
||||
if ( focusItem == nullptr )
|
||||
return;
|
||||
|
||||
if ( ( focusItem == qskInputPanel )
|
||||
|| qskIsAncestorOf( qskInputPanel, focusItem ) )
|
||||
{
|
||||
// ignore: usually the input proxy of the panel
|
||||
return;
|
||||
}
|
||||
|
||||
m_data->inputItem = focusItem;
|
||||
|
||||
auto& inputPopup = m_data->inputPopup;
|
||||
auto& inputWindow = m_data->inputWindow;
|
||||
|
||||
if ( inputPanel == nullptr )
|
||||
if ( qskInputPanel == nullptr )
|
||||
qskSetInputPanel( new QskInputPanel() );
|
||||
|
||||
connect( qskInputPanel, &QQuickItem::visibleChanged,
|
||||
this, &QPlatformInputContext::emitInputPanelVisibleChanged,
|
||||
Qt::UniqueConnection );
|
||||
|
||||
connect( qskInputPanel, &QskControl::localeChanged,
|
||||
this, &QPlatformInputContext::emitLocaleChanged,
|
||||
Qt::UniqueConnection );
|
||||
|
||||
if ( QskDialog::instance()->policy() == QskDialog::TopLevelWindow )
|
||||
{
|
||||
auto panel = new QskInputPanel();
|
||||
// The input panel is embedded in a top level window
|
||||
|
||||
panel->setParent( this );
|
||||
panel->setInputProxy( true );
|
||||
|
||||
setInputPanel( panel );
|
||||
}
|
||||
|
||||
const bool isPopupPanel = qobject_cast< QskPopup* >( inputPanel );
|
||||
|
||||
bool useWindow = false;
|
||||
if ( !isPopupPanel )
|
||||
{
|
||||
useWindow = ( QskDialog::instance()->policy() == QskDialog::TopLevelWindow );
|
||||
}
|
||||
|
||||
if ( useWindow )
|
||||
{
|
||||
delete inputPopup;
|
||||
|
||||
if ( inputWindow == nullptr )
|
||||
{
|
||||
inputWindow = new QskWindow();
|
||||
inputWindow->setDeleteOnClose( true );
|
||||
#if 0
|
||||
inputWindow->setFlags( Qt::Tool | Qt::WindowDoesNotAcceptFocus );
|
||||
#endif
|
||||
|
||||
inputPanel->setParentItem( inputWindow->contentItem() );
|
||||
|
||||
QSizeF size;
|
||||
if ( auto control = qobject_cast< const QskControl* >( inputPanel ) )
|
||||
size = control->sizeHint();
|
||||
|
||||
if ( size.isEmpty() )
|
||||
size = QSizeF( 800, 240 ); // ### what size?
|
||||
|
||||
inputWindow->resize( size.toSize() );
|
||||
inputWindow->show();
|
||||
|
||||
inputWindow->installEventFilter( this );
|
||||
qskInputPanel->setParentItem( inputWindow->contentItem() );
|
||||
}
|
||||
|
||||
QSize size = qskInputPanel->sizeHint().toSize();
|
||||
if ( size.isEmpty() )
|
||||
{
|
||||
// no idea, may be something based on the screen size
|
||||
size = QSize( 800, 240 );
|
||||
}
|
||||
|
||||
inputWindow->resize( size );
|
||||
inputWindow->show();
|
||||
|
||||
inputWindow->installEventFilter( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
// The input panel is embedded in a popup
|
||||
|
||||
delete inputWindow;
|
||||
|
||||
if ( inputPopup == nullptr )
|
||||
{
|
||||
if ( isPopupPanel )
|
||||
{
|
||||
inputPopup = qobject_cast< QskPopup* >( inputPanel );
|
||||
}
|
||||
else
|
||||
{
|
||||
auto popup = new QskPopup( m_data->inputItem->window()->contentItem() );
|
||||
inputPopup = new QskPopup( m_data->inputItem->window()->contentItem() );
|
||||
|
||||
popup->setAutoLayoutChildren( true );
|
||||
popup->setTransparentForPositioner( false );
|
||||
popup->setOverlay( false );
|
||||
popup->setModal( true );
|
||||
inputPopup->setAutoLayoutChildren( true );
|
||||
inputPopup->setTransparentForPositioner( false );
|
||||
inputPopup->setModal( true );
|
||||
|
||||
auto box = new QskLinearBox( popup );
|
||||
box->addItem( inputPanel );
|
||||
auto box = new QskLinearBox( inputPopup );
|
||||
box->addItem( qskInputPanel );
|
||||
|
||||
if ( auto panel = qobject_cast< QskInputPanel* >( inputPanel ) )
|
||||
{
|
||||
if ( panel->hasInputProxy() )
|
||||
{
|
||||
popup->setOverlay( true );
|
||||
}
|
||||
}
|
||||
/*
|
||||
When the panel has an input proxy ( usually a local text input )
|
||||
we don't need to see the input item and display the overlay
|
||||
and align in the center of the window.
|
||||
*/
|
||||
const bool hasInputProxy = qskInputPanel->hasInputProxy();
|
||||
|
||||
if ( !popup->hasOverlay() )
|
||||
{
|
||||
box->setExtraSpacingAt( Qt::TopEdge | Qt::LeftEdge | Qt::RightEdge );
|
||||
}
|
||||
inputPopup->setOverlay( hasInputProxy );
|
||||
|
||||
inputPopup = popup;
|
||||
}
|
||||
|
||||
inputPopup->installEventFilter( this );
|
||||
}
|
||||
|
||||
if ( inputPopup->window() == nullptr )
|
||||
{
|
||||
QQuickWindow* window = nullptr;
|
||||
if ( m_data->inputItem )
|
||||
window = m_data->inputItem->window();
|
||||
else
|
||||
window = qobject_cast< QQuickWindow* >( QGuiApplication::focusWindow() );
|
||||
|
||||
if ( window )
|
||||
{
|
||||
inputPopup->setParentItem( window->contentItem() );
|
||||
}
|
||||
if ( !hasInputProxy )
|
||||
box->setExtraSpacingAt( Qt::TopEdge | Qt::LeftEdge | Qt::RightEdge );
|
||||
}
|
||||
|
||||
inputPopup->setParentItem( m_data->inputItem->window()->contentItem() );
|
||||
inputPopup->setVisible( true );
|
||||
inputPopup->installEventFilter( this );
|
||||
}
|
||||
|
||||
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
|
||||
if ( auto focusItem = inputPanel->nextItemInFocusChain( true ) )
|
||||
qskForceActiveFocus( focusItem, Qt::OtherFocusReason );
|
||||
#endif
|
||||
|
||||
connect( inputPanel->window(), &QskWindow::visibleChanged,
|
||||
this, &QskInputContext::emitInputPanelVisibleChanged );
|
||||
|
||||
updateInputPanel( m_data->inputItem );
|
||||
|
||||
m_data->engine->setPredictor(
|
||||
m_data->predictorTable.find( locale() ) );
|
||||
|
||||
qskInputPanel->setLocale( locale() );
|
||||
qskInputPanel->attachInputItem( m_data->inputItem );
|
||||
qskInputPanel->setEngine( m_data->engine );
|
||||
}
|
||||
|
||||
void QskInputContext::hideInputPanel()
|
||||
{
|
||||
if ( m_data->inputPanel )
|
||||
if ( m_data->inputPopup )
|
||||
{
|
||||
// to get rid of the scene graph nodes
|
||||
m_data->inputPanel->setVisible( false );
|
||||
if ( auto panel = qobject_cast< QskInputPanel* >( m_data->inputPanel ) )
|
||||
panel->setEngine( nullptr );
|
||||
}
|
||||
|
||||
if ( m_data->inputPopup == m_data->inputPanel )
|
||||
{
|
||||
m_data->inputPopup->removeEventFilter( this );
|
||||
m_data->inputPopup = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_data->inputPopup )
|
||||
{
|
||||
#if 1
|
||||
if ( auto focusItem = m_data->inputPopup->scopedFocusItem() )
|
||||
{
|
||||
/*
|
||||
Qt bug: QQuickItem::hasFocus() is not cleared
|
||||
when the corresponding focusScope gets deleted.
|
||||
Usually no problem, but here the focusItem is no
|
||||
child and will be reused with a different parent
|
||||
later.
|
||||
*/
|
||||
focusItem->setFocus( false );
|
||||
}
|
||||
if ( auto focusItem = m_data->inputPopup->scopedFocusItem() )
|
||||
{
|
||||
/*
|
||||
Qt bug: QQuickItem::hasFocus() is not cleared
|
||||
when the corresponding focusScope gets deleted.
|
||||
Usually no problem, but here the focusItem is no
|
||||
child and will be reused with a different parent
|
||||
later.
|
||||
*/
|
||||
focusItem->setFocus( false );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_data->inputPopup->deleteLater();
|
||||
}
|
||||
m_data->inputPopup->deleteLater();
|
||||
}
|
||||
|
||||
QskWindow* window = m_data->inputWindow;
|
||||
m_data->inputWindow = nullptr;
|
||||
|
||||
if ( window )
|
||||
if ( m_data->inputWindow )
|
||||
{
|
||||
QskWindow* window = m_data->inputWindow;
|
||||
m_data->inputWindow = nullptr;
|
||||
|
||||
window->removeEventFilter( this );
|
||||
window->close(); // deleteOnClose is set
|
||||
}
|
||||
|
||||
qGuiApp->removeEventFilter( this );
|
||||
if ( qskInputPanel )
|
||||
{
|
||||
//qskInputPanel->setVisible( false );
|
||||
qskInputPanel->setParentItem( nullptr );
|
||||
qskInputPanel->attachInputItem( nullptr );
|
||||
qskInputPanel->setEngine( nullptr );
|
||||
}
|
||||
|
||||
updateInputPanel( nullptr );
|
||||
}
|
||||
|
||||
void QskInputContext::updateInputPanel( QQuickItem* inputItem )
|
||||
{
|
||||
auto panel = qobject_cast< QskInputPanel* >( m_data->inputPanel );
|
||||
if ( panel == nullptr )
|
||||
return;
|
||||
|
||||
panel->setLocale( locale() );
|
||||
panel->attachInputItem( inputItem );
|
||||
|
||||
panel->setEngine( inputItem ? m_data->engine : nullptr );
|
||||
m_data->inputItem = nullptr;
|
||||
}
|
||||
|
||||
bool QskInputContext::isInputPanelVisible() const
|
||||
{
|
||||
auto panel = m_data->inputPanel;
|
||||
|
||||
return panel && panel->isVisible()
|
||||
&& panel->window() && panel->window()->isVisible();
|
||||
return qskInputPanel && qskInputPanel->isVisible()
|
||||
&& qskInputPanel->window() && qskInputPanel->window()->isVisible();
|
||||
}
|
||||
|
||||
QLocale QskInputContext::locale() const
|
||||
|
@ -411,48 +362,52 @@ Qt::LayoutDirection QskInputContext::inputDirection() const
|
|||
|
||||
void QskInputContext::setFocusObject( QObject* focusObject )
|
||||
{
|
||||
auto focusItem = qobject_cast< QQuickItem* >( focusObject );
|
||||
|
||||
if ( focusItem == nullptr )
|
||||
if ( m_data->inputItem == nullptr || m_data->inputItem == focusObject )
|
||||
{
|
||||
if ( m_data->inputItem )
|
||||
// we don't care
|
||||
return;
|
||||
}
|
||||
|
||||
bool doTerminate = true;
|
||||
|
||||
if ( focusObject == nullptr && m_data->inputPopup )
|
||||
{
|
||||
if ( const auto window = m_data->inputItem->window() )
|
||||
{
|
||||
if ( m_data->inputItem->window() == QGuiApplication::focusWindow() )
|
||||
setInputItem( nullptr );
|
||||
auto focusItem = window->contentItem()->scopedFocusItem();
|
||||
if ( focusItem == m_data->inputPopup )
|
||||
doTerminate = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if ( doTerminate )
|
||||
{
|
||||
/*
|
||||
Do not change the input item when
|
||||
navigating to or inside the input popup/window
|
||||
*/
|
||||
|
||||
bool isAccepted = ( m_data->inputItem == nullptr );
|
||||
|
||||
if ( !isAccepted )
|
||||
if ( m_data->inputWindow )
|
||||
{
|
||||
if ( m_data->inputWindow )
|
||||
auto focusWindow = QGuiApplication::focusWindow();
|
||||
|
||||
if ( focusWindow == nullptr ||
|
||||
QGuiApplication::focusWindow() == m_data->inputWindow )
|
||||
{
|
||||
if ( focusItem->window() != m_data->inputWindow )
|
||||
isAccepted = true;
|
||||
}
|
||||
else if ( m_data->inputPopup )
|
||||
{
|
||||
if ( ( focusItem != m_data->inputPopup )
|
||||
&& !qskIsAncestorOf( m_data->inputPopup, focusItem ) )
|
||||
{
|
||||
isAccepted = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isAccepted = true;
|
||||
doTerminate = false;
|
||||
}
|
||||
}
|
||||
else if ( m_data->inputPopup )
|
||||
{
|
||||
auto focusItem = qobject_cast< QQuickItem* >( focusObject );
|
||||
|
||||
if ( isAccepted )
|
||||
setInputItem( focusItem );
|
||||
if ( ( focusItem == m_data->inputPopup )
|
||||
|| qskIsAncestorOf( m_data->inputPopup, focusItem ) )
|
||||
{
|
||||
doTerminate = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( doTerminate )
|
||||
{
|
||||
hideInputPanel();
|
||||
m_data->inputItem = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -484,51 +439,17 @@ void QskInputContext::invokeAction( QInputMethod::Action, int )
|
|||
{
|
||||
}
|
||||
|
||||
void QskInputContext::setInputPanel( QQuickItem* inputPanel )
|
||||
{
|
||||
if ( m_data->inputPanel == inputPanel )
|
||||
return;
|
||||
|
||||
if ( m_data->inputPanel )
|
||||
{
|
||||
m_data->inputPanel->disconnect( this );
|
||||
|
||||
if ( m_data->inputPanel->parent() == this )
|
||||
{
|
||||
delete m_data->inputPanel;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_data->inputPanel->setParentItem( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
m_data->inputPanel = inputPanel;
|
||||
m_data->ownsInputPanelWindow = false;
|
||||
|
||||
if ( inputPanel )
|
||||
{
|
||||
if ( inputPanel->parent() == nullptr )
|
||||
inputPanel->setParent( this );
|
||||
|
||||
connect( inputPanel, &QQuickItem::visibleChanged,
|
||||
this, &QPlatformInputContext::emitInputPanelVisibleChanged );
|
||||
|
||||
if ( auto control = qobject_cast< QskControl* >( inputPanel ) )
|
||||
{
|
||||
connect( control, &QskControl::localeChanged,
|
||||
this, &QPlatformInputContext::emitLocaleChanged );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QskInputContext::reset()
|
||||
{
|
||||
}
|
||||
|
||||
void QskInputContext::commit()
|
||||
{
|
||||
// called on focus changes
|
||||
/*
|
||||
commit is called, when the input item loses the focus.
|
||||
As it it should be possible to navigate inside of the
|
||||
inputPanel this is no valid reason to hide the panel.
|
||||
*/
|
||||
}
|
||||
|
||||
bool QskInputContext::eventFilter( QObject* object, QEvent* event )
|
||||
|
@ -539,15 +460,15 @@ bool QskInputContext::eventFilter( QObject* object, QEvent* event )
|
|||
{
|
||||
case QEvent::Move:
|
||||
{
|
||||
if ( m_data->inputPanel )
|
||||
if ( qskInputPanel )
|
||||
emitKeyboardRectChanged();
|
||||
|
||||
break;
|
||||
}
|
||||
case QEvent::Resize:
|
||||
{
|
||||
if ( m_data->inputPanel )
|
||||
m_data->inputPanel->setSize( m_data->inputWindow->size() );
|
||||
if ( qskInputPanel )
|
||||
qskInputPanel->setSize( m_data->inputWindow->size() );
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <memory>
|
||||
|
||||
class QskTextPredictor;
|
||||
class QskInputPanel;
|
||||
class QQuickItem;
|
||||
|
||||
class QSK_EXPORT QskInputContext : public QPlatformInputContext
|
||||
|
@ -51,19 +52,16 @@ public:
|
|||
|
||||
virtual bool filterEvent( const QEvent* ) override;
|
||||
|
||||
static void setInputPanel( QskInputPanel* );
|
||||
static QskInputPanel* inputPanel();
|
||||
|
||||
protected:
|
||||
virtual void updateInputPanel( QQuickItem* inputItem );
|
||||
|
||||
private Q_SLOTS:
|
||||
void setInputPanel( QQuickItem* );
|
||||
|
||||
virtual bool eventFilter( QObject*, QEvent* ) override;
|
||||
|
||||
private:
|
||||
void setInputItem( QQuickItem* );
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,10 +18,27 @@
|
|||
#include <QInputMethodQueryEvent>
|
||||
#include <QTextCharFormat>
|
||||
|
||||
static inline void qskSendText( QQuickItem* inputItem,
|
||||
static inline void qskSendReplaceText( QQuickItem* receiver, const QString& text )
|
||||
{
|
||||
if ( receiver == nullptr )
|
||||
return;
|
||||
|
||||
QInputMethodEvent::Attribute attribute(
|
||||
QInputMethodEvent::Selection, 0, 32767, QVariant() );
|
||||
|
||||
QInputMethodEvent event1( QString(), { attribute } );
|
||||
QCoreApplication::sendEvent( receiver, &event1 );
|
||||
|
||||
QInputMethodEvent event2;
|
||||
event2.setCommitString( text );
|
||||
|
||||
QCoreApplication::sendEvent( receiver, &event2 );
|
||||
}
|
||||
|
||||
static inline void qskSendText( QQuickItem* receiver,
|
||||
const QString& text, bool isFinal )
|
||||
{
|
||||
if ( inputItem == nullptr )
|
||||
if ( receiver == nullptr )
|
||||
return;
|
||||
|
||||
if ( isFinal )
|
||||
|
@ -29,7 +46,7 @@ static inline void qskSendText( QQuickItem* inputItem,
|
|||
QInputMethodEvent event;
|
||||
event.setCommitString( text );
|
||||
|
||||
QCoreApplication::sendEvent( inputItem, &event );
|
||||
QCoreApplication::sendEvent( receiver, &event );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -41,20 +58,20 @@ static inline void qskSendText( QQuickItem* inputItem,
|
|||
|
||||
QInputMethodEvent event( text, { attribute } );
|
||||
|
||||
QCoreApplication::sendEvent( inputItem, &event );
|
||||
QCoreApplication::sendEvent( receiver, &event );
|
||||
}
|
||||
}
|
||||
|
||||
static inline void qskSendKey( QQuickItem* inputItem, int key )
|
||||
static inline void qskSendKey( QQuickItem* receiver, int key )
|
||||
{
|
||||
if ( inputItem == nullptr )
|
||||
if ( receiver == nullptr )
|
||||
return;
|
||||
|
||||
QKeyEvent keyPress( QEvent::KeyPress, key, Qt::NoModifier );
|
||||
QCoreApplication::sendEvent( inputItem, &keyPress );
|
||||
QCoreApplication::sendEvent( receiver, &keyPress );
|
||||
|
||||
QKeyEvent keyRelease( QEvent::KeyRelease, key, Qt::NoModifier );
|
||||
QCoreApplication::sendEvent( inputItem, &keyRelease );
|
||||
QCoreApplication::sendEvent( receiver, &keyRelease );
|
||||
}
|
||||
|
||||
namespace
|
||||
|
@ -65,6 +82,7 @@ namespace
|
|||
TextInput( QQuickItem* parentItem = nullptr ):
|
||||
QskTextInput( parentItem )
|
||||
{
|
||||
setObjectName( "InputPanelInputProxy" );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -75,10 +93,18 @@ 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;
|
||||
|
||||
|
@ -88,6 +114,10 @@ public:
|
|||
QskInputPredictionBar* predictionBar;
|
||||
QskVirtualKeyboard* keyboard;
|
||||
|
||||
Qt::InputMethodHints inputHints;
|
||||
int maxChars;
|
||||
|
||||
bool hasPrediction : 1;
|
||||
bool hasInputProxy : 1;
|
||||
};
|
||||
|
||||
|
@ -146,7 +176,8 @@ void QskInputPanel::setEngine( QskInputEngine* engine )
|
|||
this, &QskInputPanel::updatePredictionBar );
|
||||
}
|
||||
|
||||
m_data->predictionBar->setVisible( engine && engine->predictor() );
|
||||
m_data->predictionBar->setVisible(
|
||||
m_data->hasPrediction && engine && engine->predictor() );
|
||||
}
|
||||
|
||||
void QskInputPanel::attachInputItem( QQuickItem* item )
|
||||
|
@ -165,6 +196,9 @@ void QskInputPanel::attachInputItem( QQuickItem* item )
|
|||
queries &= ~Qt::ImEnabled;
|
||||
|
||||
processInputMethodQueries( queries );
|
||||
|
||||
if ( m_data->hasInputProxy )
|
||||
m_data->inputProxy->setEditing( true );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,56 +268,6 @@ 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 );
|
||||
}
|
||||
}
|
||||
|
||||
void QskInputPanel::commitPredictiveText( int index )
|
||||
{
|
||||
m_data->predictionBar->setPrediction( QVector< QString >() );
|
||||
|
@ -302,34 +286,23 @@ void QskInputPanel::commitKey( int key )
|
|||
if ( m_data->engine == nullptr || m_data->inputItem == nullptr )
|
||||
return;
|
||||
|
||||
auto engine = m_data->engine;
|
||||
auto inputItem = m_data->inputItem;
|
||||
|
||||
QInputMethodQueryEvent event( Qt::ImHints );
|
||||
QCoreApplication::sendEvent( inputItem, &event );
|
||||
|
||||
const auto inputHints = static_cast< Qt::InputMethodHints >(
|
||||
event.value( Qt::ImHints ).toInt() );
|
||||
|
||||
int spaceLeft = -1;
|
||||
|
||||
if ( !( inputHints & Qt::ImhMultiLine ) )
|
||||
if ( !( m_data->inputHints & Qt::ImhMultiLine ) )
|
||||
{
|
||||
QInputMethodQueryEvent event(
|
||||
Qt::ImSurroundingText | Qt::ImMaximumTextLength );
|
||||
auto receiver = m_data->receiverItem();
|
||||
|
||||
QCoreApplication::sendEvent( inputItem, &event );
|
||||
|
||||
const int max = event.value( Qt::ImMaximumTextLength ).toInt();
|
||||
|
||||
if ( max > 0 )
|
||||
if ( m_data->maxChars >= 0 )
|
||||
{
|
||||
QInputMethodQueryEvent event( Qt::ImSurroundingText );
|
||||
QCoreApplication::sendEvent( receiver, &event );
|
||||
|
||||
const auto text = event.value( Qt::ImSurroundingText ).toString();
|
||||
spaceLeft = max - text.length();
|
||||
spaceLeft = m_data->maxChars - text.length();
|
||||
}
|
||||
}
|
||||
|
||||
processKey( key, inputHints, spaceLeft );
|
||||
processKey( key, m_data->inputHints, spaceLeft );
|
||||
}
|
||||
|
||||
void QskInputPanel::processKey( int key,
|
||||
|
@ -338,16 +311,35 @@ void QskInputPanel::processKey( int key,
|
|||
const auto result = m_data->engine->processKey( key, inputHints, spaceLeft );
|
||||
|
||||
auto inputItem = m_data->inputItem;
|
||||
auto inputProxy = m_data->inputProxy;
|
||||
|
||||
if ( result.key )
|
||||
{
|
||||
// sending a control key
|
||||
qskSendKey( inputItem, result.key );
|
||||
switch( result.key )
|
||||
{
|
||||
case Qt::Key_Return:
|
||||
{
|
||||
if ( m_data->hasInputProxy )
|
||||
qskSendReplaceText( inputItem, inputProxy->text() );
|
||||
|
||||
qskSendKey( inputItem, result.key );
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Escape:
|
||||
{
|
||||
qskSendKey( inputItem, result.key );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
qskSendKey( m_data->receiverItem(), result.key );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( !result.text.isEmpty() )
|
||||
{
|
||||
// changing the current text
|
||||
qskSendText( inputItem, result.text, result.isFinal );
|
||||
qskSendText( m_data->receiverItem(), result.text, result.isFinal );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -356,73 +348,182 @@ void QskInputPanel::processInputMethodQueries( Qt::InputMethodQueries queries )
|
|||
if ( m_data->inputItem == nullptr )
|
||||
return;
|
||||
|
||||
/*
|
||||
adjust the input panel to information provided from the input item
|
||||
*/
|
||||
QInputMethodQueryEvent event( queries );
|
||||
QCoreApplication::sendEvent( m_data->inputItem, &event );
|
||||
|
||||
QInputMethodQueryEvent queryEvent( queries );
|
||||
QCoreApplication::sendEvent( m_data->inputItem, &queryEvent );
|
||||
|
||||
if ( queryEvent.queries() & Qt::ImHints )
|
||||
if ( queries & Qt::ImHints )
|
||||
{
|
||||
/*
|
||||
ImhHiddenText = 0x1, // might need to disable certain checks
|
||||
ImhSensitiveData = 0x2, // shouldn't change anything
|
||||
ImhNoAutoUppercase = 0x4, // if we support auto uppercase, disable it
|
||||
ImhPreferNumbers = 0x8, // default to number keyboard
|
||||
ImhPreferUppercase = 0x10, // start with shift on
|
||||
ImhPreferLowercase = 0x20, // start with shift off
|
||||
ImhNoPredictiveText = 0x40, // not use predictive text
|
||||
bool hasPrediction = true;
|
||||
bool hasEchoMode = false;
|
||||
|
||||
ImhDate = 0x80, // ignored for now (no date keyboard)
|
||||
ImhTime = 0x100, // ignored for know (no time keyboard)
|
||||
|
||||
ImhPreferLatin = 0x200, // can be used to launch chinese kb in english mode
|
||||
|
||||
ImhMultiLine = 0x400, // not useful?
|
||||
|
||||
ImhDigitsOnly // default to number keyboard, disable other keys
|
||||
ImhFormattedNumbersOnly // hard to say
|
||||
ImhUppercaseOnly // caps-lock, disable shift
|
||||
ImhLowercaseOnly // disable shift
|
||||
ImhDialableCharactersOnly // dial pad (calculator?)
|
||||
ImhEmailCharactersOnly // disable certain symbols (email-only kb?)
|
||||
ImhUrlCharactersOnly // disable certain symbols (url-only kb?)
|
||||
ImhLatinOnly // disable chinese input
|
||||
*/
|
||||
|
||||
#if 0
|
||||
const auto hints = static_cast< Qt::InputMethodHints >(
|
||||
queryEvent.value( Qt::ImHints ).toInt() );
|
||||
event.value( Qt::ImHints ).toInt() );
|
||||
|
||||
#endif
|
||||
if ( hints & Qt::ImhHiddenText )
|
||||
{
|
||||
hasEchoMode = true;
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhSensitiveData )
|
||||
{
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhNoAutoUppercase )
|
||||
{
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhPreferNumbers )
|
||||
{
|
||||
// we should start with having the number keys being visible
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhPreferUppercase )
|
||||
{
|
||||
// we should start with having the upper keys being visible
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhPreferLowercase )
|
||||
{
|
||||
// we should start with having the upper keys being visible
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhNoPredictiveText )
|
||||
{
|
||||
hasPrediction = false;
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhDate )
|
||||
{
|
||||
// we should have a date/time input
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhTime )
|
||||
{
|
||||
// we should have a date/time input
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhPreferLatin )
|
||||
{
|
||||
// conflicts with our concept of using the locale
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhMultiLine )
|
||||
{
|
||||
// we need an implementation of QskTextEdit for this
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhDigitsOnly )
|
||||
{
|
||||
// using a numpad instead of our virtual keyboard
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhFormattedNumbersOnly )
|
||||
{
|
||||
// a numpad with decimal point and minus sign
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhUppercaseOnly )
|
||||
{
|
||||
// locking all other keys
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhLowercaseOnly )
|
||||
{
|
||||
// locking all other keys
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhDialableCharactersOnly )
|
||||
{
|
||||
// characters suitable for phone dialing
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhEmailCharactersOnly )
|
||||
{
|
||||
// characters suitable for email addresses
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhUrlCharactersOnly )
|
||||
{
|
||||
// characters suitable for URLs
|
||||
}
|
||||
|
||||
if ( hints & Qt::ImhLatinOnly )
|
||||
{
|
||||
// locking all other keys
|
||||
}
|
||||
|
||||
m_data->hasPrediction = hasPrediction;
|
||||
|
||||
m_data->predictionBar->setVisible(
|
||||
hasPrediction && m_data->engine && m_data->engine->predictor() );
|
||||
|
||||
m_data->inputProxy->setEchoMode(
|
||||
hasEchoMode ? QskTextInput::PasswordEchoOnEdit : QskTextInput::Normal );
|
||||
|
||||
m_data->inputHints = hints;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if ( queryEvent.queries() & Qt::ImPreferredLanguage )
|
||||
if ( queries & Qt::ImPreferredLanguage )
|
||||
{
|
||||
// already handled by the input context
|
||||
}
|
||||
|
||||
if ( 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 ( queries & Qt::ImSurroundingText )
|
||||
{
|
||||
if ( m_data->hasInputProxy )
|
||||
{
|
||||
const auto text = event.value( Qt::ImSurroundingText ).toString();
|
||||
m_data->inputProxy->setText( text );
|
||||
}
|
||||
}
|
||||
|
||||
if ( queries & Qt::ImCursorPosition )
|
||||
{
|
||||
if ( m_data->hasInputProxy )
|
||||
{
|
||||
const auto pos = event.value( Qt::ImCursorPosition ).toInt();
|
||||
m_data->inputProxy->setCursorPosition( pos );
|
||||
}
|
||||
}
|
||||
|
||||
if ( queries & Qt::ImCurrentSelection )
|
||||
{
|
||||
#if 0
|
||||
const auto text = event.value( Qt::ImCurrentSelection ).toString();
|
||||
if ( !text.isEmpty() )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
Qt::ImMicroFocus
|
||||
Qt::ImCursorRectangle
|
||||
Qt::ImFont
|
||||
Qt::ImCursorPosition
|
||||
Qt::ImSurroundingText // important for chinese input
|
||||
Qt::ImCurrentSelection // important for prediction
|
||||
Qt::ImMaximumTextLength // should be monitored
|
||||
Qt::ImAnchorPosition
|
||||
|
||||
Qt::ImAbsolutePosition
|
||||
Qt::ImTextBeforeCursor // important for chinese
|
||||
Qt::ImTextAfterCursor // important for chinese
|
||||
Qt::ImTextBeforeCursor
|
||||
Qt::ImTextAfterCursor
|
||||
Qt::ImPlatformData // hard to say...
|
||||
Qt::ImEnterKeyType
|
||||
Qt::ImAnchorRectangle
|
||||
Qt::ImInputItemClipRectangle // could be used for the geometry of the panel
|
||||
Qt::ImInputItemClipRectangle
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
void QskInputPanel::keyPressEvent( QKeyEvent* event )
|
||||
|
|
|
@ -16,7 +16,7 @@ class QLocale;
|
|||
|
||||
template class QVector< QString >;
|
||||
|
||||
class QSK_EXPORT QskInputPanel: public QskBox
|
||||
class QSK_EXPORT QskInputPanel : public QskBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -49,7 +49,6 @@ public:
|
|||
virtual QskAspect::Subcontrol effectiveSubcontrol(
|
||||
QskAspect::Subcontrol ) const override;
|
||||
|
||||
void updateInputProxy( const QQuickItem* );
|
||||
virtual void processInputMethodQueries( Qt::InputMethodQueries );
|
||||
|
||||
Q_SIGNALS:
|
||||
|
|
Loading…
Reference in New Issue