more keyboard refactoring
This commit is contained in:
parent
66677067d5
commit
bcd0bc94c0
|
@ -23,14 +23,18 @@ static QString qskKeyString( int code )
|
|||
case Qt::Key_Backspace:
|
||||
case Qt::Key_Muhenkan:
|
||||
return QString();
|
||||
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Kanji:
|
||||
return QChar( QChar::CarriageReturn );
|
||||
|
||||
case Qt::Key_Space:
|
||||
return QChar( QChar::Space );
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QChar( code );
|
||||
}
|
||||
|
||||
|
@ -51,6 +55,14 @@ public:
|
|||
int groupIndex;
|
||||
};
|
||||
|
||||
static inline void sendCompositionEvent( QInputMethodEvent* e )
|
||||
{
|
||||
if( auto focusObject = QGuiApplication::focusObject() )
|
||||
{
|
||||
QCoreApplication::sendEvent( focusObject, e );
|
||||
}
|
||||
}
|
||||
|
||||
QskInputCompositionModel::QskInputCompositionModel():
|
||||
m_data( new PrivateData )
|
||||
{
|
||||
|
@ -67,6 +79,13 @@ QskInputCompositionModel::~QskInputCompositionModel()
|
|||
|
||||
void QskInputCompositionModel::composeKey( Qt::Key key )
|
||||
{
|
||||
/*
|
||||
* This operation might be expensive (e.g. for Hunspell) and
|
||||
* should be done asynchronously to be able to run e.g. suggestions
|
||||
* in a separate thread to not block the UI.
|
||||
* TODO
|
||||
*/
|
||||
|
||||
auto inputMethod = QGuiApplication::inputMethod();
|
||||
if ( !inputMethod )
|
||||
return;
|
||||
|
@ -97,21 +116,19 @@ void QskInputCompositionModel::composeKey( Qt::Key key )
|
|||
case Qt::Key_Space:
|
||||
{
|
||||
if( !spaceLeft )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( !m_data->preedit.isEmpty() )
|
||||
{
|
||||
if ( candidateCount() > 0 ) // Commit first candidate
|
||||
commit( QChar( candidate( 0 ) ) );
|
||||
else // Commit what is in the buffer
|
||||
commit( m_data->preedit.left( spaceLeft ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
commit( qskKeyString( key ) );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case Qt::Key_Return:
|
||||
{
|
||||
if ( !spaceLeft )
|
||||
|
@ -119,12 +136,30 @@ void QskInputCompositionModel::composeKey( Qt::Key key )
|
|||
|
||||
// Commit what is in the buffer
|
||||
if( !m_data->preedit.isEmpty() )
|
||||
{
|
||||
commit( m_data->preedit.left( spaceLeft ) );
|
||||
}
|
||||
else if( hints & Qt::ImhMultiLine )
|
||||
{
|
||||
commit( qskKeyString( key ) );
|
||||
}
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
auto focusWindow = QGuiApplication::focusWindow();
|
||||
|
||||
if( focusWindow )
|
||||
{
|
||||
QKeyEvent keyPress( QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier );
|
||||
QKeyEvent keyRelease( QEvent::KeyRelease, Qt::Key_Return, Qt::NoModifier ); QCoreApplication::sendEvent( focusWindow, &keyPress );
|
||||
QCoreApplication::sendEvent( focusWindow, &keyRelease );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
case Qt::Key_Left:
|
||||
case Qt::Key_Right:
|
||||
{
|
||||
|
@ -169,6 +204,7 @@ void QskInputCompositionModel::composeKey( Qt::Key key )
|
|||
|
||||
m_data->preedit = qskKeyString( key );
|
||||
displayPreedit = polishPreedit( m_data->preedit );
|
||||
|
||||
if ( !hasIntermediate() )
|
||||
{
|
||||
commit( m_data->preedit );
|
||||
|
@ -258,7 +294,6 @@ void QskInputCompositionModel::moveCursor( Qt::Key key )
|
|||
if ( !m_data->preedit.isEmpty() )
|
||||
return;
|
||||
|
||||
// ### this should be in the panel:
|
||||
QKeyEvent moveCursorPress( QEvent::KeyPress, key, Qt::NoModifier );
|
||||
QKeyEvent moveCursorRelease( QEvent::KeyRelease, key, Qt::NoModifier );
|
||||
#if 1
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
virtual ~QskInputCompositionModel();
|
||||
|
||||
void commit( const QString& );
|
||||
void commitCandidate( int );
|
||||
virtual void commitCandidate( int );
|
||||
void composeKey( Qt::Key );
|
||||
|
||||
void clearPreedit();
|
||||
|
|
|
@ -14,20 +14,19 @@
|
|||
#include <QskSetup.h>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlEngine>
|
||||
#include <QQuickItem>
|
||||
#include <QQuickWindow>
|
||||
#include <QRectF>
|
||||
|
||||
QskInputContext::QskInputContext():
|
||||
Inherited(),
|
||||
m_inputCompositionModel( new QskInputCompositionModel )
|
||||
m_defaultInputCompositionModel( new QskInputCompositionModel )
|
||||
{
|
||||
connect( qskSetup, &QskSetup::inputPanelChanged,
|
||||
this, &QskInputContext::setInputPanel );
|
||||
setInputPanel( qskSetup->inputPanel() );
|
||||
|
||||
QskPinyinCompositionModel* pinyinModel = new QskPinyinCompositionModel;
|
||||
// For input methods outside skinny, call QskInputPanel::registerCompositionModelForLocale()
|
||||
inputMethodRegistered( QLocale::Chinese, pinyinModel );
|
||||
|
||||
// We could connect candidatesChanged() here, but we don't emit
|
||||
// the signal in the normal composition model anyhow
|
||||
}
|
||||
|
@ -36,6 +35,11 @@ QskInputContext::~QskInputContext()
|
|||
{
|
||||
if ( m_inputPanel )
|
||||
delete m_inputPanel;
|
||||
|
||||
for( int a = 0; a < m_inputModels.values().count(); a++ )
|
||||
{
|
||||
delete m_inputModels.values()[a];
|
||||
}
|
||||
}
|
||||
|
||||
bool QskInputContext::isValid() const
|
||||
|
@ -93,40 +97,30 @@ void QskInputContext::update( Qt::InputMethodQueries queries )
|
|||
if ( queries & Qt::ImPreferredLanguage )
|
||||
{
|
||||
const auto locale = queryEvent.value( Qt::ImPreferredLanguage ).toLocale();
|
||||
|
||||
auto oldModel = currentInputCompositionModel();
|
||||
|
||||
if( m_inputPanel )
|
||||
m_inputPanel->setLocale( locale );
|
||||
|
||||
auto modelChanged = false;
|
||||
const bool currentModelIsPinyin =
|
||||
dynamic_cast< QskPinyinCompositionModel* >( m_inputCompositionModel.get() );
|
||||
const bool localeIsChinese = locale.language() == QLocale::Chinese;
|
||||
if ( localeIsChinese && !currentModelIsPinyin )
|
||||
auto newModel = currentInputCompositionModel();
|
||||
|
||||
bool modelChanged = ( oldModel != newModel );
|
||||
|
||||
if( modelChanged )
|
||||
{
|
||||
if( m_inputPanel )
|
||||
m_inputPanel->disconnect( m_inputCompositionModel.get() );
|
||||
|
||||
m_inputCompositionModel.reset( new QskPinyinCompositionModel );
|
||||
modelChanged = true;
|
||||
}
|
||||
else if ( !m_inputCompositionModel || ( !localeIsChinese && currentModelIsPinyin ) ) // Install default
|
||||
{
|
||||
if ( m_inputPanel )
|
||||
m_inputPanel->disconnect( m_inputCompositionModel.get() );
|
||||
|
||||
m_inputCompositionModel.reset( new QskInputCompositionModel );
|
||||
modelChanged = true;
|
||||
}
|
||||
|
||||
if ( modelChanged && m_inputPanel )
|
||||
{
|
||||
m_inputPanel->disconnect( oldModel );
|
||||
QObject::connect(
|
||||
m_inputCompositionModel.get(), &QskInputCompositionModel::groupsChanged,
|
||||
newModel, &QskInputCompositionModel::groupsChanged,
|
||||
m_inputPanel.data(), &QskVirtualKeyboard::setPreeditGroups );
|
||||
QObject::connect(
|
||||
m_inputCompositionModel.get(), &QskInputCompositionModel::candidatesChanged,
|
||||
newModel, &QskInputCompositionModel::candidatesChanged,
|
||||
this, &QskInputContext::handleCandidatesChanged );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Qt::ImAbsolutePosition
|
||||
// Qt::ImTextBeforeCursor // important for chinese
|
||||
|
@ -212,7 +206,7 @@ void QskInputContext::setFocusObject( QObject* focusObject )
|
|||
if ( !m_focusObject )
|
||||
{
|
||||
m_inputItem = nullptr;
|
||||
m_inputCompositionModel->setInputItem( nullptr );
|
||||
currentInputCompositionModel()->setInputItem( nullptr );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -225,7 +219,7 @@ void QskInputContext::setFocusObject( QObject* focusObject )
|
|||
if( qskNearestFocusScope( focusQuickItem ) != m_inputPanel )
|
||||
{
|
||||
m_inputItem = focusQuickItem;
|
||||
m_inputCompositionModel->setInputItem( m_inputItem ); // ### use a signal/slot connection
|
||||
currentInputCompositionModel()->setInputItem( m_inputItem ); // ### use a signal/slot connection
|
||||
inputItemChanged = true;
|
||||
}
|
||||
}
|
||||
|
@ -246,6 +240,28 @@ void QskInputContext::setFocusObject( QObject* focusObject )
|
|||
update( Qt::InputMethodQuery( Qt::ImQueryAll & ~Qt::ImEnabled ) );
|
||||
}
|
||||
|
||||
void QskInputContext::inputMethodRegistered( const QLocale& locale, QskInputCompositionModel* model )
|
||||
{
|
||||
auto oldModel = m_inputModels.value( locale, nullptr );
|
||||
|
||||
if( oldModel != nullptr )
|
||||
{
|
||||
oldModel->deleteLater();
|
||||
}
|
||||
|
||||
m_inputModels.insert( locale, model );
|
||||
}
|
||||
|
||||
QskInputCompositionModel* QskInputContext::compositionModelForLocale( const QLocale& locale ) const
|
||||
{
|
||||
return m_inputModels.value( locale, m_defaultInputCompositionModel );
|
||||
}
|
||||
|
||||
QskInputCompositionModel* QskInputContext::currentInputCompositionModel() const
|
||||
{
|
||||
return m_inputModels.value( locale(), m_defaultInputCompositionModel );
|
||||
}
|
||||
|
||||
void QskInputContext::invokeAction( QInputMethod::Action action, int cursorPosition )
|
||||
{
|
||||
Q_UNUSED( cursorPosition );
|
||||
|
@ -256,13 +272,15 @@ void QskInputContext::invokeAction( QInputMethod::Action action, int cursorPosit
|
|||
switch ( static_cast< QskVirtualKeyboard::Action >( action ) )
|
||||
{
|
||||
case QskVirtualKeyboard::Compose:
|
||||
m_inputCompositionModel->composeKey( static_cast< Qt::Key >( cursorPosition ) );
|
||||
currentInputCompositionModel()->composeKey( static_cast< Qt::Key >( cursorPosition ) );
|
||||
break;
|
||||
|
||||
case QskVirtualKeyboard::SelectGroup:
|
||||
m_inputCompositionModel->setGroupIndex( cursorPosition );
|
||||
currentInputCompositionModel()->setGroupIndex( cursorPosition );
|
||||
break;
|
||||
|
||||
case QskVirtualKeyboard::SelectCandidate:
|
||||
m_inputCompositionModel->commitCandidate( cursorPosition );
|
||||
currentInputCompositionModel()->commitCandidate( cursorPosition );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -274,10 +292,11 @@ void QskInputContext::emitAnimatingChanged()
|
|||
|
||||
void QskInputContext::handleCandidatesChanged()
|
||||
{
|
||||
QVector< Qt::Key > candidates( m_inputCompositionModel->candidateCount() );
|
||||
QVector< Qt::Key > candidates( currentInputCompositionModel()->candidateCount() );
|
||||
|
||||
for( int i = 0; i < candidates.length(); ++i )
|
||||
{
|
||||
candidates[i] = static_cast< Qt::Key >( m_inputCompositionModel->candidate( i ) );
|
||||
candidates[i] = currentInputCompositionModel()->candidate( i );
|
||||
}
|
||||
|
||||
m_inputPanel->setPreeditCandidates( candidates );
|
||||
|
@ -296,8 +315,8 @@ void QskInputContext::setInputPanel( QskVirtualKeyboard* inputPanel )
|
|||
this, &QPlatformInputContext::emitKeyboardRectChanged );
|
||||
QObject::disconnect( m_inputPanel, &QskVirtualKeyboard::localeChanged,
|
||||
this, &QPlatformInputContext::emitLocaleChanged );
|
||||
if ( m_inputCompositionModel )
|
||||
m_inputPanel->disconnect( m_inputCompositionModel.get() );
|
||||
if ( currentInputCompositionModel() )
|
||||
m_inputPanel->disconnect( currentInputCompositionModel() );
|
||||
}
|
||||
|
||||
m_inputPanel = inputPanel;
|
||||
|
@ -310,10 +329,10 @@ void QskInputContext::setInputPanel( QskVirtualKeyboard* inputPanel )
|
|||
this, &QPlatformInputContext::emitKeyboardRectChanged );
|
||||
QObject::connect( m_inputPanel, &QskVirtualKeyboard::localeChanged,
|
||||
this, &QPlatformInputContext::emitLocaleChanged );
|
||||
if ( m_inputCompositionModel )
|
||||
if ( currentInputCompositionModel() )
|
||||
{
|
||||
QObject::connect(
|
||||
m_inputCompositionModel.get(), &QskInputCompositionModel::groupsChanged,
|
||||
currentInputCompositionModel(), &QskInputCompositionModel::groupsChanged,
|
||||
m_inputPanel.data(), &QskVirtualKeyboard::setPreeditGroups );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
#define QSK_INPUT_CONTEXT_H
|
||||
|
||||
#include <qpa/qplatforminputcontext.h>
|
||||
#include <QPointer>
|
||||
#include <QHash>
|
||||
#include <QQuickItem>
|
||||
#include <QPointer>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -36,16 +37,22 @@ public:
|
|||
QLocale locale() const override;
|
||||
void setFocusObject( QObject* ) override;
|
||||
|
||||
QskInputCompositionModel* compositionModelForLocale( const QLocale& locale ) const;
|
||||
|
||||
private Q_SLOTS:
|
||||
void emitAnimatingChanged();
|
||||
void handleCandidatesChanged();
|
||||
void setInputPanel( QskVirtualKeyboard* );
|
||||
void inputMethodRegistered( const QLocale& locale, QskInputCompositionModel* model );
|
||||
|
||||
private:
|
||||
QskInputCompositionModel* currentInputCompositionModel() const;
|
||||
|
||||
QPointer< QObject > m_focusObject;
|
||||
QPointer< QQuickItem > m_inputItem;
|
||||
QPointer< QskVirtualKeyboard > m_inputPanel;
|
||||
std::unique_ptr< QskInputCompositionModel > m_inputCompositionModel;
|
||||
QskInputCompositionModel* m_defaultInputCompositionModel;
|
||||
QHash< QLocale, QskInputCompositionModel* > m_inputModels;
|
||||
};
|
||||
|
||||
#endif // QSK_INPUT_CONTEXT_H
|
||||
|
|
|
@ -14,7 +14,7 @@ class QskPinyinCompositionModel : public QskInputCompositionModel
|
|||
|
||||
public:
|
||||
QskPinyinCompositionModel();
|
||||
~QskPinyinCompositionModel();
|
||||
virtual ~QskPinyinCompositionModel() override;
|
||||
|
||||
int candidateCount() const override;
|
||||
Qt::Key candidate( int ) const override;
|
||||
|
|
|
@ -22,6 +22,7 @@ class QSK_EXPORT QskVirtualKeyboardButton : public QskPushButton
|
|||
|
||||
public:
|
||||
QSK_SUBCONTROLS( Panel, Text, TextCancelButton )
|
||||
|
||||
QskVirtualKeyboardButton( int keyIndex, QskVirtualKeyboard* inputPanel, QQuickItem* parent = nullptr );
|
||||
|
||||
virtual QskAspect::Subcontrol effectiveSubcontrol( QskAspect::Subcontrol subControl ) const override;
|
||||
|
@ -48,7 +49,6 @@ class QSK_EXPORT QskVirtualKeyboard : public QskBox
|
|||
using Inherited = QskBox;
|
||||
|
||||
public:
|
||||
|
||||
QSK_SUBCONTROLS( Panel )
|
||||
|
||||
struct KeyData
|
||||
|
|
Loading…
Reference in New Issue