2018-04-06 17:30:24 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskInputPanel.h"
|
2018-04-26 14:42:33 +02:00
|
|
|
#include "QskInputEngine.h"
|
2018-04-10 16:51:35 +02:00
|
|
|
#include "QskVirtualKeyboard.h"
|
2018-04-26 14:42:33 +02:00
|
|
|
#include "QskInputPredictionBar.h"
|
2018-04-18 19:41:46 +02:00
|
|
|
#include "QskTextInput.h"
|
|
|
|
#include "QskTextLabel.h"
|
2018-04-10 16:51:35 +02:00
|
|
|
#include "QskLinearBox.h"
|
2018-04-06 17:30:24 +02:00
|
|
|
|
|
|
|
#include <QString>
|
|
|
|
#include <QLocale>
|
2018-04-11 08:58:14 +02:00
|
|
|
#include <QGuiApplication>
|
2018-04-26 14:42:33 +02:00
|
|
|
#include <QPointer>
|
|
|
|
#include <QInputMethodQueryEvent>
|
|
|
|
#include <QTextCharFormat>
|
2018-04-10 16:51:35 +02:00
|
|
|
|
2018-04-27 13:48:51 +02:00
|
|
|
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,
|
2018-04-26 14:42:33 +02:00
|
|
|
const QString& text, bool isFinal )
|
2018-04-06 17:30:24 +02:00
|
|
|
{
|
2018-04-27 13:48:51 +02:00
|
|
|
if ( receiver == nullptr )
|
2018-04-26 14:42:33 +02:00
|
|
|
return;
|
2018-04-06 17:30:24 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
if ( isFinal )
|
|
|
|
{
|
|
|
|
QInputMethodEvent event;
|
|
|
|
event.setCommitString( text );
|
2018-04-06 17:30:24 +02:00
|
|
|
|
2018-04-27 13:48:51 +02:00
|
|
|
QCoreApplication::sendEvent( receiver, &event );
|
2018-04-26 14:42:33 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QTextCharFormat format;
|
|
|
|
format.setFontUnderline( true );
|
2018-04-06 17:30:24 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
const QInputMethodEvent::Attribute attribute(
|
|
|
|
QInputMethodEvent::TextFormat, 0, text.length(), format );
|
2018-04-06 17:30:24 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
QInputMethodEvent event( text, { attribute } );
|
2018-04-06 17:30:24 +02:00
|
|
|
|
2018-04-27 13:48:51 +02:00
|
|
|
QCoreApplication::sendEvent( receiver, &event );
|
2018-04-26 14:42:33 +02:00
|
|
|
}
|
|
|
|
}
|
2018-04-06 17:30:24 +02:00
|
|
|
|
2018-04-27 13:48:51 +02:00
|
|
|
static inline void qskSendKey( QQuickItem* receiver, int key )
|
2018-04-26 14:42:33 +02:00
|
|
|
{
|
2018-04-27 13:48:51 +02:00
|
|
|
if ( receiver == nullptr )
|
2018-04-26 14:42:33 +02:00
|
|
|
return;
|
2018-04-06 17:30:24 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
QKeyEvent keyPress( QEvent::KeyPress, key, Qt::NoModifier );
|
2018-04-27 13:48:51 +02:00
|
|
|
QCoreApplication::sendEvent( receiver, &keyPress );
|
2018-04-06 17:30:24 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
QKeyEvent keyRelease( QEvent::KeyRelease, key, Qt::NoModifier );
|
2018-04-27 13:48:51 +02:00
|
|
|
QCoreApplication::sendEvent( receiver, &keyRelease );
|
2018-04-06 17:30:24 +02:00
|
|
|
}
|
|
|
|
|
2018-04-27 16:55:50 +02:00
|
|
|
static inline void qskSyncInputProxy(
|
|
|
|
QQuickItem* inputItem, QskTextInput* inputProxy )
|
|
|
|
{
|
|
|
|
int passwordMaskDelay = -1;
|
|
|
|
QString passwordCharacter;
|
|
|
|
|
|
|
|
if ( auto textInput = qobject_cast< QskTextInput* >( inputItem ) )
|
|
|
|
{
|
|
|
|
passwordMaskDelay = textInput->passwordMaskDelay();
|
|
|
|
passwordCharacter = textInput->passwordCharacter();
|
|
|
|
|
|
|
|
if ( inputProxy->echoMode() == QskTextInput::NoEcho )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Qt::ImhHiddenText does not provide information
|
|
|
|
to decide between NoEcho/Password
|
|
|
|
*/
|
|
|
|
auto mode = textInput->echoMode();
|
|
|
|
if ( mode == QskTextInput::Password )
|
|
|
|
inputProxy->setEchoMode( mode );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( passwordMaskDelay >= 0 )
|
|
|
|
inputProxy->setPasswordMaskDelay( passwordMaskDelay );
|
|
|
|
else
|
|
|
|
inputProxy->resetPasswordMaskDelay();
|
|
|
|
|
|
|
|
if ( !passwordCharacter.isEmpty() )
|
|
|
|
inputProxy->setPasswordCharacter( passwordCharacter );
|
|
|
|
else
|
|
|
|
inputProxy->resetPasswordCharacter();
|
|
|
|
}
|
|
|
|
|
2018-04-18 19:41:46 +02:00
|
|
|
namespace
|
|
|
|
{
|
2018-04-30 10:03:51 +02:00
|
|
|
class TextInputProxy final : public QskTextInput
|
2018-04-18 19:41:46 +02:00
|
|
|
{
|
|
|
|
public:
|
2018-04-30 10:03:51 +02:00
|
|
|
TextInputProxy( QQuickItem* parentItem = nullptr ):
|
2018-04-18 19:41:46 +02:00
|
|
|
QskTextInput( parentItem )
|
|
|
|
{
|
2018-04-27 13:48:51 +02:00
|
|
|
setObjectName( "InputPanelInputProxy" );
|
2018-04-30 10:03:51 +02:00
|
|
|
#if 1
|
2018-04-27 16:55:50 +02:00
|
|
|
setFocusPolicy( Qt::NoFocus );
|
2018-04-30 10:03:51 +02:00
|
|
|
#endif
|
2018-04-27 16:55:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void focusInEvent( QFocusEvent* ) override final
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void focusOutEvent( QFocusEvent* ) override final
|
|
|
|
{
|
2018-04-18 19:41:46 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
QSK_SUBCONTROL( QskInputPanel, Panel )
|
|
|
|
|
2018-04-10 16:51:35 +02:00
|
|
|
class QskInputPanel::PrivateData
|
|
|
|
{
|
|
|
|
public:
|
2018-04-18 19:41:46 +02:00
|
|
|
PrivateData():
|
2018-04-27 13:48:51 +02:00
|
|
|
inputHints( 0 ),
|
|
|
|
maxChars( -1 ),
|
|
|
|
hasPrediction( true ),
|
2018-04-18 19:41:46 +02:00
|
|
|
hasInputProxy( true )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-04-27 13:48:51 +02:00
|
|
|
QQuickItem* receiverItem()
|
|
|
|
{
|
|
|
|
return hasInputProxy ? inputProxy : inputItem;
|
|
|
|
}
|
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
QPointer< QskInputEngine > engine;
|
|
|
|
QPointer< QQuickItem > inputItem;
|
|
|
|
|
2018-04-12 12:03:51 +02:00
|
|
|
QskLinearBox* layout;
|
2018-04-18 19:41:46 +02:00
|
|
|
QskTextLabel* prompt;
|
2018-04-30 10:03:51 +02:00
|
|
|
TextInputProxy* inputProxy;
|
2018-04-26 14:42:33 +02:00
|
|
|
QskInputPredictionBar* predictionBar;
|
2018-04-10 16:51:35 +02:00
|
|
|
QskVirtualKeyboard* keyboard;
|
2018-04-18 19:41:46 +02:00
|
|
|
|
2018-04-27 13:48:51 +02:00
|
|
|
Qt::InputMethodHints inputHints;
|
|
|
|
int maxChars;
|
|
|
|
|
|
|
|
bool hasPrediction : 1;
|
2018-04-18 19:41:46 +02:00
|
|
|
bool hasInputProxy : 1;
|
2018-04-10 16:51:35 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
QskInputPanel::QskInputPanel( QQuickItem* parent ):
|
2018-04-18 19:41:46 +02:00
|
|
|
Inherited( parent ),
|
2018-04-10 16:51:35 +02:00
|
|
|
m_data( new PrivateData() )
|
|
|
|
{
|
|
|
|
setAutoLayoutChildren( true );
|
2018-04-12 12:03:51 +02:00
|
|
|
initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Constrained );
|
2018-04-10 16:51:35 +02:00
|
|
|
|
2018-04-18 19:41:46 +02:00
|
|
|
m_data->prompt = new QskTextLabel();
|
|
|
|
m_data->prompt->setVisible( false );
|
|
|
|
|
2018-04-30 10:03:51 +02:00
|
|
|
m_data->inputProxy = new TextInputProxy();
|
2018-04-23 14:06:40 +02:00
|
|
|
m_data->inputProxy->setVisible( m_data->hasInputProxy );
|
2018-04-10 16:51:35 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
m_data->predictionBar = new QskInputPredictionBar();
|
|
|
|
m_data->predictionBar->setVisible( false );
|
2018-04-10 16:51:35 +02:00
|
|
|
|
2018-04-18 19:41:46 +02:00
|
|
|
m_data->keyboard = new QskVirtualKeyboard();
|
|
|
|
|
|
|
|
auto layout = new QskLinearBox( Qt::Vertical, this );
|
|
|
|
|
|
|
|
layout->addItem( m_data->prompt, Qt::AlignLeft | Qt::AlignHCenter );
|
2018-04-23 14:06:40 +02:00
|
|
|
layout->addItem( m_data->inputProxy, Qt::AlignLeft | Qt::AlignHCenter );
|
2018-04-18 19:41:46 +02:00
|
|
|
layout->addStretch( 10 );
|
2018-04-26 14:42:33 +02:00
|
|
|
layout->addItem( m_data->predictionBar );
|
2018-04-18 19:41:46 +02:00
|
|
|
layout->addItem( m_data->keyboard );
|
|
|
|
|
|
|
|
m_data->layout = layout;
|
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
connect( m_data->predictionBar, &QskInputPredictionBar::predictiveTextSelected,
|
|
|
|
this, &QskInputPanel::commitPredictiveText );
|
2018-04-10 16:51:35 +02:00
|
|
|
|
|
|
|
connect( m_data->keyboard, &QskVirtualKeyboard::keySelected,
|
|
|
|
this, &QskInputPanel::commitKey );
|
|
|
|
}
|
|
|
|
|
|
|
|
QskInputPanel::~QskInputPanel()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
void QskInputPanel::setEngine( QskInputEngine* engine )
|
2018-04-12 12:03:51 +02:00
|
|
|
{
|
2018-04-26 14:42:33 +02:00
|
|
|
if ( engine == m_data->engine )
|
|
|
|
return;
|
2018-04-18 19:41:46 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
if ( m_data->engine )
|
|
|
|
m_data->engine->disconnect( this );
|
2018-04-18 19:41:46 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
m_data->engine = engine;
|
2018-04-12 12:03:51 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
if ( engine )
|
2018-04-12 12:03:51 +02:00
|
|
|
{
|
2018-04-26 14:42:33 +02:00
|
|
|
connect( engine, &QskInputEngine::predictionChanged,
|
2018-05-01 11:52:29 +02:00
|
|
|
this, &QskInputPanel::updatePrediction );
|
2018-04-12 12:03:51 +02:00
|
|
|
}
|
|
|
|
|
2018-04-27 13:48:51 +02:00
|
|
|
m_data->predictionBar->setVisible(
|
|
|
|
m_data->hasPrediction && engine && engine->predictor() );
|
2018-04-12 12:03:51 +02:00
|
|
|
}
|
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
void QskInputPanel::attachInputItem( QQuickItem* item )
|
2018-04-12 12:03:51 +02:00
|
|
|
{
|
2018-04-26 14:42:33 +02:00
|
|
|
if ( item == m_data->inputItem )
|
|
|
|
return;
|
2018-04-12 12:03:51 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
m_data->inputItem = item;
|
2018-04-12 12:03:51 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
if ( m_data->engine )
|
|
|
|
m_data->engine->reset();
|
2018-04-18 19:41:46 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
if ( item )
|
2018-04-12 12:03:51 +02:00
|
|
|
{
|
2018-04-26 14:42:33 +02:00
|
|
|
Qt::InputMethodQueries queries = Qt::ImQueryAll;
|
|
|
|
queries &= ~Qt::ImEnabled;
|
|
|
|
|
|
|
|
processInputMethodQueries( queries );
|
2018-04-27 13:48:51 +02:00
|
|
|
|
|
|
|
if ( m_data->hasInputProxy )
|
2018-04-27 16:55:50 +02:00
|
|
|
{
|
2018-04-27 13:48:51 +02:00
|
|
|
m_data->inputProxy->setEditing( true );
|
2018-04-27 16:55:50 +02:00
|
|
|
|
|
|
|
// hiding the cursor in the real input 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
|
|
|
|
qskSyncInputProxy( item, m_data->inputProxy );
|
|
|
|
}
|
2018-04-12 12:03:51 +02:00
|
|
|
}
|
2018-04-26 14:42:33 +02:00
|
|
|
}
|
2018-04-12 12:03:51 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
QQuickItem* QskInputPanel::attachedInputItem() const
|
|
|
|
{
|
|
|
|
return m_data->inputItem;
|
|
|
|
}
|
2018-04-18 19:41:46 +02:00
|
|
|
|
2018-05-01 11:52:29 +02:00
|
|
|
void QskInputPanel::updatePrediction()
|
2018-04-26 14:42:33 +02:00
|
|
|
{
|
|
|
|
m_data->predictionBar->setPrediction(
|
|
|
|
m_data->engine->prediction() );
|
|
|
|
}
|
2018-04-12 12:03:51 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
QskInputEngine* QskInputPanel::engine()
|
|
|
|
{
|
|
|
|
return m_data->engine;
|
|
|
|
}
|
|
|
|
|
|
|
|
QskAspect::Subcontrol QskInputPanel::effectiveSubcontrol(
|
|
|
|
QskAspect::Subcontrol subControl ) const
|
|
|
|
{
|
|
|
|
if( subControl == QskBox::Panel )
|
|
|
|
return QskInputPanel::Panel;
|
|
|
|
|
|
|
|
return subControl;
|
2018-04-12 12:03:51 +02:00
|
|
|
}
|
|
|
|
|
2018-04-18 19:41:46 +02:00
|
|
|
QString QskInputPanel::inputPrompt() const
|
|
|
|
{
|
|
|
|
return m_data->prompt->text();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskInputPanel::setInputPrompt( const QString& text )
|
|
|
|
{
|
|
|
|
auto prompt = m_data->prompt;
|
|
|
|
|
|
|
|
if ( text != prompt->text() )
|
|
|
|
{
|
|
|
|
prompt->setText( text );
|
|
|
|
|
|
|
|
if ( m_data->hasInputProxy )
|
|
|
|
prompt->setVisible( !text.isEmpty() );
|
|
|
|
|
|
|
|
Q_EMIT inputPromptChanged( text );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskInputPanel::hasInputProxy() const
|
|
|
|
{
|
|
|
|
return m_data->hasInputProxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskInputPanel::setInputProxy( bool on )
|
|
|
|
{
|
|
|
|
if ( m_data->hasInputProxy == on )
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_data->hasInputProxy = on;
|
2018-04-23 14:06:40 +02:00
|
|
|
m_data->inputProxy->setVisible( on );
|
2018-04-18 19:41:46 +02:00
|
|
|
|
|
|
|
auto prompt = m_data->prompt;
|
|
|
|
|
|
|
|
if ( on )
|
|
|
|
prompt->setVisible( !prompt->text().isEmpty() );
|
|
|
|
else
|
|
|
|
prompt->setVisible( false );
|
|
|
|
}
|
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
void QskInputPanel::commitPredictiveText( int index )
|
2018-04-10 16:51:35 +02:00
|
|
|
{
|
2018-05-01 11:52:29 +02:00
|
|
|
m_data->predictionBar->setPrediction( QStringList() );
|
2018-04-10 16:51:35 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
if ( m_data->engine )
|
|
|
|
{
|
|
|
|
const QString text = m_data->engine->predictiveText( index );
|
2018-04-30 10:03:51 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
m_data->engine->reset();
|
2018-04-30 10:03:51 +02:00
|
|
|
qskSendText( m_data->receiverItem(), text, true );
|
2018-04-26 14:42:33 +02:00
|
|
|
}
|
2018-04-10 16:51:35 +02:00
|
|
|
}
|
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
void QskInputPanel::commitKey( int key )
|
2018-04-10 16:51:35 +02:00
|
|
|
{
|
2018-04-26 14:42:33 +02:00
|
|
|
if ( m_data->engine == nullptr || m_data->inputItem == nullptr )
|
|
|
|
return;
|
|
|
|
|
|
|
|
int spaceLeft = -1;
|
|
|
|
|
2018-04-27 13:48:51 +02:00
|
|
|
if ( !( m_data->inputHints & Qt::ImhMultiLine ) )
|
2018-04-26 14:42:33 +02:00
|
|
|
{
|
2018-04-27 13:48:51 +02:00
|
|
|
auto receiver = m_data->receiverItem();
|
2018-04-26 14:42:33 +02:00
|
|
|
|
2018-04-27 13:48:51 +02:00
|
|
|
if ( m_data->maxChars >= 0 )
|
2018-04-26 14:42:33 +02:00
|
|
|
{
|
2018-04-27 13:48:51 +02:00
|
|
|
QInputMethodQueryEvent event( Qt::ImSurroundingText );
|
|
|
|
QCoreApplication::sendEvent( receiver, &event );
|
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
const auto text = event.value( Qt::ImSurroundingText ).toString();
|
2018-04-27 13:48:51 +02:00
|
|
|
spaceLeft = m_data->maxChars - text.length();
|
2018-04-26 14:42:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-27 13:48:51 +02:00
|
|
|
processKey( key, m_data->inputHints, spaceLeft );
|
2018-04-10 16:51:35 +02:00
|
|
|
}
|
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
void QskInputPanel::processKey( int key,
|
|
|
|
Qt::InputMethodHints inputHints, int spaceLeft )
|
2018-04-10 16:51:35 +02:00
|
|
|
{
|
2018-04-26 14:42:33 +02:00
|
|
|
const auto result = m_data->engine->processKey( key, inputHints, spaceLeft );
|
|
|
|
|
|
|
|
auto inputItem = m_data->inputItem;
|
2018-04-10 16:51:35 +02:00
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
if ( result.key )
|
|
|
|
{
|
2018-04-27 13:48:51 +02:00
|
|
|
switch( result.key )
|
|
|
|
{
|
|
|
|
case Qt::Key_Return:
|
|
|
|
{
|
2018-05-09 08:20:59 +02:00
|
|
|
done( true );
|
2018-04-27 13:48:51 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Qt::Key_Escape:
|
|
|
|
{
|
2018-05-09 08:20:59 +02:00
|
|
|
done( false );
|
2018-04-27 13:48:51 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
qskSendKey( m_data->receiverItem(), result.key );
|
|
|
|
}
|
|
|
|
}
|
2018-04-26 14:42:33 +02:00
|
|
|
}
|
|
|
|
else if ( !result.text.isEmpty() )
|
|
|
|
{
|
|
|
|
// changing the current text
|
2018-04-27 13:48:51 +02:00
|
|
|
qskSendText( m_data->receiverItem(), result.text, result.isFinal );
|
2018-04-26 14:42:33 +02:00
|
|
|
}
|
2018-04-10 16:51:35 +02:00
|
|
|
}
|
|
|
|
|
2018-05-09 08:20:59 +02:00
|
|
|
void QskInputPanel::done( bool success )
|
|
|
|
{
|
|
|
|
if ( success )
|
|
|
|
{
|
|
|
|
if ( m_data->hasInputProxy )
|
|
|
|
qskSendReplaceText( m_data->inputItem, m_data->inputProxy->text() );
|
|
|
|
}
|
|
|
|
|
|
|
|
qskSendKey( m_data->inputItem,
|
|
|
|
success ? Qt::Key_Return : Qt::Key_Escape );
|
|
|
|
}
|
|
|
|
|
2018-04-26 14:42:33 +02:00
|
|
|
void QskInputPanel::processInputMethodQueries( Qt::InputMethodQueries queries )
|
2018-04-10 16:51:35 +02:00
|
|
|
{
|
2018-04-26 14:42:33 +02:00
|
|
|
if ( m_data->inputItem == nullptr )
|
|
|
|
return;
|
|
|
|
|
2018-04-27 13:48:51 +02:00
|
|
|
QInputMethodQueryEvent event( queries );
|
|
|
|
QCoreApplication::sendEvent( m_data->inputItem, &event );
|
2018-04-26 14:42:33 +02:00
|
|
|
|
2018-04-27 16:55:50 +02:00
|
|
|
if ( event.queries() & Qt::ImHints )
|
2018-04-26 14:42:33 +02:00
|
|
|
{
|
2018-04-27 13:48:51 +02:00
|
|
|
bool hasPrediction = true;
|
2018-04-27 16:55:50 +02:00
|
|
|
QskTextInput::EchoMode echoMode = QskTextInput::Normal;
|
2018-04-26 14:42:33 +02:00
|
|
|
|
|
|
|
const auto hints = static_cast< Qt::InputMethodHints >(
|
2018-04-27 13:48:51 +02:00
|
|
|
event.value( Qt::ImHints ).toInt() );
|
2018-04-26 14:42:33 +02:00
|
|
|
|
2018-04-27 13:48:51 +02:00
|
|
|
if ( hints & Qt::ImhHiddenText )
|
|
|
|
{
|
2018-04-27 16:55:50 +02:00
|
|
|
echoMode = QskTextInput::NoEcho;
|
2018-04-27 13:48:51 +02:00
|
|
|
}
|
|
|
|
|
2018-06-01 09:45:02 +02:00
|
|
|
/*
|
|
|
|
- Qt::ImhSensitiveData
|
|
|
|
- Qt::ImhNoAutoUppercase
|
|
|
|
- Qt::ImhMultiLine
|
2018-04-27 13:48:51 +02:00
|
|
|
|
2018-06-01 09:45:02 +02:00
|
|
|
// we should start in a specific mode
|
2018-04-27 13:48:51 +02:00
|
|
|
|
2018-06-01 09:45:02 +02:00
|
|
|
- Qt::ImhPreferNumbers
|
|
|
|
- Qt::ImhPreferUppercase
|
|
|
|
- Qt::ImhPreferLowercase
|
|
|
|
- Qt::ImhPreferLatin
|
2018-04-27 13:48:51 +02:00
|
|
|
|
2018-06-01 09:45:02 +02:00
|
|
|
// we should lock all other modes
|
2018-04-27 13:48:51 +02:00
|
|
|
|
2018-06-01 09:45:02 +02:00
|
|
|
- Qt::ImhFormattedNumbersOnly
|
|
|
|
- Qt::ImhUppercaseOnly
|
|
|
|
- Qt::ImhDialableCharactersOnly
|
|
|
|
- Qt::ImhEmailCharactersOnly
|
|
|
|
- Qt::ImhUrlCharactersOnly
|
|
|
|
- Qt::ImhLatinOnly
|
2018-04-27 13:48:51 +02:00
|
|
|
|
2018-06-01 09:45:02 +02:00
|
|
|
// we should have specific input panels
|
2018-04-27 13:48:51 +02:00
|
|
|
|
2018-06-01 09:45:02 +02:00
|
|
|
- Qt::ImhDate
|
|
|
|
- Qt::ImhTime
|
|
|
|
- Qt::ImhDigitsOnly
|
|
|
|
- Qt::ImhFormattedNumbersOnly
|
|
|
|
*/
|
2018-04-27 13:48:51 +02:00
|
|
|
|
2018-06-01 09:45:02 +02:00
|
|
|
m_data->hasPrediction =
|
|
|
|
!( hints & ( Qt::ImhNoPredictiveText | Qt::ImhExclusiveInputMask ) );
|
2018-04-27 13:48:51 +02:00
|
|
|
|
|
|
|
m_data->predictionBar->setVisible(
|
|
|
|
hasPrediction && m_data->engine && m_data->engine->predictor() );
|
|
|
|
|
2018-04-27 16:55:50 +02:00
|
|
|
m_data->inputProxy->setEchoMode( echoMode );
|
2018-04-27 13:48:51 +02:00
|
|
|
|
|
|
|
m_data->inputHints = hints;
|
2018-04-26 14:42:33 +02:00
|
|
|
}
|
|
|
|
|
2018-04-27 16:55:50 +02:00
|
|
|
if ( event.queries() & Qt::ImPreferredLanguage )
|
2018-04-26 14:42:33 +02:00
|
|
|
{
|
2018-04-27 13:48:51 +02:00
|
|
|
// already handled by the input context
|
2018-04-26 14:42:33 +02:00
|
|
|
}
|
2018-04-27 13:48:51 +02:00
|
|
|
|
2018-04-27 16:55:50 +02:00
|
|
|
if ( event.queries() & Qt::ImMaximumTextLength )
|
2018-04-27 13:48:51 +02:00
|
|
|
{
|
|
|
|
// 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;
|
2018-04-26 14:42:33 +02:00
|
|
|
#endif
|
|
|
|
|
2018-04-27 13:48:51 +02:00
|
|
|
if ( m_data->hasInputProxy )
|
|
|
|
m_data->inputProxy->setMaxLength( m_data->maxChars );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-27 16:55:50 +02:00
|
|
|
if ( event.queries() & Qt::ImSurroundingText )
|
2018-04-27 13:48:51 +02:00
|
|
|
{
|
|
|
|
if ( m_data->hasInputProxy )
|
|
|
|
{
|
|
|
|
const auto text = event.value( Qt::ImSurroundingText ).toString();
|
|
|
|
m_data->inputProxy->setText( text );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-27 16:55:50 +02:00
|
|
|
if ( event.queries() & Qt::ImCursorPosition )
|
2018-04-27 13:48:51 +02:00
|
|
|
{
|
|
|
|
if ( m_data->hasInputProxy )
|
|
|
|
{
|
|
|
|
const auto pos = event.value( Qt::ImCursorPosition ).toInt();
|
|
|
|
m_data->inputProxy->setCursorPosition( pos );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-27 16:55:50 +02:00
|
|
|
if ( event.queries() & Qt::ImCurrentSelection )
|
2018-04-27 13:48:51 +02:00
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
const auto text = event.value( Qt::ImCurrentSelection ).toString();
|
|
|
|
if ( !text.isEmpty() )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2018-04-26 14:42:33 +02:00
|
|
|
/*
|
|
|
|
Qt::ImMicroFocus
|
|
|
|
Qt::ImCursorRectangle
|
|
|
|
Qt::ImFont
|
|
|
|
Qt::ImAnchorPosition
|
|
|
|
|
|
|
|
Qt::ImAbsolutePosition
|
2018-04-27 13:48:51 +02:00
|
|
|
Qt::ImTextBeforeCursor
|
|
|
|
Qt::ImTextAfterCursor
|
2018-04-26 14:42:33 +02:00
|
|
|
Qt::ImPlatformData // hard to say...
|
|
|
|
Qt::ImEnterKeyType
|
|
|
|
Qt::ImAnchorRectangle
|
2018-04-27 13:48:51 +02:00
|
|
|
Qt::ImInputItemClipRectangle
|
2018-04-26 14:42:33 +02:00
|
|
|
*/
|
2018-04-10 16:51:35 +02:00
|
|
|
}
|
|
|
|
|
2018-04-13 16:32:48 +02:00
|
|
|
void QskInputPanel::keyPressEvent( QKeyEvent* event )
|
|
|
|
{
|
|
|
|
// animate the corresponding key button TODO
|
|
|
|
|
|
|
|
switch( event->key() )
|
|
|
|
{
|
|
|
|
case Qt::Key_Return:
|
|
|
|
case Qt::Key_Escape:
|
|
|
|
{
|
|
|
|
commitKey( event->key() );
|
|
|
|
break;
|
|
|
|
}
|
2018-04-30 10:03:51 +02:00
|
|
|
|
|
|
|
case Qt::Key_Shift:
|
|
|
|
case Qt::Key_Control:
|
|
|
|
case Qt::Key_Meta:
|
|
|
|
case Qt::Key_Alt:
|
|
|
|
case Qt::Key_AltGr:
|
|
|
|
case Qt::Key_CapsLock:
|
|
|
|
case Qt::Key_NumLock:
|
|
|
|
case Qt::Key_ScrollLock:
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2018-04-13 16:32:48 +02:00
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
const auto text = event->text();
|
|
|
|
if ( !text.isEmpty() )
|
|
|
|
commitKey( text[0].unicode() );
|
|
|
|
else
|
|
|
|
commitKey( event->key() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskInputPanel::keyReleaseEvent( QKeyEvent* event )
|
|
|
|
{
|
|
|
|
return Inherited::keyReleaseEvent( event );
|
|
|
|
}
|
|
|
|
|
2018-04-10 16:51:35 +02:00
|
|
|
#include "moc_QskInputPanel.cpp"
|